Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
f9f9df5
Consolidate type schema validation
leehack Jun 1, 2026
9ee1f99
Validate sampling wire fields
leehack Jun 1, 2026
5807114
Validate content resource wire fields
leehack Jun 1, 2026
883532a
Validate initialization wire fields
leehack Jun 1, 2026
49e86b1
Validate prompt completion wire fields
leehack Jun 1, 2026
ddd8cb5
Validate tool wire fields
leehack Jun 1, 2026
f2f3b0c
Validate root wire fields
leehack Jun 1, 2026
14cf221
Validate task wire fields
leehack Jun 1, 2026
48192a3
Validate elicitation wire fields
leehack Jun 1, 2026
f3412b7
Validate subscription wire fields
leehack Jun 1, 2026
c6b3f03
Validate sampling tool wire fields
leehack Jun 1, 2026
74d3ff7
Validate content block discriminators
leehack Jun 1, 2026
5a37ecf
Validate resource content union
leehack Jun 1, 2026
85974fa
Validate sampling content discriminators
leehack Jun 1, 2026
980822e
Validate completion reference discriminators
leehack Jun 1, 2026
61ea486
Validate completion request wrapper constants
leehack Jun 1, 2026
3c6f976
Validate prompt request wrapper constants
leehack Jun 1, 2026
4a3a59a
Validate resource request wrapper constants
leehack Jun 1, 2026
8cc2d0c
Validate tool request wrapper constants
leehack Jun 1, 2026
8f28d52
Validate root request wrapper constants
leehack Jun 1, 2026
dfc0fe3
Validate common request wrapper constants
leehack Jun 1, 2026
4602e75
Validate initialization wrapper constants
leehack Jun 1, 2026
b2dca45
Validate task wrapper constants
leehack Jun 1, 2026
7a7b527
Validate sampling and elicitation wrapper constants
leehack Jun 1, 2026
59a6a00
Preserve empty result metadata
leehack Jun 1, 2026
e236fe4
Preserve filtered tool cache hints
leehack Jun 1, 2026
c113ff2
Preserve unknown capability entries
leehack Jun 1, 2026
afabf92
Handle client input_required retries
leehack Jun 1, 2026
4af899b
Handle custom request fallback dispatch
leehack Jun 1, 2026
c6132af
Validate stateless result types per request
leehack Jun 1, 2026
1ed5ea5
Handle task extension tool results
leehack Jun 1, 2026
3242957
Validate task extension status payloads
leehack Jun 1, 2026
89ebf0c
Route TaskClient through task extension flow
leehack Jun 1, 2026
b221387
Expand compliance coverage for 2026 RC
leehack Jun 1, 2026
9a57c75
Add official conformance CI coverage
leehack Jun 3, 2026
3f52eaf
Align header conformance with 2026 RC
leehack Jun 3, 2026
44333da
Use Node 24 for conformance CI
leehack Jun 3, 2026
5be81d6
Add typed protocol profile opt-in
leehack Jun 3, 2026
dee1e7e
Fix CLI conformance profile fixtures
leehack Jun 3, 2026
7f44ddb
Prepare 2026 draft dev release
leehack Jun 3, 2026
d2d4a10
Document deprecated public APIs
leehack Jun 3, 2026
0c5ca39
Wait for both Codecov uploads
leehack Jun 3, 2026
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
1 change: 1 addition & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jobs:
rm -rf "$PUBLISH_ROOT"
mkdir -p "$PUBLISH_ROOT"
rsync -a --exclude .git --exclude .dart_tool --exclude pubspec.lock ./ "$PUBLISH_ROOT/"
rm -f "$PUBLISH_ROOT/packages/mcp_dart_cli/pubspec_overrides.yaml"
echo "working_directory=$PUBLISH_ROOT/${{ steps.package-info.outputs.working_directory }}" >> "$GITHUB_OUTPUT"
else
echo "working_directory=${{ steps.package-info.outputs.working_directory }}" >> "$GITHUB_OUTPUT"
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/test_cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
node-version: '24'

- name: Set up Python
uses: actions/setup-python@v6
Expand Down Expand Up @@ -100,8 +100,10 @@ jobs:
# Given the previous task aimed for 160/160, let's keep it strict but maybe allow slight dev.
# For this initial workflow file, I will fail if not max points to maintain quality.
if [ "$PANA_EXIT" -ne 0 ] || [ "$SCORE" != "$MAX_POINTS" ]; then
if grep -q 'depends on mcp_dart .*which doesn.*t match any versions' pana_output.json; then
echo "::warning::Skipping strict CLI pana score because this PR prepares the CLI against an unpublished mcp_dart release. Publish mcp_dart first, then rerun pana before publishing mcp_dart_cli."
if grep -q 'depends on mcp_dart .*which doesn.*t match any versions' pana_output.json ||
{ grep -q '^dependency_overrides:' pubspec.yaml &&
grep -Eq 'UNDEFINED_(NAMED_PARAMETER|FUNCTION|GETTER|METHOD|CLASS)' pana_output.json; }; then
echo "::warning::Skipping strict CLI pana score because this PR prepares the CLI against unpublished local mcp_dart APIs. Publish mcp_dart first, then rerun pana before publishing mcp_dart_cli."
exit 0
fi
echo "pana exited with code $PANA_EXIT."
Expand Down
29 changes: 28 additions & 1 deletion .github/workflows/test_core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
node-version: '24'

- name: Install TS Interop dependencies
working-directory: test/interop/ts
Expand All @@ -43,6 +43,33 @@ jobs:
working-directory: packages/mcp_dart_cli
run: dart run bin/mcp_dart.dart conformance --suite all --json

- name: Run official MCP 2025 server conformance
run: >
dart run test/conformance/run_2025_server_conformance.dart
--timeout-seconds 90
--output-dir .dart_tool/conformance/ci_2025_server

- name: Run official MCP 2025 client conformance
run: >
npx -y @modelcontextprotocol/conformance@0.2.0-alpha.1 client
--command "dart run test/conformance/mcp_2026_rc_client.dart"
--suite all
--spec-version 2025-11-25
--verbose
-o .dart_tool/conformance/ci_2025_client

- name: Run official MCP 2026 RC server conformance
run: >
dart run test/conformance/run_2026_rc_server_conformance.dart
--timeout-seconds 90
--output-dir .dart_tool/conformance/ci_2026_server

- name: Run official MCP 2026 RC client conformance
run: >
dart run test/conformance/run_2026_rc_client_conformance.dart
--timeout-seconds 90
--output-dir .dart_tool/conformance/ci_2026_client

- name: Run interop test suite
run: dart test -t interop

Expand Down
147 changes: 137 additions & 10 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
## Unreleased
## 2.3.0-dev.0

### MCP 2026-07-28 RC
### MCP 2026-07-28 draft/RC

- Started the MCP 2026-07-28 RC development line with opt-in protocol
constants, stateless request metadata helpers, and `server/discover` request
and result types.
- Added server-side `server/discover` handling before legacy initialization and
initial stateless request validation for per-request protocol version,
client identity, and client capability metadata.
- Added opt-in client discovery via `McpClientOptions(useServerDiscover: true)`
while keeping the stable `initialize` flow as the default until the 2026
stateless transport and MRTR implementation is complete.
- Added explicit protocol profiles via
`McpClientOptions(protocol: McpProtocol.preview2026)` and
`McpServerOptions(protocol: McpProtocol.preview2026)` while keeping the stable
`initialize` flow as the default. The lower-level `protocolVersion` and
`useServerDiscover` options remain available for interoperability testing.
- Kept stable public tool result APIs object-rooted while adding explicit
draft-only APIs for non-object values: `JsonValue`,
`CallToolResult.fromStructuredArray()`, `structuredContentJson`, and
server `outputJsonSchema`.
- Added 2026 cacheable result support for `tools/list`, `prompts/list`,
`resources/list`, `resources/templates/list`, and `resources/read`, including
stateless server defaults for `resultType`, `ttlMs`, and `cacheScope` while
Expand All @@ -22,11 +28,11 @@
- Synced registered tool `x-mcp-header` metadata into Streamable HTTP server
transports so 2026 stateless `tools/call` requests reject missing or
mismatched `Mcp-Param-*` argument headers.
- Rejected `x-mcp-header` usage on JSON Schema `number` parameters, keeping
mirrored tool headers limited to string, JavaScript-safe integer, and boolean
parameters.
- Removed `Mcp-Session-Id` from 2026 stateless Streamable HTTP requests by
stripping it from client sends and ignoring it on stateless server POSTs.
- Prevented 2026 stateless request handlers and task-store operations from
inheriting transport session IDs, including direct Streamable HTTP transport
responses after a prior stateful initialization.
- Enforced 2026 stateless Streamable HTTP POST-only behavior by skipping
legacy client GET/DELETE session paths and returning `Allow: POST` for
stateless non-POST server requests.
Expand All @@ -37,16 +43,38 @@
values beginning with `=?base64?` and ending with `?=` round-trip correctly.
- Synced nested 2026 `x-mcp-header` mappings into Streamable HTTP transports
using JSON Pointer selectors for nested tool arguments.
- Limited 2026 Streamable HTTP `x-mcp-header` mirroring to string, boolean,
finite number, and JavaScript-safe integer argument values; unsafe integers
and non-finite numbers are omitted.
- Returned HTTP 404 with JSON-RPC `Method not found` for unsupported or removed
2026 stateless Streamable HTTP request methods before opening response
streams.
- Sent and required `Mcp-Name` for MCP 2026 task lifecycle requests over
Streamable HTTP, using the request body `taskId` as the routing value.
- Accepted MCP 2026 stateless Streamable HTTP JSON-RPC response POSTs without
requiring request-only metadata in the response body.
- Treated client closure of a 2026 stateless Streamable HTTP SSE response stream
as cancellation of that pending request.
- Sorted 2026 stateless high-level `tools/list` responses by tool name for
deterministic list results while preserving legacy registration-order output.
- Omitted stable-only `Tool.execution` metadata from 2026 stateless
`tools/list` responses and embedded MRTR sampling tool definitions while
preserving stable/default serialization.
- Rejected legacy `RequestOptions.task` augmentation before sending 2026
stateless requests while preserving stable task augmentation.
- Added `tool/spec_example_audit.dart` so upstream machine-readable spec
examples can be parsed through the checked-in typed SDK surfaces during
RC/final release audits.
- Gated 2026 stateless task extension methods on advertised server extension
support and rejected legacy task result shapes on extension `tasks/get`,
`tasks/update`, and `tasks/cancel` handlers.
- Ignored legacy `tools/call` `task` parameters on 2026 stateless requests so
handlers do not receive legacy task TTL hints through `RequestHandlerExtra`.
- Required 2026 stateless task creation results to be immediately resolvable
through `tasks/get` before returning `resultType: "task"`.
- Exposed task-store options on `McpServerOptions` and serialized built-in
task-store `tasks/get`/`tasks/cancel` handlers in the 2026 task-extension
wire shape for stateless requests.
- Added request-scoped stateless logging gating via
`io.modelcontextprotocol/logLevel` metadata so 2026 log notifications are
emitted only when the current request opts in.
Expand All @@ -63,9 +91,34 @@
`input_required` results instead.
- Enforced `subscriptions/listen` stream ordering and filters for 2026
subscription notifications.
- Required nested request `_meta` on `subscriptions/listen` requests, matching
the 2026 schema's per-request metadata requirement.
- Rejected mismatched JSON-RPC `jsonrpc` and `method` wrapper constants when
parsing typed `notifications/subscriptions/acknowledged` notifications.
- Rejected mismatched JSON-RPC wrapper constants when directly parsing the
experimental completion list-changed notification.
- Rejected incoming `tools/call` JSON-RPC requests that omit the MCP-required
`params` object.
- Rejected JSON-RPC envelopes that mix request/notification `method` fields
with response `result` or `error` fields, including direct typed
request/notification/error parsing.
- Returned `MissingRequiredClientCapability` (`-32003`) with required task
extension capability data when 2026 task notification subscriptions omit the
per-request `io.modelcontextprotocol/tasks` client capability.
- Rejected deprecated sampling `includeContext` values unless the client
advertises `sampling.context`, while still allowing omitted context and
`includeContext: "none"`.
- Stopped sending `notifications/cancelled` when an outgoing `initialize`
request is aborted or times out, matching the stable lifecycle rule that
clients must not cancel initialization.
- Required `notifications/cancelled` payloads to carry a valid string-or-integer
`requestId` instead of accepting ID-less cancellation notifications.
- Retried `server/discover` with an advertised compatible stateless protocol
version after `UnsupportedProtocolVersionError` instead of falling back to
legacy initialization.
- Accepted whole-number JSON numeric values for integer wire fields such as
resource link sizes, completion totals, sampling `maxTokens`, task TTLs, and
JSON Schema length/item bounds while continuing to reject fractional values.
- Added client-side `subscriptions/listen` handles that correlate stream
notifications by `io.modelcontextprotocol/subscriptionId`, validate the
acknowledgment, and cancel long-lived streams with `notifications/cancelled`.
Expand All @@ -84,18 +137,84 @@
stateless requests use `-32602` with the missing `uri` in error data.
- Enforced MCP 2026 `_meta` key-name grammar on stateless request metadata and
the 2026 request metadata builder while preserving legacy metadata parsing.
- Exposed typed request-envelope accessors on `RequestHandlerExtra` for
per-request protocol version, client info, and client capabilities metadata.
- Rejected negative cacheable-result `ttlMs` values during parsing instead of
clamping malformed wire values to zero.
- Validated MRTR `inputResponses` as `CreateMessageResult`, `ListRootsResult`,
or `ElicitResult` instead of accepting arbitrary result objects.
- Allowed finite numeric `ElicitResult.content` values to match the stable and
MCP 2026 `string | number | boolean | string[]` schema.
- Restricted numeric `ElicitResult.content` values to integers, matching the
stable and MCP 2026 `string | integer | boolean | string[]` schemas while
still accepting whole-number JSON numeric values.
- Required integer `minimum`, `maximum`, and `default` values in form
elicitation number schemas for both stable 2025 and MCP 2026.
- Rejected MCP 2026 `CallToolResult.extra` attempts to spoof non-complete
`resultType` values, and added CLI conformance coverage for that guard.
- Rejected form elicitation schemas that provide legacy `enumNames` without the
required string `enum`.
- Rejected `ElicitResult.content` when the result action is `decline` or
`cancel`.
- Rejected URL elicitation values that are not absolute URIs to match the stable
and MCP 2026 `format: uri` schemas.
- Rejected non-absolute resource URIs and malformed resource URI templates to
match stable and MCP 2026 `format: uri` and `format: uri-template` schemas.
- Rejected malformed base64 payloads for image, audio, and blob resource
content to match stable and MCP 2026 `format: byte` schemas.
- Rejected malformed shared annotation fields, including non-role audiences,
out-of-range priorities, and non-string `lastModified` values.
- Rejected malformed `Role` values in prompt and sampling messages instead of
allowing raw enum lookup failures.
- Rejected malformed logging level, sampling `includeContext`, and sampling
`toolChoice.mode` enum values with protocol parse errors.
- Rejected malformed sampling string, boolean, and string-list wire fields with
protocol parse errors.
- Rejected malformed content and resource string/list wire fields with protocol
parse errors.
- Rejected malformed initialization and capability wire fields with protocol
parse errors.
- Rejected malformed prompt, completion, logging, and common notification wire
fields with protocol parse errors.
- Rejected malformed prompt JSON-RPC wrapper constants with protocol parse
errors.
- Rejected malformed resource JSON-RPC wrapper constants with protocol parse
errors.
- Rejected malformed tool JSON-RPC wrapper constants with protocol parse
errors.
- Rejected malformed root JSON-RPC wrapper constants with protocol parse
errors.
- Rejected malformed common notification and logging JSON-RPC wrapper
constants with protocol parse errors.
- Rejected malformed initialization and `server/discover` JSON-RPC wrapper
constants with protocol parse errors.
- Rejected malformed task and task-extension JSON-RPC wrapper constants with
protocol parse errors.
- Rejected malformed sampling and elicitation JSON-RPC wrapper constants while
preserving embedded MRTR input request parsing.
- Preserved `Result._meta` while parsing empty results for high-level ping,
logging, and subscription acknowledgments.
- Preserved MCP 2026 `tools/list` cache hints when client-side tool metadata
filtering removes invalid tool definitions.
- Rejected missing and mismatched completion reference type discriminators with
protocol parse errors.
- Rejected malformed completion JSON-RPC wrapper constants with protocol parse
errors.
- Rejected malformed tool definition, tool-list, and tool-call wire fields with
protocol parse errors.
- Rejected malformed root-list wire fields with protocol parse errors.
- Rejected malformed stable task and task-extension wire fields with protocol
parse errors.
- Rejected malformed elicitation request, result, completion, and URL-required
error wire fields with protocol parse errors.
- Rejected malformed subscription listen and acknowledgment wire fields with
protocol parse errors.
- Rejected malformed sampling tool-list, tool-choice, and tool-result content
wire fields with protocol parse errors.
- Rejected missing, unknown, and mismatched content block type discriminators
with protocol parse errors.
- Rejected missing and mismatched sampling content type discriminators with
protocol parse errors.
- Rejected resource content items that omit both `text` and `blob`, matching
the spec-defined `TextResourceContents | BlobResourceContents` union.
- Rejected non-finite numeric values for progress, annotation priority, model
priority, and sampling temperature fields so SDK-built payloads remain valid
JSON numbers.
Expand Down Expand Up @@ -123,6 +242,8 @@
notification methods removed from that protocol revision.
- Rejected server-initiated JSON-RPC requests received by stateless MCP 2026
clients on generic transports.
- Omitted the removed `roots.listChanged` client capability from MCP 2026
stateless request metadata while preserving it for stable 2025 metadata.
- Rejected stateless MCP 2026 responses that omit `resultType` or required
cacheable-result fields.
- Stripped caller-supplied `Mcp-Session-Id` headers case-insensitively from
Expand All @@ -140,6 +261,12 @@
dispatch finite numeric progress tokens end-to-end.
- Widened protocol `relatedRequestId` API parameters to preserve string and
finite numeric JSON-RPC request IDs through request and notification routing.
- Accepted numeric `minimum`, `maximum`, `exclusiveMinimum`,
`exclusiveMaximum`, `multipleOf`, and `default` values on JSON Schema
`integer` schemas, matching the stable and MCP 2026 schema definitions.
- Preserved object-level JSON Schema 2020-12 keywords on `JsonObject`
round-trips and added official MCP conformance gates for stable 2025 and
2026 RC client/server coverage in core CI.

## 2.2.0

Expand Down
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Add to your `pubspec.yaml`:

```yaml
dependencies:
mcp_dart: ^2.2.0
mcp_dart: ^2.3.0-dev.0
```

Then install dependencies:
Expand Down Expand Up @@ -87,10 +87,35 @@ Use this comparison as a starting point, not a permanent verdict: both packages

## Model Context Protocol Version

The current version of the protocol is `2025-11-25`. This library is designed to be compatible with this version, and any future updates will be made to ensure continued compatibility.
The default protocol profile is MCP `2025-11-25`. This library is designed to
be compatible with this version, and any future updates will preserve an
explicit stable profile.

It's also backward compatible with previous versions including `2025-06-18`, `2025-03-26`, `2024-11-05`, and `2024-10-07`.

MCP `2026-07-28` draft/RC support is available behind an explicit preview
profile:

```dart
final client = McpClient(
const Implementation(name: 'my-client', version: '1.0.0'),
options: const McpClientOptions(
protocol: McpProtocol.preview2026,
),
);

final server = McpServer(
const Implementation(name: 'my-server', version: '1.0.0'),
options: const McpServerOptions(
protocol: McpProtocol.preview2026,
),
);
```

Use the preview profile while the spec is still a draft/RC. See the
[MCP 2026-07-28 draft/RC transition guide](https://github.com/leehack/mcp_dart/blob/main/doc/mcp-2026-rc.md)
for opt-in behavior, fallback rules, and draft-only APIs.

## Documentation

### Getting Started
Expand All @@ -112,6 +137,7 @@ It's also backward compatible with previous versions including `2025-06-18`, `20

- 🧪 **[SDK Interoperability Matrix](https://github.com/leehack/mcp_dart/blob/main/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/main/doc/spec-coverage-2025-11-25.md)** - Auditable coverage map with CLI conformance cases and known gaps
- 🧭 **[MCP 2026-07-28 Draft/RC Transition Guide](https://github.com/leehack/mcp_dart/blob/main/doc/mcp-2026-rc.md)** - Opt-in profile, fallback behavior, and draft-only APIs
- 🔒 **[Transport Security Recipes](https://github.com/leehack/mcp_dart/blob/main/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/main/doc/flutter-recipes.md)** - Flutter Web, mobile, and desktop host/client guidance
- 🔁 **[Migration Cookbooks](https://github.com/leehack/mcp_dart/blob/main/doc/migration-cookbooks.md)** - TypeScript SDK, `dart_mcp`, stdio-to-HTTP, and version migration paths
Expand Down
4 changes: 4 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
codecov:
notify:
after_n_builds: 2

coverage:
status:
project:
Expand Down
Loading
Loading