diff --git a/.github/workflows/test_core.yml b/.github/workflows/test_core.yml index 3b1ec340..73896c30 100644 --- a/.github/workflows/test_core.yml +++ b/.github/workflows/test_core.yml @@ -52,7 +52,7 @@ jobs: - name: Run official MCP 2025 client conformance run: > - npx -y @modelcontextprotocol/conformance@0.2.0-alpha.7 client + npx -y @modelcontextprotocol/conformance@0.2.0-alpha.8 client --command "dart run test/conformance/mcp_2026_07_28_rc_client.dart" --suite all --spec-version 2025-11-25 diff --git a/CHANGELOG.md b/CHANGELOG.md index c60139b4..c41f63b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,22 +8,22 @@ ### Conformance and interoperability -- Documented that published TypeScript SDK `2.0.0-alpha.3` packages are not yet - valid replacements for the `pkg.pr.new` 2026-07-28 RC interop fixture because - the alpha.3 client is missing the preview negotiation API used by the fixture. +- Re-pinned the TypeScript SDK 2026-07-28 RC interop fixture from `pkg.pr.new` + previews to published `@modelcontextprotocol/client@2.0.0-beta.1` and + `@modelcontextprotocol/server@2.0.0-beta.1` packages after verifying both + Dart -> TypeScript and TypeScript -> Dart 2026 draft/RC paths. - Updated official conformance gates to - `@modelcontextprotocol/conformance@0.2.0-alpha.7`. The 2026-07-28 RC server suite - now has no expected failures; the 2026 client suite keeps only the upstream + `@modelcontextprotocol/conformance@0.2.0-alpha.8`, adding the new stateless + diagnostic probes for missing client capabilities, response-stream shape, and + request-scoped logging. The 2026-07-28 RC server suite now has no expected + failures; the 2026 client suite keeps only the upstream `json-schema-ref-no-deref` fixture gap expected. -- Added a dedicated CI workflow for the TypeScript SDK 2026-07-28 RC preview +- Added a dedicated CI workflow for the TypeScript SDK 2026-07-28 RC beta interop fixture on relevant PRs, `dev/2026-07-28-rc` pushes, daily schedule, and manual dispatch. - Added an MCP 2026-07-28 draft/RC spec coverage matrix that maps the opt-in - profile to official conformance, local tests, and TypeScript preview interop. -- Re-pinned the TypeScript SDK 2026-07-28 RC interop fixture to - `pkg.pr.new` previews from the merged `v2-2026-07-28` branch head for both - client and server packages. -- Switched the reverse Dart preview client -> TypeScript preview server fixture + profile to official conformance, local tests, and TypeScript SDK beta interop. +- Switched the reverse Dart 2026 client -> TypeScript SDK beta server fixture to the TypeScript SDK's 2026 HTTP handler entry, making `server/discover`, `tools/list`, and `tools/call` strict interop checks instead of diagnostic skips. diff --git a/README.md b/README.md index db660c1c..d7d3151a 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ for opt-in behavior, fallback rules, and draft-only APIs. - ๐Ÿงช **[SDK Interoperability Matrix](https://github.com/leehack/mcp_dart/blob/dev/2026-07-28-rc/doc/interoperability.md)** - Verified Dart/TypeScript and documented cross-SDK scenarios - โœ… **[MCP 2025-11-25 Spec Coverage Matrix](https://github.com/leehack/mcp_dart/blob/dev/2026-07-28-rc/doc/spec-coverage-2025-11-25.md)** - Auditable coverage map with CLI conformance cases and known gaps -- ๐Ÿงช **[MCP 2026-07-28 Draft/RC Spec Coverage Matrix](https://github.com/leehack/mcp_dart/blob/dev/2026-07-28-rc/doc/spec-coverage-2026-07-28-rc.md)** - Opt-in draft/RC coverage map across official conformance and TypeScript preview interop +- ๐Ÿงช **[MCP 2026-07-28 Draft/RC Spec Coverage Matrix](https://github.com/leehack/mcp_dart/blob/dev/2026-07-28-rc/doc/spec-coverage-2026-07-28-rc.md)** - Opt-in draft/RC coverage map across official conformance and TypeScript SDK beta interop - ๐Ÿงญ **[MCP 2026-07-28 Draft/RC Transition Guide](https://github.com/leehack/mcp_dart/blob/dev/2026-07-28-rc/doc/mcp-2026-07-28-rc.md)** - Opt-in profile, fallback behavior, and draft-only APIs - ๐Ÿ”’ **[Transport Security Recipes](https://github.com/leehack/mcp_dart/blob/dev/2026-07-28-rc/doc/transports.md#dns-rebinding-protection)** - Host/Origin allowlists, OAuth layering, and compatibility-toggle trade-offs - ๐Ÿ“ฑ **[Flutter Recipes](https://github.com/leehack/mcp_dart/blob/dev/2026-07-28-rc/doc/flutter-recipes.md)** - Flutter Web, mobile, and desktop host/client guidance diff --git a/doc/interoperability.md b/doc/interoperability.md index 0ebefd48..35ef7317 100644 --- a/doc/interoperability.md +++ b/doc/interoperability.md @@ -23,8 +23,8 @@ For MCP 2026-07-28 draft/RC 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_07_28_rc/`](../test/interop/ts_2026_07_28_rc/), [`tool/testing/run_ts_2026_07_28_rc_interop.dart`](../tool/testing/run_ts_2026_07_28_rc_interop.dart), [`interop_2026_07_28.yml`](../.github/workflows/interop_2026_07_28.yml) | Automated preview check | Uses pinned `pkg.pr.new` previews from the TypeScript SDK `v2-2026-07-28` branch head. Covers modern negotiation, cache metadata, `tools/list`, `tools/call`, `x-mcp-header` mirroring, raw header and unsupported-version rejection, removed core RPC rejection, progress notifications, `subscriptions/listen`, and HTTP SSE cancellation against the Dart 2026-07-28 RC conformance server. | -| Dart preview client -> TypeScript SDK preview server | Streamable HTTP | `2026-07-28` draft/RC | [`test/interop/ts_2026_07_28_rc/src/server.mjs`](../test/interop/ts_2026_07_28_rc/src/server.mjs), [`tool/testing/run_ts_2026_07_28_rc_interop.dart`](../tool/testing/run_ts_2026_07_28_rc_interop.dart), [`interop_2026_07_28.yml`](../.github/workflows/interop_2026_07_28.yml) | Automated preview check | Uses the pinned TypeScript SDK server preview through its `createMcpHandler` entry and covers `server/discover` negotiation, `tools/list`, and `tools/call`. | +| TypeScript SDK beta client -> Dart server | Streamable HTTP | `2026-07-28` draft/RC | [`test/interop/ts_2026_07_28_rc/`](../test/interop/ts_2026_07_28_rc/), [`tool/testing/run_ts_2026_07_28_rc_interop.dart`](../tool/testing/run_ts_2026_07_28_rc_interop.dart), [`interop_2026_07_28.yml`](../.github/workflows/interop_2026_07_28.yml) | Automated 2026 check | Uses published `@modelcontextprotocol/client@2.0.0-beta.1` and `@modelcontextprotocol/server@2.0.0-beta.1` packages. Covers modern negotiation, cache metadata, `tools/list`, `tools/call`, `x-mcp-header` mirroring, raw header and unsupported-version rejection, removed core RPC rejection, progress notifications, `subscriptions/listen`, and HTTP SSE cancellation against the Dart 2026-07-28 RC conformance server. | +| Dart 2026 client -> TypeScript SDK beta server | Streamable HTTP | `2026-07-28` draft/RC | [`test/interop/ts_2026_07_28_rc/src/server.mjs`](../test/interop/ts_2026_07_28_rc/src/server.mjs), [`tool/testing/run_ts_2026_07_28_rc_interop.dart`](../tool/testing/run_ts_2026_07_28_rc_interop.dart), [`interop_2026_07_28.yml`](../.github/workflows/interop_2026_07_28.yml) | Automated 2026 check | Uses the published TypeScript SDK beta server through its `createMcpHandler` entry and covers `server/discover` negotiation, `tools/list`, and `tools/call`. | | 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 | `2026-07-28` draft/RC preview with stable fallback | [`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. The example opts into preview negotiation while retaining stable fallback. | | MCP Apps host/client metadata | stdio or Streamable HTTP | `2026-07-28` draft/RC preview 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. | @@ -46,8 +46,8 @@ 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-07-28 RC fixture uses unreleased `pkg.pr.new` previews from -the TypeScript SDK `v2-2026-07-28` branch: +The TypeScript 2026-07-28 RC fixture uses the published TypeScript SDK beta +packages: ```bash # From repository root @@ -57,17 +57,15 @@ cd ../../.. dart run tool/testing/run_ts_2026_07_28_rc_interop.dart ``` -This starts the Dart 2026-07-28 RC conformance server, runs the pinned TypeScript SDK -preview client against it, then runs the reverse Dart preview client smoke check -against the TypeScript preview server. +This starts the Dart 2026-07-28 RC conformance server, runs the pinned TypeScript +SDK beta client against it, then runs the reverse Dart 2026 client smoke check +against the TypeScript SDK beta server. -Published `@modelcontextprotocol/client@2.0.0-alpha.3` and -`@modelcontextprotocol/server@2.0.0-alpha.3` packages are not yet suitable -replacements for this fixture: the published alpha.3 client does not expose the -preview `versionNegotiation` / `getProtocolEra` APIs used here, and a direct -`supportedProtocolVersions: ["2026-07-28"]` repin fails the handshake. Keep the -`pkg.pr.new` pin until a published TypeScript SDK package exposes the 2026 draft -path and this interop runner passes against it. +The fixture previously depended on `pkg.pr.new` artifacts because published +`2.0.0-alpha.3` packages did not expose the preview negotiation API used here. +`@modelcontextprotocol/client@2.0.0-beta.1` and +`@modelcontextprotocol/server@2.0.0-beta.1` expose the required modern path and +the interop runner passes against them. CI also runs this fixture in the dedicated `Run MCP 2026-07-28 TypeScript Interop` workflow for relevant PRs, @@ -96,12 +94,7 @@ When adding a new interoperability claim: ## Known gaps worth tracking - Automated Python SDK fixture coverage. -- Re-pin the TypeScript 2026-07-28 RC interop fixture to a published upstream - alpha package once that package exposes the 2026 draft path. The published - `@modelcontextprotocol/client/server@2.0.0-alpha.3` packages are not enough - because the client is missing the preview negotiation API used by this - fixture. -- Broader reverse-path TypeScript preview server coverage beyond discovery, +- Broader reverse-path TypeScript SDK beta server coverage beyond discovery, `tools/list`, and `tools/call`. - Host-specific MCP Apps rendering compatibility notes. - More OAuth-protected remote server scenarios beyond the checked-in examples. diff --git a/doc/mcp-2026-07-28-rc.md b/doc/mcp-2026-07-28-rc.md index c6ad40ed..5431d2a7 100644 --- a/doc/mcp-2026-07-28-rc.md +++ b/doc/mcp-2026-07-28-rc.md @@ -131,7 +131,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.7 client \ +npx -y @modelcontextprotocol/conformance@0.2.0-alpha.8 client \ --command "dart run test/conformance/mcp_2026_07_28_rc_client.dart" \ --suite all \ --spec-version 2025-11-25 @@ -147,21 +147,20 @@ dart run tool/validate_cli_publish.dart ``` The `run_2026_07_28_rc_server_conformance.dart` gate runs the full -`@modelcontextprotocol/conformance@0.2.0-alpha.7` server scenario list for +`@modelcontextprotocol/conformance@0.2.0-alpha.8` 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 packages, +For cross-SDK smoke coverage against the TypeScript SDK 2026 beta packages, run the fixture documented in [`doc/interoperability.md`](interoperability.md#running-interop-checks-locally). CI also runs it in the dedicated `Run MCP 2026-07-28 TypeScript Interop` workflow on relevant PRs, `dev/2026-07-28-rc` pushes, a daily schedule, and manual dispatch. Keep it pinned to the draft behavior rather than TypeScript -preview behavior alone; re-pin from `pkg.pr.new` to a published TypeScript SDK -alpha only when the published package advertises `2026-07-28` support. The -published `@modelcontextprotocol/client/server@2.0.0-alpha.3` packages are -missing the preview negotiation API used by this fixture, so they are not a -replacement for the current preview pin. +preview behavior alone. The fixture is currently pinned to published +`@modelcontextprotocol/client@2.0.0-beta.1` and +`@modelcontextprotocol/server@2.0.0-beta.1`, which expose the 2026 negotiation +path and pass the checked-in interop runner. 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`. diff --git a/doc/spec-coverage-2026-07-28-rc.md b/doc/spec-coverage-2026-07-28-rc.md index 95c3d29f..0da5f300 100644 --- a/doc/spec-coverage-2026-07-28-rc.md +++ b/doc/spec-coverage-2026-07-28-rc.md @@ -14,7 +14,7 @@ Run the official conformance gates from the repository root: ```bash dart run test/conformance/run_2025_server_conformance.dart -npx -y @modelcontextprotocol/conformance@0.2.0-alpha.7 client \ +npx -y @modelcontextprotocol/conformance@0.2.0-alpha.8 client \ --command "dart run test/conformance/mcp_2026_07_28_rc_client.dart" \ --suite all \ --spec-version 2025-11-25 @@ -22,7 +22,7 @@ dart run test/conformance/run_2026_07_28_rc_server_conformance.dart dart run test/conformance/run_2026_07_28_rc_client_conformance.dart ``` -Run the TypeScript preview interop gate from the repository root: +Run the TypeScript SDK beta interop gate from the repository root: ```bash cd test/interop/ts_2026_07_28_rc @@ -32,7 +32,7 @@ dart run tool/testing/run_ts_2026_07_28_rc_interop.dart ``` CI runs the official conformance gates in the core workflow. The -`Run MCP 2026-07-28 TypeScript Interop` workflow runs the TypeScript preview +`Run MCP 2026-07-28 TypeScript Interop` workflow runs the TypeScript SDK beta interop fixture on relevant PRs, `dev/2026-07-28-rc` pushes, a daily schedule, and manual dispatch. @@ -40,29 +40,23 @@ and manual dispatch. | Spec area | Draft source | Requirement tracked here | Local coverage | Cross-SDK coverage | Official conformance | Status | | --- | --- | --- | --- | --- | --- | --- | -| Opt-in profile and stable default | [Versioning and compatibility](https://modelcontextprotocol.io/specification/draft/basic/versioning) | Stable MCP `2025-11-25` remains default, while 2026 behavior is selected explicitly with preview or require profiles. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`doc/mcp-2026-07-28-rc.md`](mcp-2026-07-28-rc.md) | TypeScript preview interop uses explicit 2026 clients and servers only. | 2025 and 2026 conformance both run in CI. | Verified | -| Version negotiation and discovery | [Discovery](https://modelcontextprotocol.io/specification/draft/server/discover), [Versioning](https://modelcontextprotocol.io/specification/draft/basic/versioning) | Servers implement `server/discover`, advertise supported versions and capabilities, reject unsupported versions with draft error data, and clients retry or fall back according to transport-era rules. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/conformance/mcp_2026_07_28_rc_server.dart`](../test/conformance/mcp_2026_07_28_rc_server.dart), [`test/conformance/mcp_2026_07_28_rc_client.dart`](../test/conformance/mcp_2026_07_28_rc_client.dart) | [`tool/testing/run_ts_2026_07_28_rc_interop.dart`](../tool/testing/run_ts_2026_07_28_rc_interop.dart) validates TypeScript preview client -> Dart server and Dart preview client -> TypeScript preview server discovery. | `protocol-version`, `server/discover`, and client negotiation scenarios in alpha.7. | Verified | -| Stateless request metadata | [Overview](https://modelcontextprotocol.io/specification/draft/basic), [Versioning](https://modelcontextprotocol.io/specification/draft/basic/versioning) | Every 2026 request carries protocol version, client identity, and client capabilities in `_meta`; servers do not infer protocol state from a prior request. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/server/streamable_https_test.dart`](../test/server/streamable_https_test.dart) | TypeScript preview client fixture exercises normal request paths with 2026 metadata. | `stateless` and `stateless-http` scenarios in alpha.7. | Verified | -| Streamable HTTP routing headers | [Key changes](https://modelcontextprotocol.io/specification/draft/changelog), [Transports](https://modelcontextprotocol.io/specification/draft/basic/transports) | 2026 HTTP POST requests include required protocol, method, name, and parameter-routing headers; mismatches reject with draft header errors. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/server/streamable_https_test.dart`](../test/server/streamable_https_test.dart) | TypeScript preview client fixture validates `x-mcp-header` mirroring and raw header rejection against the Dart server. | `stateless-http.requires-routing-headers`, `stateless-http.validates-parameter-headers`, and related alpha.7 cases. | Verified | -| Removed session and resumability behavior | [Key changes](https://modelcontextprotocol.io/specification/draft/changelog) | 2026 Streamable HTTP omits protocol-level sessions, rejects removed GET/DELETE behaviors, rejects JSON-RPC batches, and treats closed SSE response streams as request cancellation without legacy redelivery. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/server/streamable_mcp_server_test.dart`](../test/server/streamable_mcp_server_test.dart) | TypeScript preview fixture closes the Dart SSE response stream and verifies no legacy `notifications/cancelled` side effect is required. | `stateless-http.rejects-non-post-methods`, `stateless-http.rejects-batch-payloads`, and related alpha.7 cases. | Verified | -| Cacheable results and deterministic lists | [Key changes](https://modelcontextprotocol.io/specification/draft/changelog), [Discovery](https://modelcontextprotocol.io/specification/draft/server/discover) | `server/discover`, list, and read responses include `resultType`, `ttlMs`, and `cacheScope`; stateless `tools/list` is deterministic and omits stable-only tool execution metadata. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/conformance/mcp_2026_07_28_rc_server.dart`](../test/conformance/mcp_2026_07_28_rc_server.dart) | TypeScript preview client fixture checks discovery cache metadata and `tools/list` cache metadata. | Cacheable-result and tools-list scenarios in alpha.7. | Verified | -| Tools and JSON Schema 2020-12 | [Tools](https://modelcontextprotocol.io/specification/draft/server/tools), [Overview JSON Schema usage](https://modelcontextprotocol.io/specification/draft/basic) | Tool schemas preserve JSON Schema 2020-12 constructs, including nested boolean schemas; stable root-object compatibility remains intact for 2025 behavior. | [`test/tool_schema_test.dart`](../test/tool_schema_test.dart), [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/conformance/mcp_2026_07_28_rc_server.dart`](../test/conformance/mcp_2026_07_28_rc_server.dart) | TypeScript preview fixture validates `tools/list` and `tools/call`; deeper schema semantics are covered by local and conformance tests. | 2026 server suite is green; 2026 client suite keeps the upstream `json-schema-ref-no-deref` fixture gap expected. | Verified with one upstream client fixture gap | -| MRTR and elicitation | [Message patterns](https://modelcontextprotocol.io/specification/draft/basic) | 2026 `input_required` results are emitted only for supported requests and require advertised client capabilities. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/elicitation_test.dart`](../test/elicitation_test.dart) | TypeScript preview client fixture completes a 2026 `input_required` retry flow against the Dart server. | `mrtr` scenarios in alpha.7. | Verified | -| Subscriptions | [Subscriptions](https://modelcontextprotocol.io/specification/draft/basic/utilities/subscriptions), [Schema reference](https://modelcontextprotocol.io/specification/draft/schema#subscriptionslistenresult) | `subscriptions/listen` acknowledges before list-change notifications, filters unsupported notification types, correlates notifications through `io.modelcontextprotocol/subscriptionId`, and returns `SubscriptionsListenResult` with the same required subscription id metadata on graceful close. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/conformance/mcp_2026_07_28_rc_server.dart`](../test/conformance/mcp_2026_07_28_rc_server.dart) | TypeScript preview fixture validates `subscriptions/listen` acknowledgment and list-change notification correlation against the Dart server. | Subscription scenarios in alpha.7. | Verified | -| Request-scoped logging and removed core RPCs | [Logging](https://modelcontextprotocol.io/specification/draft/server/utilities/logging), [Key changes](https://modelcontextprotocol.io/specification/draft/changelog) | 2026 stateless requests use request-scoped logging metadata, and removed stable-era core RPCs/notifications are rejected in the 2026 profile. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/server/server_advanced_test.dart`](../test/server/server_advanced_test.dart) | TypeScript preview fixture validates raw removed-RPC rejection against the Dart server. | Removed-RPC and logging scenarios in alpha.7. | Verified | +| Opt-in profile and stable default | [Versioning and compatibility](https://modelcontextprotocol.io/specification/draft/basic/versioning) | Stable MCP `2025-11-25` remains default, while 2026 behavior is selected explicitly with preview or require profiles. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`doc/mcp-2026-07-28-rc.md`](mcp-2026-07-28-rc.md) | TypeScript SDK beta interop uses explicit 2026 clients and servers only. | 2025 and 2026 conformance both run in CI. | Verified | +| Version negotiation and discovery | [Discovery](https://modelcontextprotocol.io/specification/draft/server/discover), [Versioning](https://modelcontextprotocol.io/specification/draft/basic/versioning) | Servers implement `server/discover`, advertise supported versions and capabilities, reject unsupported versions with draft error data, and clients retry or fall back according to transport-era rules. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/conformance/mcp_2026_07_28_rc_server.dart`](../test/conformance/mcp_2026_07_28_rc_server.dart), [`test/conformance/mcp_2026_07_28_rc_client.dart`](../test/conformance/mcp_2026_07_28_rc_client.dart) | [`tool/testing/run_ts_2026_07_28_rc_interop.dart`](../tool/testing/run_ts_2026_07_28_rc_interop.dart) validates TypeScript SDK beta client -> Dart server and Dart 2026 client -> TypeScript SDK beta server discovery. | `protocol-version`, `server/discover`, and client negotiation scenarios in alpha.8. | Verified | +| Stateless request metadata | [Overview](https://modelcontextprotocol.io/specification/draft/basic), [Versioning](https://modelcontextprotocol.io/specification/draft/basic/versioning) | Every 2026 request carries protocol version, client identity, and client capabilities in `_meta`; servers do not infer protocol state from a prior request. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/server/streamable_https_test.dart`](../test/server/streamable_https_test.dart) | TypeScript SDK beta client fixture exercises normal request paths with 2026 metadata. | `stateless` and `stateless-http` scenarios in alpha.8. | Verified | +| Streamable HTTP routing headers | [Key changes](https://modelcontextprotocol.io/specification/draft/changelog), [Transports](https://modelcontextprotocol.io/specification/draft/basic/transports) | 2026 HTTP POST requests include required protocol, method, name, and parameter-routing headers; mismatches reject with draft header errors. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/server/streamable_https_test.dart`](../test/server/streamable_https_test.dart) | TypeScript SDK beta client fixture validates `x-mcp-header` mirroring and raw header rejection against the Dart server. | `stateless-http.requires-routing-headers`, `stateless-http.validates-parameter-headers`, and related alpha.8 cases. | Verified | +| Removed session and resumability behavior | [Key changes](https://modelcontextprotocol.io/specification/draft/changelog) | 2026 Streamable HTTP omits protocol-level sessions, rejects removed GET/DELETE behaviors, rejects JSON-RPC batches, and treats closed SSE response streams as request cancellation without legacy redelivery. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/server/streamable_mcp_server_test.dart`](../test/server/streamable_mcp_server_test.dart) | TypeScript SDK beta fixture closes the Dart SSE response stream and verifies no legacy `notifications/cancelled` side effect is required. | `stateless-http.rejects-non-post-methods`, `stateless-http.rejects-batch-payloads`, and related alpha.8 cases. | Verified | +| Cacheable results and deterministic lists | [Key changes](https://modelcontextprotocol.io/specification/draft/changelog), [Discovery](https://modelcontextprotocol.io/specification/draft/server/discover) | `server/discover`, list, and read responses include `resultType`, `ttlMs`, and `cacheScope`; stateless `tools/list` is deterministic and omits stable-only tool execution metadata. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/conformance/mcp_2026_07_28_rc_server.dart`](../test/conformance/mcp_2026_07_28_rc_server.dart) | TypeScript SDK beta client fixture checks discovery cache metadata and `tools/list` cache metadata. | Cacheable-result and tools-list scenarios in alpha.8. | Verified | +| Tools and JSON Schema 2020-12 | [Tools](https://modelcontextprotocol.io/specification/draft/server/tools), [Overview JSON Schema usage](https://modelcontextprotocol.io/specification/draft/basic) | Tool schemas preserve JSON Schema 2020-12 constructs, including nested boolean schemas; stable root-object compatibility remains intact for 2025 behavior. | [`test/tool_schema_test.dart`](../test/tool_schema_test.dart), [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/conformance/mcp_2026_07_28_rc_server.dart`](../test/conformance/mcp_2026_07_28_rc_server.dart) | TypeScript SDK beta fixture validates `tools/list` and `tools/call`; deeper schema semantics are covered by local and conformance tests. | 2026 server suite is green; 2026 client suite keeps the upstream `json-schema-ref-no-deref` fixture gap expected. | Verified with one upstream client fixture gap | +| MRTR and elicitation | [Message patterns](https://modelcontextprotocol.io/specification/draft/basic) | 2026 `input_required` results are emitted only for supported requests and require advertised client capabilities. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/elicitation_test.dart`](../test/elicitation_test.dart) | TypeScript SDK beta client fixture completes a 2026 `input_required` retry flow against the Dart server. | `mrtr` scenarios in alpha.8. | Verified | +| Subscriptions | [Subscriptions](https://modelcontextprotocol.io/specification/draft/basic/utilities/subscriptions), [Schema reference](https://modelcontextprotocol.io/specification/draft/schema#subscriptionslistenresult) | `subscriptions/listen` acknowledges before list-change notifications, filters unsupported notification types, correlates notifications through `io.modelcontextprotocol/subscriptionId`, and returns `SubscriptionsListenResult` with the same required subscription id metadata on graceful close. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/conformance/mcp_2026_07_28_rc_server.dart`](../test/conformance/mcp_2026_07_28_rc_server.dart) | TypeScript SDK beta fixture validates `subscriptions/listen` acknowledgment and list-change notification correlation against the Dart server. | Subscription scenarios in alpha.8. | Verified | +| Request-scoped logging and removed core RPCs | [Logging](https://modelcontextprotocol.io/specification/draft/server/utilities/logging), [Key changes](https://modelcontextprotocol.io/specification/draft/changelog) | 2026 stateless requests use request-scoped logging metadata, and removed stable-era core RPCs/notifications are rejected in the 2026 profile. | [`test/mcp_2026_07_28_test.dart`](../test/mcp_2026_07_28_test.dart), [`test/server/server_advanced_test.dart`](../test/server/server_advanced_test.dart) | TypeScript SDK beta fixture validates raw removed-RPC rejection against the Dart server. | Removed-RPC and logging scenarios in alpha.8. | Verified | | Draft-only public APIs | [Schema reference](https://modelcontextprotocol.io/specification/draft/schema) | APIs that are useful only for 2026, such as non-object structured tool output and 2026 protocol profiles, are documented as draft/RC APIs and do not change stable defaults. | [`doc/mcp-2026-07-28-rc.md`](mcp-2026-07-28-rc.md), public dartdoc on protocol profiles and draft-only helpers. | Not cross-SDK specific. | Covered indirectly by 2026 conformance and local parser/serializer tests. | Verified | ## Known Gaps - The official conformance package is still alpha. The 2026 client suite keeps - `json-schema-ref-no-deref` expected-failed because the alpha.7 mock server for + `json-schema-ref-no-deref` expected-failed because the alpha.8 mock server for that scenario still behaves like a stable-only server. -- The TypeScript 2026-07-28 fixture depends on `pkg.pr.new` preview artifacts - from the TypeScript SDK branch. Keep the CI workflow, but re-pin it to a - published alpha package once upstream provides one that advertises the 2026 - draft path. The published `@modelcontextprotocol/client/server@2.0.0-alpha.3` - packages are missing the preview negotiation API used by this fixture, so - they are not a valid replacement for the current preview pin. -- The reverse Dart preview client -> TypeScript preview server path currently +- The reverse Dart 2026 client -> TypeScript SDK beta server path currently covers discovery, `tools/list`, and `tools/call`. Broader reverse-path - coverage should follow as the TypeScript preview server surface stabilizes. + coverage should follow as the TypeScript SDK beta server surface stabilizes. diff --git a/lib/src/server/mcp_server.dart b/lib/src/server/mcp_server.dart index 9447e376..5e5ebd89 100644 --- a/lib/src/server/mcp_server.dart +++ b/lib/src/server/mcp_server.dart @@ -15,6 +15,9 @@ import 'tasks.dart'; final _logger = Logger("mcp_dart.server.mcp"); +const _requiredClientCapabilitiesMetaKey = + 'io.modelcontextprotocol/requiredClientCapabilities'; + /// Callback capable of providing completions for a partial value. typedef CompleteCallback = FutureOr> Function(String value); @@ -1083,7 +1086,18 @@ class McpServer { /// Connects the server to a communication [transport]. Future connect(Transport transport) async { _syncToolParameterHeaderMappings(transport); - return await server.connect(transport); + await server.connect(transport); + if (transport is IncomingRequestValidationAwareTransport) { + final validationAwareTransport = + transport as IncomingRequestValidationAwareTransport; + validationAwareTransport.setIncomingRequestValidator((request) { + final protocolError = server.validateIncomingRequest(request); + if (protocolError != null) { + return protocolError; + } + return _validateToolClientCapabilities(request); + }); + } } /// Closes the server connection. @@ -1094,6 +1108,77 @@ class McpServer { /// Checks if the server is connected to a transport. bool get isConnected => server.transport != null; + McpError? _validateToolClientCapabilities(JsonRpcRequest request) { + if (request is! JsonRpcCallToolRequest || + !_isDraft2026Request(request.meta?[McpMetaKey.protocolVersion])) { + return null; + } + + final tool = _registeredTools[request.callParams.name]; + if (tool == null) { + return null; + } + + final requiredCapabilities = _requiredClientCapabilities(tool); + if (requiredCapabilities.isEmpty) { + return null; + } + + final clientCapabilitiesValue = + request.meta?[McpMetaKey.clientCapabilities]; + if (clientCapabilitiesValue is! Map) { + return McpError( + ErrorCode.invalidParams.value, + 'Missing required request metadata: ${McpMetaKey.clientCapabilities}', + ); + } + + final clientCapabilities = ClientCapabilities.fromJson( + clientCapabilitiesValue.cast(), + ); + final missingCapabilities = requiredCapabilities + .where( + (capability) => !_hasClientCapability(clientCapabilities, capability), + ) + .toList(growable: false); + if (missingCapabilities.isEmpty) { + return null; + } + + return McpError( + ErrorCode.missingRequiredClientCapability.value, + 'Missing required client capability', + {'requiredCapabilities': missingCapabilities}, + ); + } + + List _requiredClientCapabilities(_RegisteredToolImpl tool) { + final value = tool.meta?[_requiredClientCapabilitiesMetaKey]; + if (value is String) { + return [value]; + } + if (value is Iterable) { + return value.whereType().toList(growable: false); + } + return const []; + } + + bool _hasClientCapability( + ClientCapabilities capabilities, + String capability, + ) { + return switch (capability) { + 'sampling' => capabilities.sampling != null, + 'roots' => capabilities.roots != null, + 'elicitation' => capabilities.elicitation != null, + 'tasks' => capabilities.tasks != null, + _ => capabilities.additionalCapabilities?.containsKey(capability) ?? + capabilities.experimental?.containsKey(capability) ?? + capabilities.extensions?.containsKey(capability) ?? + false, + }; + } + /// Sends a logging message to the client, if connected. /// /// For stateless MCP requests, pass [requestMeta] from diff --git a/test/conformance/2026_07_28_rc_client_expected_failures.txt b/test/conformance/2026_07_28_rc_client_expected_failures.txt index fd91ef9e..2cbf84be 100644 --- a/test/conformance/2026_07_28_rc_client_expected_failures.txt +++ b/test/conformance/2026_07_28_rc_client_expected_failures.txt @@ -1,10 +1,10 @@ -# Expected failures for @modelcontextprotocol/conformance@0.2.0-alpha.7 +# Expected failures for @modelcontextprotocol/conformance@0.2.0-alpha.8 # against the 2026-07-28 RC/DRAFT client suite. # # Keep this list scenario-based so the baseline is easy to review. When a # scenario turns green, remove it from this file in the same PR as the fix. # -# Upstream alpha.7 fixture gap: this scenario's mock server still rejects +# Upstream alpha.8 fixture gap: this scenario's mock server still rejects # 2026-07-28 with HTTP 400 and advertises only stable protocol versions. # Keep it expected-fail until the conformance fixture is draft-capable. json-schema-ref-no-deref diff --git a/test/conformance/2026_07_28_rc_expected_failures.txt b/test/conformance/2026_07_28_rc_expected_failures.txt index 20a0c852..21abbea0 100644 --- a/test/conformance/2026_07_28_rc_expected_failures.txt +++ b/test/conformance/2026_07_28_rc_expected_failures.txt @@ -1,6 +1,8 @@ -# Expected failures for @modelcontextprotocol/conformance@0.2.0-alpha.7 +# Expected failures for @modelcontextprotocol/conformance@0.2.0-alpha.8 # against the full 2026-07-28 RC/DRAFT server suite. # +# The alpha.8 server suite has no expected failures against the Dart fixture. +# # Keep this list scenario-based so the baseline is easy to review. When a # scenario turns green, remove it from this file in the same PR as the fix. # diff --git a/test/conformance/README.md b/test/conformance/README.md index 2f494251..e7a5c6b7 100644 --- a/test/conformance/README.md +++ b/test/conformance/README.md @@ -26,14 +26,14 @@ dart run test/conformance/run_2025_server_conformance.dart ``` The runner starts `mcp_2025_server.dart`, runs -`@modelcontextprotocol/conformance@0.2.0-alpha.7 server --suite all +`@modelcontextprotocol/conformance@0.2.0-alpha.8 server --suite all --spec-version 2025-11-25`, and writes artifacts under `.dart_tool/conformance/2025_server/`. Run the stable client suite from the repository root: ```bash -npx -y @modelcontextprotocol/conformance@0.2.0-alpha.7 client \ +npx -y @modelcontextprotocol/conformance@0.2.0-alpha.8 client \ --command "dart run test/conformance/mcp_2026_07_28_rc_client.dart" \ --suite all \ --spec-version 2025-11-25 \ @@ -55,14 +55,14 @@ dart run test/conformance/run_2026_07_28_rc_server_conformance.dart The runner starts a local `StreamableMcpServer` in default Streamable HTTP SSE response mode, runs the full `2026-07-28` server scenario list from -`@modelcontextprotocol/conformance@0.2.0-alpha.7` one by one with `--suite all` +`@modelcontextprotocol/conformance@0.2.0-alpha.8` one by one with `--suite all` and `--spec-version 2026-07-28`, and writes per-run artifacts under `.dart_tool/conformance/2026_07_28_rc/`. Expected failures live in `2026_07_28_rc_expected_failures.txt`. When a scenario is fixed, remove it from that file so the baseline remains useful. -As of `@modelcontextprotocol/conformance@0.2.0-alpha.7`, the full 2026-07-28 RC server +As of `@modelcontextprotocol/conformance@0.2.0-alpha.8`, the full 2026-07-28 RC server suite has no expected failures against the Dart fixture. Run the current client baseline from the repository root: diff --git a/test/conformance/mcp_2026_07_28_rc_client.dart b/test/conformance/mcp_2026_07_28_rc_client.dart index b63ff3bf..a6b1cdf5 100644 --- a/test/conformance/mcp_2026_07_28_rc_client.dart +++ b/test/conformance/mcp_2026_07_28_rc_client.dart @@ -251,7 +251,6 @@ Future _runCustomHeaders( 'debug': 'Debug', 'empty_val': 'EmptyVal', 'method_val': 'Method', - 'float_val': 'FloatVal', 'non_ascii_val': 'NonAscii', 'whitespace_val': 'Whitespace', 'leading_space_val': 'LeadingSpace', diff --git a/test/conformance/mcp_2026_07_28_rc_server.dart b/test/conformance/mcp_2026_07_28_rc_server.dart index 868c4fe5..3473c1e4 100644 --- a/test/conformance/mcp_2026_07_28_rc_server.dart +++ b/test/conformance/mcp_2026_07_28_rc_server.dart @@ -104,12 +104,52 @@ McpServer _createConformanceServer() { }, ); + _registerAlpha8StatelessDiagnostics(server); _registerStreamDiagnostics(server); _registerInputRequiredDiagnostics(server); return server; } +void _registerAlpha8StatelessDiagnostics(McpServer server) { + server.registerTool( + 'test_missing_capability', + description: + 'Requires sampling so missing client capability handling can be validated', + meta: const { + 'io.modelcontextprotocol/requiredClientCapabilities': ['sampling'], + }, + callback: (args, extra) async { + return _textResult('sampling capability present'); + }, + ); + + server.registerTool( + 'test_streaming_elicitation', + description: + 'Returns a normal result so response-stream frame shape can be validated', + callback: (args, extra) async { + return _textResult('stream-shape-ok'); + }, + ); + + server.registerTool( + 'test_logging_tool', + description: + 'Attempts request-scoped logging for the stateless log-level diagnostic', + callback: (args, extra) async { + await server.sendLoggingMessage( + const LoggingMessageNotification( + level: LoggingLevel.info, + data: 'log-level diagnostic', + ), + requestMeta: extra.meta, + ); + return _textResult('logging-ok'); + }, + ); +} + void _registerStreamDiagnostics(McpServer server) { server.registerTool( 'test_stream_cancellation', diff --git a/test/conformance/run_2025_server_conformance.dart b/test/conformance/run_2025_server_conformance.dart index e03fd9f4..cf3aa87f 100644 --- a/test/conformance/run_2025_server_conformance.dart +++ b/test/conformance/run_2025_server_conformance.dart @@ -3,10 +3,10 @@ import 'dart:convert'; import 'dart:io'; const _defaultConformancePackage = - '@modelcontextprotocol/conformance@0.2.0-alpha.7'; + '@modelcontextprotocol/conformance@0.2.0-alpha.8'; const _defaultTimeout = Duration(seconds: 60); -// The alpha.7 conformance CLI occasionally leaks or stalls server-initiated +// The alpha conformance CLI can occasionally leak or stall server-initiated // elicitation state when the complete 2025 server suite is run in one process // on GitHub's Linux runners. Running each pinned scenario in a fresh // conformance process preserves coverage while isolating CLI-side state. diff --git a/test/conformance/run_2026_07_28_rc_client_conformance.dart b/test/conformance/run_2026_07_28_rc_client_conformance.dart index 155254e9..34feddba 100644 --- a/test/conformance/run_2026_07_28_rc_client_conformance.dart +++ b/test/conformance/run_2026_07_28_rc_client_conformance.dart @@ -3,7 +3,7 @@ import 'dart:convert'; import 'dart:io'; const _defaultConformancePackage = - '@modelcontextprotocol/conformance@0.2.0-alpha.7'; + '@modelcontextprotocol/conformance@0.2.0-alpha.8'; const _defaultTimeout = Duration(seconds: 30); const _draftClientScenarios = [ diff --git a/test/conformance/run_2026_07_28_rc_server_conformance.dart b/test/conformance/run_2026_07_28_rc_server_conformance.dart index 321b0cb8..68ccb129 100644 --- a/test/conformance/run_2026_07_28_rc_server_conformance.dart +++ b/test/conformance/run_2026_07_28_rc_server_conformance.dart @@ -3,7 +3,7 @@ import 'dart:convert'; import 'dart:io'; const _defaultConformancePackage = - '@modelcontextprotocol/conformance@0.2.0-alpha.7'; + '@modelcontextprotocol/conformance@0.2.0-alpha.8'; const _defaultTimeout = Duration(seconds: 25); const _serverScenarios = [ diff --git a/test/interop/ts_2026_07_28_rc/README.md b/test/interop/ts_2026_07_28_rc/README.md index 8ed45e4c..8a294f24 100644 --- a/test/interop/ts_2026_07_28_rc/README.md +++ b/test/interop/ts_2026_07_28_rc/README.md @@ -5,12 +5,12 @@ This fixture is an experimental smoke test for the unreleased MCP progress. It is intentionally separate from `test/interop/ts`, which tracks the published -stable TypeScript SDK and MCP `2025-11-25` behavior. The fixture pins -`pkg.pr.new` client and server previews from the TypeScript SDK -`v2-2026-07-28` branch after PR #2327 landed. The TypeScript client path is a -draft-aligned smoke check against the Dart 2026-07-28 RC server. The reverse Dart -client path is a draft-aligned smoke check against the TypeScript preview -server. +stable TypeScript SDK and MCP `2025-11-25` behavior. The fixture pins published +`@modelcontextprotocol/client@2.0.0-beta.1` and +`@modelcontextprotocol/server@2.0.0-beta.1` packages. The TypeScript client path +is a draft-aligned smoke check against the Dart 2026-07-28 RC server. The +reverse Dart client path is a draft-aligned smoke check against the TypeScript +beta server. ## Run @@ -53,10 +53,10 @@ bound local URL, and then runs `src/client.mjs` against it. The fixture asserts: - Closing a 2026 HTTP SSE response stream cancels the in-flight Dart server request without sending `notifications/cancelled`. -The runner also starts `src/server.mjs` with the TypeScript preview +The runner also starts `src/server.mjs` with the TypeScript beta `createMcpHandler` entry and runs a Dart preview client against it. That reverse path asserts `server/discover` negotiation, `tools/list`, and `tools/call` -against the TypeScript preview server; failures are treated as interop failures. +against the TypeScript beta server; failures are treated as interop failures. Keep this fixture anchored to the official draft/RC behavior rather than the preview TypeScript implementation alone. In particular, `x-mcp-header` tests use @@ -67,11 +67,6 @@ assertion source and document the preview gap near the test. CI runs this fixture in the dedicated `Run MCP 2026-07-28 TypeScript Interop` workflow for relevant PRs, `dev/2026-07-28-rc` pushes, daily scheduled drift checks, and manual dispatch. -Keep the fixture pinned to a published TypeScript SDK alpha once upstream no -longer requires `pkg.pr.new` preview artifacts. Do not treat publication alone -as enough to re-pin: `@modelcontextprotocol/client@2.0.0-alpha.3` and -`@modelcontextprotocol/server@2.0.0-alpha.3` are published, but the published -client does not expose the preview `versionNegotiation` / `getProtocolEra` APIs -used here, and a direct `supportedProtocolVersions: ["2026-07-28"]` repin fails -the handshake. Keep this fixture on the `pkg.pr.new` preview until a published -package exposes the 2026 draft path and this runner passes against it. +Keep the fixture pinned to a published TypeScript SDK beta that exposes the +2026 draft path and passes this runner; do not treat package publication alone +as enough to re-pin without rerunning the interop check. diff --git a/test/interop/ts_2026_07_28_rc/package-lock.json b/test/interop/ts_2026_07_28_rc/package-lock.json index d24447b0..bdbe33f3 100644 --- a/test/interop/ts_2026_07_28_rc/package-lock.json +++ b/test/interop/ts_2026_07_28_rc/package-lock.json @@ -9,8 +9,8 @@ "version": "0.0.0", "dependencies": { "@cfworker/json-schema": "4.1.1", - "@modelcontextprotocol/client": "https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/client@9fdb62e", - "@modelcontextprotocol/server": "https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/server@9fdb62e" + "@modelcontextprotocol/client": "2.0.0-beta.1", + "@modelcontextprotocol/server": "2.0.0-beta.1" }, "engines": { "node": ">=20" @@ -23,9 +23,9 @@ "license": "MIT" }, "node_modules/@modelcontextprotocol/client": { - "version": "2.0.0-alpha.2", - "resolved": "https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/client@9fdb62e", - "integrity": "sha512-A02KwaeB0p7WJ8TCQB83WLtPpGUK+1h3y4k6IMxfun3VmIiH7jrAw2y72TmSnofwO1GKYr53R142t78sCE5ycg==", + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/client/-/client-2.0.0-beta.1.tgz", + "integrity": "sha512-1YbnguKN7OFGA/lmCtgIthyE5d+j7dvu7hJld+f0mKrM0YAV4Q8TG80RBto+qyupxhHjTMEWItHu7cQlAmVtyA==", "license": "MIT", "dependencies": { "cross-spawn": "^7.0.5", @@ -40,9 +40,9 @@ } }, "node_modules/@modelcontextprotocol/server": { - "version": "2.0.0-alpha.2", - "resolved": "https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/server@9fdb62e", - "integrity": "sha512-4yLquMq4S/d69ISm7XyDsyVDxtih7jGVKCXK1QDqBuxVgFGDN2jY4iZb13kFVD28Wv1IPQ93pHtCEEn7j+0iqw==", + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/server/-/server-2.0.0-beta.1.tgz", + "integrity": "sha512-83scKauajX9fWbSIC4NBYdnvXajH+cqvX8QqsrPH0XNgqtMmym1kWucMO7YyNkrBD9C7/R+FRCmkjC9kgEKXlQ==", "license": "MIT", "dependencies": { "zod": "^4.2.0" diff --git a/test/interop/ts_2026_07_28_rc/package.json b/test/interop/ts_2026_07_28_rc/package.json index 93f537a3..7c870d8d 100644 --- a/test/interop/ts_2026_07_28_rc/package.json +++ b/test/interop/ts_2026_07_28_rc/package.json @@ -9,8 +9,8 @@ }, "dependencies": { "@cfworker/json-schema": "4.1.1", - "@modelcontextprotocol/client": "https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/client@9fdb62e", - "@modelcontextprotocol/server": "https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/server@9fdb62e" + "@modelcontextprotocol/client": "2.0.0-beta.1", + "@modelcontextprotocol/server": "2.0.0-beta.1" }, "engines": { "node": ">=20" diff --git a/test/mcp_2026_07_28_test.dart b/test/mcp_2026_07_28_test.dart index 91081152..bd64c977 100644 --- a/test/mcp_2026_07_28_test.dart +++ b/test/mcp_2026_07_28_test.dart @@ -45,6 +45,24 @@ class RecordingTransport extends Transport { } } +class ValidationRecordingTransport extends RecordingTransport + implements IncomingRequestValidationAwareTransport { + McpError? Function(JsonRpcRequest request)? incomingRequestValidator; + bool Function(String method)? requestMethodSupported; + + @override + void setIncomingRequestValidator( + McpError? Function(JsonRpcRequest request) validator, + ) { + incomingRequestValidator = validator; + } + + @override + void setRequestMethodSupported(bool Function(String method) isSupported) { + requestMethodSupported = isSupported; + } +} + class SessionRecordingTaskStore extends InMemoryTaskStore { final List createTaskSessionIds = []; final List updateTaskStatusSessionIds = []; @@ -2991,6 +3009,59 @@ void main() { ); }); + test('stateless tools/call rejects missing tool-required client capability', + () async { + final server = McpServer( + const Implementation(name: 'server', version: '1.0.0'), + options: const McpServerOptions( + protocol: McpProtocol.preview2026, + ), + ); + server.registerTool( + 'needs_sampling', + meta: const { + 'io.modelcontextprotocol/requiredClientCapabilities': ['sampling'], + }, + callback: (args, extra) => const CallToolResult( + content: [TextContent(text: 'ok')], + ), + ); + final transport = ValidationRecordingTransport(); + await server.connect(transport); + final validator = transport.incomingRequestValidator; + expect(validator, isNotNull); + + final missingError = validator!( + JsonRpcCallToolRequest( + id: 'call-1', + params: const CallToolRequest(name: 'needs_sampling').toJson(), + meta: _clientMeta(), + ), + ); + + expect(missingError, isNotNull); + expect( + missingError!.code, + ErrorCode.missingRequiredClientCapability.value, + ); + expect(missingError.data, { + 'requiredCapabilities': ['sampling'], + }); + + final allowedError = validator( + JsonRpcCallToolRequest( + id: 'call-2', + params: const CallToolRequest(name: 'needs_sampling').toJson(), + meta: _clientMeta( + clientCapabilities: const ClientCapabilities( + sampling: ClientCapabilitiesSampling(tools: true), + ), + ), + ), + ); + expect(allowedError, isNull); + }); + test('stateless tools/call ignores legacy task parameter', () async { final server = McpServer( const Implementation(name: 'server', version: '1.0.0'),