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
30 changes: 26 additions & 4 deletions .github/workflows/interop_2026_07_28.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ on:
- 'tool/testing/run_ts_2026_07_28_interop.dart'
- 'tool/testing/run_python_2026_07_28_interop.dart'
- 'tool/testing/run_browser_2026_07_28_interop.dart'
- 'tool/testing/bounded_response_body.dart'
- 'tool/testing/mcp_2026_07_28_discovery_wire_probe.dart'
- '.github/workflows/interop_2026_07_28.yml'
- 'pubspec.yaml'
- 'pubspec.lock'
Expand All @@ -34,6 +36,8 @@ on:
- 'tool/testing/run_ts_2026_07_28_interop.dart'
- 'tool/testing/run_python_2026_07_28_interop.dart'
- 'tool/testing/run_browser_2026_07_28_interop.dart'
- 'tool/testing/bounded_response_body.dart'
- 'tool/testing/mcp_2026_07_28_discovery_wire_probe.dart'
- '.github/workflows/interop_2026_07_28.yml'
- 'pubspec.yaml'
- 'pubspec.lock'
Expand Down Expand Up @@ -62,8 +66,16 @@ jobs:
working-directory: test/interop/ts_2026_07_28
run: npm ci

- name: Run TypeScript 2026-07-28 interop fixture
run: dart run tool/testing/run_ts_2026_07_28_interop.dart
- name: Run Dart client against published TypeScript beta server
run: >-
dart run tool/testing/run_ts_2026_07_28_interop.dart
--direction=dart-to-ts

- name: Verify known published TypeScript beta client gap
run: >-
dart run tool/testing/run_ts_2026_07_28_interop.dart
--direction=ts-to-dart
--expect-published-ts-client-gap

python-2026-07-28-interop:
runs-on: ubuntu-latest
Expand All @@ -90,10 +102,20 @@ jobs:
python -m pip install
-r test/interop/python_2026_07_28/requirements.txt

- name: Run Python 2026-07-28 interop fixture
- name: Run Dart client against published Python beta server
env:
MCP_PYTHON: python
run: >-
dart run tool/testing/run_python_2026_07_28_interop.dart
--direction=dart-to-python

- name: Verify known published Python beta client gap
env:
MCP_PYTHON: python
run: dart run tool/testing/run_python_2026_07_28_interop.dart
run: >-
dart run tool/testing/run_python_2026_07_28_interop.dart
--direction=python-to-dart
--expect-published-python-client-gap

browser-2026-07-28-interop:
runs-on: ubuntu-latest
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
## Unreleased

### Changed

- Aligned MCP `2026-07-28` identity with spec PR #3002: client identity is
optional, and servers stamp validated identity in successful stateless result
`_meta` by default instead of the discovery body. A handler `null` omits the
optional key; received canonical `null` or malformed identities are rejected.

### Breaking and compatibility notes

- `DiscoverResult.serverInfo` is now nullable because MCP `2026-07-28` permits
anonymous servers. Check for `null` before reading identity fields. MCP
`2025-11-25` behavior is unchanged.

## 2.3.0-dev.2

This preview makes MCP `2026-07-28` the preferred protocol while preserving
Expand Down
55 changes: 36 additions & 19 deletions doc/interoperability.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ For MCP 2026-07-28 coverage, see the
| Dart client -> TypeScript SDK server | Streamable HTTP | MCP 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 | MCP 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 | MCP 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 beta client -> Dart server | Streamable HTTP | MCP 2026-07-28 | [`test/interop/ts_2026_07_28/`](../test/interop/ts_2026_07_28/), [`tool/testing/run_ts_2026_07_28_interop.dart`](../tool/testing/run_ts_2026_07_28_interop.dart), [`interop_2026_07_28.yml`](../.github/workflows/interop_2026_07_28.yml) | Verified | Uses published `@modelcontextprotocol/client@2.0.0-beta.4` and `@modelcontextprotocol/server@2.0.0-beta.4` packages. Covers modern negotiation, cache metadata, `tools/list`, `tools/call`, routing-header validation and retry, removed core RPC rejection, progress, `subscriptions/listen`, `AbortController` response-stream cancellation observed by the Dart server, and follow-up recovery. |
| Dart MCP 2026-07-28 client -> TypeScript SDK beta server | Streamable HTTP | MCP 2026-07-28 | [`test/interop/ts_2026_07_28/src/server.mjs`](../test/interop/ts_2026_07_28/src/server.mjs), [`tool/testing/run_ts_2026_07_28_interop.dart`](../tool/testing/run_ts_2026_07_28_interop.dart), [`interop_2026_07_28.yml`](../.github/workflows/interop_2026_07_28.yml) | Verified | Uses the published TypeScript SDK beta server through its `createMcpHandler` entry and covers `server/discover` negotiation, `tools/list`, `tools/call`, one-time `HeaderMismatch` metadata refresh and retry, an MCP 2026-07-28 `input_required` elicitation retry, request-stream cancellation observed through the server's Web Request `AbortSignal`, and post-cancellation recovery. |
| TypeScript SDK beta client -> Dart server | Streamable HTTP | MCP 2026-07-28 | [`test/interop/ts_2026_07_28/`](../test/interop/ts_2026_07_28/), [`tool/testing/run_ts_2026_07_28_interop.dart`](../tool/testing/run_ts_2026_07_28_interop.dart), [`interop_2026_07_28.yml`](../.github/workflows/interop_2026_07_28.yml) | Known published-beta gap | Published `@modelcontextprotocol/client@2.0.0-beta.4` predates spec PR #3002 and rejects discovery without obsolete body `serverInfo`. CI asserts the exact negotiation failure as temporary expected drift; a TypeScript SDK PR #2513 preview validates the final result metadata identity shape. |
| Dart MCP 2026-07-28 client -> TypeScript SDK beta server | Streamable HTTP | MCP 2026-07-28 | [`test/interop/ts_2026_07_28/src/server.mjs`](../test/interop/ts_2026_07_28/src/server.mjs), [`tool/testing/run_ts_2026_07_28_interop.dart`](../tool/testing/run_ts_2026_07_28_interop.dart), [`interop_2026_07_28.yml`](../.github/workflows/interop_2026_07_28.yml) | Verified | Uses the published TypeScript SDK beta server through its `createMcpHandler` entry and a temporary read-only fallback for legacy body `serverInfo`; covers `server/discover`, `tools/list`, `tools/call`, one-time `HeaderMismatch` metadata refresh and retry, MCP 2026-07-28 `input_required`, request-stream cancellation, and post-cancellation recovery. |
| 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; the stable recipe remains separate from the MCP 2026-07-28 beta fixture. |
| Python SDK beta client -> Dart server | Streamable HTTP | MCP 2026-07-28 | [`test/interop/python_2026_07_28/`](../test/interop/python_2026_07_28/), [`tool/testing/run_python_2026_07_28_interop.dart`](../tool/testing/run_python_2026_07_28_interop.dart), [`interop_2026_07_28.yml`](../.github/workflows/interop_2026_07_28.yml) | Verified | Uses official Python SDK `mcp==2.0.0b1` and covers automatic `server/discover` negotiation, `tools/list`, and `tools/call` against the Dart conformance server. |
| Dart MCP 2026-07-28 client -> Python SDK beta server | Streamable HTTP | MCP 2026-07-28 | [`test/interop/python_2026_07_28/server.py`](../test/interop/python_2026_07_28/server.py), [`tool/testing/run_python_2026_07_28_interop.dart`](../tool/testing/run_python_2026_07_28_interop.dart), [`interop_2026_07_28.yml`](../.github/workflows/interop_2026_07_28.yml) | Verified | Uses the official Python SDK beta MCP server and covers discovery, protocol selection, `tools/list`, and `tools/call`. |
| Python SDK beta client -> Dart server | Streamable HTTP | MCP 2026-07-28 | [`test/interop/python_2026_07_28/`](../test/interop/python_2026_07_28/), [`tool/testing/run_python_2026_07_28_interop.dart`](../tool/testing/run_python_2026_07_28_interop.dart), [`interop_2026_07_28.yml`](../.github/workflows/interop_2026_07_28.yml) | Known published-beta gap | Published `mcp==2.0.0b2` predates spec PR #3002 and falls back to MCP 2025-11-25 when canonical discovery omits obsolete body `serverInfo`. CI asserts that exact fallback as temporary expected drift. |
| Dart MCP 2026-07-28 client -> Python SDK beta server | Streamable HTTP | MCP 2026-07-28 | [`test/interop/python_2026_07_28/server.py`](../test/interop/python_2026_07_28/server.py), [`tool/testing/run_python_2026_07_28_interop.dart`](../tool/testing/run_python_2026_07_28_interop.dart), [`interop_2026_07_28.yml`](../.github/workflows/interop_2026_07_28.yml) | Verified | Uses the official Python SDK beta server through the temporary read-only fallback for legacy body `serverInfo`; covers discovery, protocol selection, `tools/list`, and `tools/call`. |
| Dart browser client -> Dart server | Streamable HTTP | MCP 2025-11-25 and MCP 2026-07-28 | [`test/browser/mcp_2026_07_28_streamable_http_test.dart`](../test/browser/mcp_2026_07_28_streamable_http_test.dart), [`tool/testing/run_browser_2026_07_28_interop.dart`](../tool/testing/run_browser_2026_07_28_interop.dart) | Verified | A real Chrome client completes 12 tool-list requests and 12 tool calls in each profile over cross-origin Streamable HTTP. It also proves MCP 2026-07-28 request-stream cancellation and recovery. The MCP 2025-11-25 case waits for response-stream reconnect timers and guards against browser connection-slot exhaustion. |
| Flutter Web example -> Dart server | Streamable HTTP | MCP 2026-07-28 | [`example/flutter_http_client/test/browser_e2e_test.dart`](../example/flutter_http_client/test/browser_e2e_test.dart), [`tool/testing/run_flutter_web_example_e2e.dart`](../tool/testing/run_flutter_web_example_e2e.dart), [`test_core.yml`](../.github/workflows/test_core.yml) | Verified | The example's real service layer runs in Chrome and completes connection, 12 tool-list requests, 12 tool calls, expected RPC-error recovery, reconnect, a post-reconnect request, and disconnect. Deterministic widget tests cover the UI separately. Flutter Web cannot spawn stdio servers. |
| MCP Apps host/client metadata | stdio or Streamable HTTP | MCP 2026-07-28 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 Down Expand Up @@ -60,35 +60,50 @@ packages:
cd test/interop/ts_2026_07_28
npm ci
cd ../../..
dart run tool/testing/run_ts_2026_07_28_interop.dart
dart run tool/testing/run_ts_2026_07_28_interop.dart \
--direction=dart-to-ts
```

This starts the Dart MCP 2026-07-28 conformance server, runs the pinned TypeScript
SDK beta client against it, then runs the reverse Dart MCP 2026-07-28 client smoke check
against the TypeScript SDK beta server.
That direction verifies the compatible Dart client -> published TypeScript beta
server path. The published beta.4 client still expects obsolete body
`serverInfo`; CI keeps that reverse direction visible without weakening Dart's
wire output by asserting the specific pre-#3002 negotiation failure:

`@modelcontextprotocol/client@2.0.0-beta.4` and
`@modelcontextprotocol/server@2.0.0-beta.4` expose the required modern path and
pass in both directions. The reverse path includes an `input_required`
elicitation retry, bidirectional request-stream cancellation observed by each
server, and successful post-cancellation tool calls in addition to discovery
and normal tool calls.
```bash
dart run tool/testing/run_ts_2026_07_28_interop.dart \
--direction=ts-to-dart \
--expect-published-ts-client-gap
```

An unexpected pass or a different failure is an error, so the workaround cannot
silently become stale. To validate a TypeScript SDK #2513 preview installation,
run the same `ts-to-dart` direction without the expected-gap flag.

The Dart-client path includes an `input_required` elicitation retry,
request-stream cancellation observed by the TypeScript server, and successful
post-cancellation tool calls in addition to discovery and normal tool calls.

The `Run MCP 2026-07-28 Interop` workflow covers relevant PRs, manual dispatch,
and a daily schedule on `main`.

The official Python SDK beta fixture runs independently in both directions:
The official Python SDK beta fixture runs each direction independently:

```bash
python3 -m venv .dart_tool/python-2026-interop
.dart_tool/python-2026-interop/bin/python -m pip install \
-r test/interop/python_2026_07_28/requirements.txt
MCP_PYTHON=.dart_tool/python-2026-interop/bin/python \
dart run tool/testing/run_python_2026_07_28_interop.dart
dart run tool/testing/run_python_2026_07_28_interop.dart \
--direction=dart-to-python
MCP_PYTHON=.dart_tool/python-2026-interop/bin/python \
dart run tool/testing/run_python_2026_07_28_interop.dart \
--direction=python-to-dart \
--expect-published-python-client-gap
```

It verifies automatic MCP 2026-07-28 discovery plus tool listing and execution for both
Python client -> Dart server and Dart client -> Python server.
The Dart client -> Python beta server path remains required. The reverse path
asserts the published beta's exact pre-#3002 fallback; an unexpected pass or a
different failure is an error so the exception cannot silently become stale.

The browser fixture runs the web implementation in Chrome against the same
Dart conformance server:
Expand Down Expand Up @@ -146,4 +161,6 @@ When adding a new interoperability claim:
- A broader compatibility table once additional SDKs expose stable MCP
2025-11-25 fixtures.
- Request-scoped cancellation against Python SDK beta and additional peer
implementations; both TypeScript SDK beta directions are verified.
implementations. The published TypeScript beta.4 server direction is
verified, its client direction remains the documented pre-#3002 gap, and the
TypeScript SDK #2513 preview verifies the final reverse path.
13 changes: 11 additions & 2 deletions doc/mcp-2026-07-28-release-runbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,21 @@ dart run test/conformance/run_2026_07_28_server_conformance.dart \
dart run test/conformance/run_2026_07_28_client_conformance.dart \
--timeout-seconds 90
cd test/interop/ts_2026_07_28 && npm ci && cd ../../..
dart run tool/testing/run_ts_2026_07_28_interop.dart
dart run tool/testing/run_ts_2026_07_28_interop.dart \
--direction=dart-to-ts
dart run tool/testing/run_ts_2026_07_28_interop.dart \
--direction=ts-to-dart \
--expect-published-ts-client-gap
python3 -m venv .dart_tool/python-2026-interop
.dart_tool/python-2026-interop/bin/python -m pip install \
-r test/interop/python_2026_07_28/requirements.txt
MCP_PYTHON=.dart_tool/python-2026-interop/bin/python \
dart run tool/testing/run_python_2026_07_28_interop.dart
dart run tool/testing/run_python_2026_07_28_interop.dart \
--direction=dart-to-python
MCP_PYTHON=.dart_tool/python-2026-interop/bin/python \
dart run tool/testing/run_python_2026_07_28_interop.dart \
--direction=python-to-dart \
--expect-published-python-client-gap
dart run tool/testing/run_browser_2026_07_28_interop.dart
dart run tool/testing/run_flutter_web_example_e2e.dart
dart pub publish --dry-run
Expand Down
43 changes: 39 additions & 4 deletions doc/mcp-2026-07-28.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,40 @@ Use `McpServerOptions(protocol: McpProtocol.legacy)` to advertise only legacy
MCP versions, or `McpServerOptions(protocol: McpProtocol.require2026)` to
reject legacy initialization.

## Stateless identity metadata

MCP `2026-07-28` carries peer identity in stateless metadata:

- Clients normally include `_meta["io.modelcontextprotocol/clientInfo"]` on
every request, but the field is optional. Servers accept it when omitted and
reject a value that is present but is not a valid `Implementation` object.
- `McpServer` stamps its configured identity in
`_meta["io.modelcontextprotocol/serverInfo"]` on successful stateless results
by default. A valid handler-authored `Implementation` value at that key wins;
`null` configures an anonymous result by omitting the key, while malformed
non-null values fail before serialization. `server/discover` no longer emits
a body `serverInfo` field.
- `DiscoverResult.serverInfo` is nullable and reads result metadata for
convenience. Missing canonical identity is anonymous; a present malformed or
`null` canonical identity is rejected. The temporary pre-#3002 body fallback
ignores malformed legacy identity. Applications must not use self-reported
identity for security or protocol behavior.

Code that previously dereferenced discovery identity must now handle an
anonymous server:

```dart
final discovery = await client.discoverServer();
final serverInfo = discovery.serverInfo;
if (serverInfo != null) {
print('${serverInfo.name} ${serverInfo.version}');
}
```

The parser temporarily accepts the pre-spec top-level discovery identity sent by
published TypeScript and Python SDK beta releases. Dart never emits that legacy
shape; the fallback can be removed after corrected peer releases are pinned.

## Profile summary

| Profile | Default? | Client behavior | Server behavior |
Expand Down Expand Up @@ -162,10 +196,11 @@ matching dev.2 SDK dependency.
while `dev/2026-07-28-rc` remains a read-only archive for links embedded in the
earlier dev.0 and dev.1 packages.

CI runs official MCP 2025-11-25 and MCP 2026-07-28 conformance, pinned
spec-example audits, bidirectional TypeScript and Python interop, real-browser
transport tests, a Flutter Web service integration in Chrome, and widget
tests. See
CI runs official MCP 2025-11-25 and MCP 2026-07-28 conformance plus pinned
spec-example audits, published TypeScript and Python server interop, exact
published-beta client expected-gap checks for both SDKs, real-browser transport
tests, a Flutter Web service integration in Chrome, and widget tests.
TypeScript SDK #2513 preview interop is validated separately before release. See
the [interoperability guide](interoperability.md#running-interop-checks-locally)
for local commands and the
[day-0 release runbook](mcp-2026-07-28-release-runbook.md) for the final tag,
Expand Down
Loading
Loading