Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions lib/src/types/initialization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,16 @@ class DiscoverResult implements BaseResultData {
});

factory DiscoverResult.fromJson(Map<String, dynamic> json) {
final resultType = readOptionalString(
json['resultType'],
'DiscoverResult.resultType',
);
if (resultType != resultTypeComplete) {
throw const FormatException(
'DiscoverResult.resultType must be complete',
);
}

final supportedVersions = json['supportedVersions'];
if (supportedVersions is! List) {
throw const FormatException(
Expand All @@ -1091,7 +1101,6 @@ class DiscoverResult implements BaseResultData {
}

return DiscoverResult(
resultType: json['resultType'] as String? ?? 'complete',
supportedVersions: supportedVersions.cast<String>(),
capabilities: ServerCapabilities.fromJson(
json['capabilities'] as Map<String, dynamic>,
Expand All @@ -1105,14 +1114,24 @@ class DiscoverResult implements BaseResultData {
}

@override
Map<String, dynamic> toJson() => {
'resultType': resultType,
'supportedVersions': supportedVersions,
'capabilities': capabilities.toJson(),
'serverInfo': serverInfo.toJson(),
if (instructions != null) 'instructions': instructions,
if (meta != null) '_meta': readJsonObject(meta, 'DiscoverResult._meta'),
};
Map<String, dynamic> toJson() {
if (resultType != resultTypeComplete) {
throw ArgumentError.value(
resultType,
'DiscoverResult.resultType',
'must be complete',
);
}

return {
'resultType': resultType,
'supportedVersions': supportedVersions,
'capabilities': capabilities.toJson(),
'serverInfo': serverInfo.toJson(),
if (instructions != null) 'instructions': instructions,
if (meta != null) '_meta': readJsonObject(meta, 'DiscoverResult._meta'),
};
}
}

/// Notification sent from the client to the server after initialization is finished.
Expand Down
37 changes: 37 additions & 0 deletions test/mcp_2026_07_28_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,43 @@ void main() {
);
});

test('requires complete resultType on server/discover results', () {
final validResult = const DiscoverResult(
supportedVersions: [draftProtocolVersion2026_07_28],
capabilities: ServerCapabilities(),
serverInfo: Implementation(name: 'server', version: '1.0.0'),
).toJson();

for (final json in [
{
...validResult,
}..remove('resultType'),
{
...validResult,
'resultType': resultTypeInputRequired,
},
{
...validResult,
'resultType': 1,
},
]) {
expect(
() => DiscoverResult.fromJson(json),
throwsFormatException,
);
}

expect(
() => const DiscoverResult(
resultType: resultTypeInputRequired,
supportedVersions: [draftProtocolVersion2026_07_28],
capabilities: ServerCapabilities(),
serverInfo: Implementation(name: 'server', version: '1.0.0'),
).toJson(),
throwsArgumentError,
);
});

test('requires server/discover request metadata in params', () {
expect(
() => JsonRpcServerDiscoverRequest(id: 'discover-1').toJson(),
Expand Down