Skip to content
Merged
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

### Conformance and release readiness

- Added a manual TypeScript SDK 2026 RC interop fixture pinned to the upstream
PR #2327 preview package, covering modern negotiation, `tools/list`, and
`tools/call` against the Dart 2026 RC conformance server.
- Marked `server/discover` as a 2026 cacheable result so stateless responses
include default `ttlMs` and `cacheScope` hints.
- Updated official conformance gates to
`@modelcontextprotocol/conformance@0.2.0-alpha.4`, with 2026 RC runs pinned
to `2026-07-28`, the full 2026 server scenario list covered in CI, the 2026
Expand Down
17 changes: 17 additions & 0 deletions doc/interoperability.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ For requirement-level MCP 2025-11-25 coverage, see the
| Dart client -> TypeScript SDK server | Streamable HTTP | `2025-11-25` | [`test/interop/dart_client_with_ts_server_test.dart`](../test/interop/dart_client_with_ts_server_test.dart), [`test/interop/ts/`](../test/interop/ts/) | Verified | Covers tool calls and stale preconfigured session-id recovery. |
| TypeScript SDK client -> Dart server | stdio | `2025-11-25` | [`test/interop/ts_client_with_dart_server_test.dart`](../test/interop/ts_client_with_dart_server_test.dart), [`test/interop/test_dart_server.dart`](../test/interop/test_dart_server.dart) | Verified | Runs the compiled TypeScript client fixture against a Dart server process and checks that an official TS client can list tools immediately after the lifecycle handshake. |
| TypeScript SDK client -> Dart server | Streamable HTTP | `2025-11-25` | [`test/interop/ts_client_with_dart_server_test.dart`](../test/interop/ts_client_with_dart_server_test.dart), [`test/interop/test_dart_server.dart`](../test/interop/test_dart_server.dart) | Verified | Includes official TS Streamable HTTP client lifecycle coverage, pre-`initialized` operation rejection, GET SSE streams, and `Last-Event-ID` replay behavior. |
| TypeScript SDK preview client -> Dart server | Streamable HTTP | `2026-07-28` draft/RC | [`test/interop/ts_2026_rc/`](../test/interop/ts_2026_rc/), [`tool/testing/run_ts_2026_rc_interop.dart`](../tool/testing/run_ts_2026_rc_interop.dart) | Experimental manual check | Uses a pinned `pkg.pr.new` preview from TypeScript SDK PR #2327 because published TS packages do not yet advertise `2026-07-28`. Covers modern negotiation, `tools/list`, and `tools/call` against the Dart 2026 RC conformance server. Not a CI gate yet. |
| Dart client -> Python MCP server | stdio | Server-dependent | [`doc/transports.md`](transports.md#connect-to-python-server) | Documented recipe | The transport can spawn Python servers over stdio, but this repo does not yet include an automated Python SDK fixture. |
| Flutter/Web client -> Dart server | Streamable HTTP | `2025-11-25` | [`example/flutter_http_client/`](../example/flutter_http_client/), [`doc/flutter-recipes.md`](flutter-recipes.md) | Documented recipe | Flutter Web cannot spawn stdio servers; use Streamable HTTP or another browser-safe transport. |
| MCP Apps host/client metadata | stdio or Streamable HTTP | `2025-11-25` plus `io.modelcontextprotocol/ui` extension | [`doc/mcp-apps.md`](mcp-apps.md), [`example/mcp_apps_helpers_server.dart`](../example/mcp_apps_helpers_server.dart), [`test/types/mcp_ui_test.dart`](../test/types/mcp_ui_test.dart), [`test/server/mcp_ui_test.dart`](../test/server/mcp_ui_test.dart) | Verified | Verified coverage is limited to SDK metadata helpers, serialization, and checked-in examples; host rendering behavior varies by host, so verify UI metadata against your target host. |
Expand All @@ -42,6 +43,20 @@ dart test --tags interop

If the compiled fixtures are missing, local test runs skip the interop groups; CI should fail when required fixtures are unavailable.

The TypeScript 2026 RC fixture is manual while the upstream SDK support remains
unreleased and split across preview PRs:

```bash
# From repository root
cd test/interop/ts_2026_rc
npm install
cd ../../..
dart run tool/testing/run_ts_2026_rc_interop.dart
```

This starts the Dart 2026 RC conformance server and runs the pinned TypeScript
SDK preview client against it.

The CLI spec conformance gate covers raw-wire negative cases that do not need a
cross-SDK fixture, including stable MCP 2025-11-25 checks and MCP 2026-07-28 RC
stateless/discovery/task-extension checks:
Expand All @@ -65,6 +80,8 @@ When adding a new interoperability claim:
## Known gaps worth tracking

- Automated Python SDK fixture coverage.
- CI promotion for the TypeScript 2026 RC interop fixture after the TypeScript
SDK publishes a 2026-compatible alpha package.
- Host-specific MCP Apps rendering compatibility notes.
- More OAuth-protected remote server scenarios beyond the checked-in examples.
- A broader compatibility table once additional SDKs expose stable 2025-11-25 fixtures.
10 changes: 8 additions & 2 deletions doc/mcp-2026-rc.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ Before creating follow-up dev tags from `dev/2026-07-28-rc`, run:
```sh
dart analyze
dart run test/conformance/run_2025_server_conformance.dart
npx -y @modelcontextprotocol/conformance@0.2.0-alpha.3 client \
npx -y @modelcontextprotocol/conformance@0.2.0-alpha.4 client \
--command "dart run test/conformance/mcp_2026_rc_client.dart" \
--suite all \
--spec-version 2025-11-25
Expand All @@ -142,10 +142,16 @@ dart run tool/validate_cli_publish.dart
```

The `run_2026_rc_server_conformance.dart` gate runs the full
`@modelcontextprotocol/conformance@0.2.0-alpha.3` server scenario list for
`@modelcontextprotocol/conformance@0.2.0-alpha.4` server scenario list for
`--spec-version 2026-07-28`, including the stable-style tool, resource, prompt,
completion, and JSON Schema scenarios that the alpha package tags for the RC.

For cross-SDK smoke coverage against the TypeScript SDK 2026 preview client,
run the manual fixture documented in
[`doc/interoperability.md`](interoperability.md#running-interop-checks-locally).
Keep that fixture out of CI until upstream publishes a 2026-compatible alpha
package instead of requiring a `pkg.pr.new` PR preview.

For dev packages, keep package documentation links pointed at
`dev/2026-07-28-rc` until the draft work is ready to merge back to `main`.
Restore those links to `main` as part of the final spec release prep.
Expand Down
1 change: 1 addition & 0 deletions lib/src/server/server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,7 @@ class Server extends Protocol {

bool _requiresCacheableResult(String method) {
return switch (method) {
Method.serverDiscover ||
Method.toolsList ||
Method.promptsList ||
Method.resourcesList ||
Expand Down
1 change: 1 addition & 0 deletions lib/src/shared/protocol.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ bool _isProgressToken(Object? token) =>
(token is double && token.isFinite && token == token.truncateToDouble());

const Set<String> _statelessCacheableResultMethods = {
Method.serverDiscover,
Method.toolsList,
Method.promptsList,
Method.resourcesList,
Expand Down
21 changes: 20 additions & 1 deletion lib/src/types/initialization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1345,7 +1345,7 @@ class InitializeResult implements BaseResultData {
}

/// Result data for a successful `server/discover` request.
class DiscoverResult implements BaseResultData {
class DiscoverResult implements CacheableResultData {
/// Result discriminator used by the 2026 result model.
final String resultType;

Expand All @@ -1361,6 +1361,14 @@ class DiscoverResult implements BaseResultData {
/// Instructions describing how to use the server and its features.
final String? instructions;

/// How long, in milliseconds, the client may consider this result fresh.
@override
final int? ttlMs;

/// Intended cache visibility: `public` or `private`.
@override
final String? cacheScope;

/// Optional metadata.
@override
final Map<String, dynamic>? meta;
Expand All @@ -1371,6 +1379,8 @@ class DiscoverResult implements BaseResultData {
required this.capabilities,
required this.serverInfo,
this.instructions,
this.ttlMs,
this.cacheScope,
this.meta,
});

Expand Down Expand Up @@ -1407,12 +1417,19 @@ class DiscoverResult implements BaseResultData {
json['instructions'],
'DiscoverResult.instructions',
),
ttlMs: readOptionalTtlMs(json['ttlMs'], 'DiscoverResult.ttlMs'),
cacheScope: readOptionalCacheScope(
json['cacheScope'],
'DiscoverResult.cacheScope',
),
meta: readOptionalJsonObject(json['_meta'], 'DiscoverResult._meta'),
);
}

@override
Map<String, dynamic> toJson() {
validateTtlMs(ttlMs, 'DiscoverResult.ttlMs');
validateCacheScope(cacheScope, 'DiscoverResult.cacheScope');
if (resultType != resultTypeComplete) {
throw ArgumentError.value(
resultType,
Expand All @@ -1427,6 +1444,8 @@ class DiscoverResult implements BaseResultData {
'capabilities': capabilities.toJson(omitLegacyTasks: true),
'serverInfo': serverInfo.toJson(),
if (instructions != null) 'instructions': instructions,
if (ttlMs != null) 'ttlMs': ttlMs,
if (cacheScope != null) 'cacheScope': cacheScope,
if (meta != null) '_meta': readJsonObject(meta, 'DiscoverResult._meta'),
};
}
Expand Down
25 changes: 15 additions & 10 deletions packages/mcp_dart_cli/lib/src/conformance_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,8 @@ class _DiscoveringConformanceTransport extends Transport
'name': 'conformance-server',
'version': '1.0.0',
},
'ttlMs': 0,
'cacheScope': _cacheScopePrivate,
},
),
);
Expand Down Expand Up @@ -1480,18 +1482,21 @@ Future<void> _httpModernProtocolErrorsRetryDiscovery() async {
jsonEncode(
JsonRpcResponse(
id: id,
result: const DiscoverResult(
supportedVersions: <String>[
result: const <String, dynamic>{
'resultType': _resultTypeComplete,
'supportedVersions': <String>[
_draftProtocolVersion2026_07_28,
],
capabilities: ServerCapabilities(
tools: ServerCapabilitiesTools(),
),
serverInfo: Implementation(
name: 'modern-http-server',
version: '1.0.0',
),
).toJson(),
'capabilities': <String, dynamic>{
'tools': <String, dynamic>{},
},
'serverInfo': <String, dynamic>{
'name': 'modern-http-server',
'version': '1.0.0',
},
'ttlMs': 0,
'cacheScope': _cacheScopePrivate,
},
).toJson(),
),
);
Expand Down
3 changes: 3 additions & 0 deletions test/interop/ts_2026_rc/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
npm-debug.log*

35 changes: 35 additions & 0 deletions test/interop/ts_2026_rc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# TypeScript SDK 2026 RC Interop

This fixture is an experimental smoke test for the unreleased MCP
`2026-07-28` draft/RC path against the official TypeScript SDK work in
progress.

It is intentionally separate from `test/interop/ts`, which tracks the published
stable TypeScript SDK and MCP `2025-11-25` behavior. The published split
TypeScript packages still do not advertise `2026-07-28`, so this fixture pins a
`pkg.pr.new` preview package from TypeScript SDK PR #2327. That PR includes the
modern Streamable HTTP `Mcp-Name` header support needed to interoperate with the
Dart 2026 RC server.

## Run

From the repository root:

```bash
cd test/interop/ts_2026_rc
npm install
cd ../../..
dart run tool/testing/run_ts_2026_rc_interop.dart
```

The runner starts `test/conformance/mcp_2026_rc_server.dart`, waits for its
bound local URL, and then runs `src/client.mjs` against it. The smoke asserts:

- TypeScript client negotiation selects the modern `2026-07-28` era.
- `tools/list` returns the Dart fixture tools.
- `tools/call` can invoke the Dart `echo` tool over modern Streamable HTTP.

Keep this as a manual, non-blocking check until the TypeScript SDK publishes a
stable 2026-compatible alpha package or the upstream PR stack lands on the
`v2-2026-07-28` branch.

148 changes: 148 additions & 0 deletions test/interop/ts_2026_rc/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading