Skip to content

Commit 102f94b

Browse files
Merge branch 'main' into feat/sep-2106-json-schema-2020-12
2 parents 895e7a1 + 78fbe27 commit 102f94b

53 files changed

Lines changed: 1682 additions & 200 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@modelcontextprotocol/server': patch
3+
---
4+
5+
Bound the protocol-version checks gating SSE resumability behavior (priming events and `closeSSEStream` callbacks) in the Streamable HTTP server transport. Previously an open-ended `>= '2025-11-25'` comparison let unknown future protocol version strings from an `initialize`
6+
request body enable this behavior; the version must now also be one of the transport's supported protocol versions. Behavior for all currently supported protocol versions is unchanged.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@modelcontextprotocol/codemod': patch
3+
---
4+
5+
The v1→v2 codemod now migrates the removed `StreamableHTTPError` to `SdkHttpError` (instead of the base `SdkError`), matching the shipped error type and the migration guide. Diagnostics now point at the typed `error.status` / `error.statusText` accessors and note that unexpected-content-type responses are thrown as the base `SdkError`.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'@modelcontextprotocol/server': patch
3+
'@modelcontextprotocol/client': patch
4+
---
5+
6+
Non-SEP draft spec conformance fixes
7+
8+
- `McpServer` now eagerly installs list/read/call handlers for every primitive capability (`tools`, `resources`, `prompts`) declared in `ServerOptions.capabilities`. Per the draft spec, a server that declares a capability MUST respond to its list method (potentially with an empty result) instead of returning "Method not found". Previously, handlers were only installed lazily on first registration, so a server constructed with e.g. `capabilities: { tools: {} }` and zero registered tools answered `tools/list` with `-32601`. Low-level `Server` users remain responsible for registering handlers for declared capabilities (documented on `ServerOptions.capabilities`).
9+
- Fixed pagination doc examples on `Client.listTools`/`listPrompts`/`listResources` to loop `while (cursor !== undefined)` instead of `while (cursor)` — per the draft spec, clients MUST NOT treat an empty-string cursor as the end of results.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@modelcontextprotocol/test-conformance': patch
3+
---
4+
5+
Fix the server conformance script leaking the test server process: the cleanup trap killed the npx wrapper while the actual server kept listening on port 3000, making later runs silently test stale code or hang forever in the readiness loop. The script now spawns the server directly with `node --import tsx`, refuses to start while the port is taken, and bounds each readiness probe; both test servers report `EADDRINUSE` with an actionable message, and the plain `test:conformance:client` script works again (`--suite core`, required since conformance 0.2.0-alpha.1).
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@modelcontextprotocol/core': patch
3+
'@modelcontextprotocol/server': patch
4+
'@modelcontextprotocol/client': patch
5+
---
6+
7+
Mark the roots, sampling, and logging runtime APIs as `@deprecated` per SEP-2577 (deprecated as of protocol version 2026-07-28; functional for at least twelve months). Annotates `Server.createMessage`/`listRoots`/`sendLoggingMessage`, `McpServer.sendLoggingMessage`, `Client.setLoggingLevel`/`sendRootsListChanged`, the `ServerContext.mcpReq.log`/`requestSampling` helpers, and the `roots`/`sampling`/`logging` capability schema fields. JSDoc/docs only — no behavior change.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@modelcontextprotocol/core': patch
3+
---
4+
5+
Add reserved trace context `_meta` key constants (`TRACEPARENT_META_KEY`, `TRACESTATE_META_KEY`, `BAGGAGE_META_KEY`) per SEP-414, plus docs and a passthrough regression test. The spec reserves the unprefixed `_meta` keys `traceparent`, `tracestate`, and `baggage` (W3C Trace Context / W3C Baggage formats) for distributed tracing; the SDK passes them through untouched.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@modelcontextprotocol/core': patch
3+
'@modelcontextprotocol/client': patch
4+
'@modelcontextprotocol/server': patch
5+
---
6+
7+
Add a configurable `maxBufferSize` (default 10 MB) to the stdio transports. When a single message would push the read buffer past the limit, the transport now emits an `onerror` and closes instead of growing the buffer unbounded. Configure via `new StdioClientTransport({ ..., maxBufferSize })` or `new StdioServerTransport(stdin, stdout, { maxBufferSize })`. The default is exported from `@modelcontextprotocol/core` as `STDIO_DEFAULT_MAX_BUFFER_SIZE`.

docs/client.md

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ import {
2626
SdkError,
2727
SdkErrorCode,
2828
SSEClientTransport,
29-
StreamableHTTPClientTransport
29+
StreamableHTTPClientTransport,
30+
TRACEPARENT_META_KEY,
31+
TRACESTATE_META_KEY
3032
} from '@modelcontextprotocol/client';
3133
import { StdioClientTransport } from '@modelcontextprotocol/client/stdio';
3234
```
@@ -404,6 +406,9 @@ client.setNotificationHandler('notifications/resources/list_changed', async () =
404406
});
405407
```
406408

409+
> [!WARNING]
410+
> MCP logging (including `setLoggingLevel()` and `notifications/message`) is deprecated as of protocol version 2026-07-28 (SEP-2577). It remains fully functional during the deprecation window (at least twelve months); see the [deprecated features registry](https://modelcontextprotocol.io/specification/draft/deprecated). Servers should migrate to stderr logging (STDIO) or OpenTelemetry.
411+
407412
To control the minimum severity of log messages the server sends, use {@linkcode @modelcontextprotocol/client!client/client.Client#setLoggingLevel | setLoggingLevel()}:
408413

409414
```ts source="../examples/client/src/clientGuide.examples.ts#setLoggingLevel_basic"
@@ -431,6 +436,9 @@ const client = new Client(
431436

432437
### Sampling
433438

439+
> [!WARNING]
440+
> Sampling is deprecated as of protocol version 2026-07-28 (SEP-2577). It remains fully functional during the deprecation window (at least twelve months); see the [deprecated features registry](https://modelcontextprotocol.io/specification/draft/deprecated). Servers should migrate to calling LLM provider APIs directly.
441+
434442
When a server needs an LLM completion during tool execution, it sends a `sampling/createMessage` request to the client (see [Sampling](https://modelcontextprotocol.io/docs/learn/client-concepts#sampling) in the MCP overview). Register a handler to fulfill it:
435443

436444
```ts source="../examples/client/src/clientGuide.examples.ts#sampling_handler"
@@ -472,6 +480,9 @@ For a full form-based elicitation handler with AJV validation, see [`simpleStrea
472480

473481
### Roots
474482

483+
> [!WARNING]
484+
> Roots are deprecated as of protocol version 2026-07-28 (SEP-2577). They remain fully functional during the deprecation window (at least twelve months); see the [deprecated features registry](https://modelcontextprotocol.io/specification/draft/deprecated). Migrate to passing paths via tool parameters, resource URIs, or configuration.
485+
475486
Roots let the client expose filesystem boundaries to the server (see [Roots](https://modelcontextprotocol.io/docs/learn/client-concepts#roots) in the MCP overview). Declare the `roots` capability and register a `roots/list` handler:
476487

477488
```ts source="../examples/client/src/clientGuide.examples.ts#roots_handler"
@@ -571,6 +582,58 @@ const transport = new StreamableHTTPClientTransport(new URL('http://localhost:30
571582
});
572583
```
573584

585+
## Trace context propagation
586+
587+
The MCP specification ([SEP-414](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/414)) reserves the unprefixed `_meta` keys `traceparent`, `tracestate`, and `baggage` for distributed trace context, as an exception to the usual `_meta` key prefix rule. When present, the values must follow the [W3C Trace Context](https://www.w3.org/TR/trace-context/) and [W3C Baggage](https://www.w3.org/TR/baggage/) formats. The SDK does not interpret these keys — `_meta` passes through both directions untouched — so you can propagate OpenTelemetry context across any transport, including stdio where HTTP headers are unavailable. The key names are exported as `TRACEPARENT_META_KEY`, `TRACESTATE_META_KEY`, and `BAGGAGE_META_KEY`.
588+
589+
Attach trace context to a single request via `_meta`:
590+
591+
```ts source="../examples/client/src/clientGuide.examples.ts#traceContext_perRequest"
592+
// Values would normally come from your tracer's active span context.
593+
const result = await client.callTool({
594+
name: 'calculate-bmi',
595+
arguments: { weightKg: 70, heightM: 1.75 },
596+
_meta: {
597+
[TRACEPARENT_META_KEY]: '00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01',
598+
[TRACESTATE_META_KEY]: 'vendor1=opaqueValue1'
599+
}
600+
});
601+
console.log(result.content);
602+
```
603+
604+
Or inject it into every outgoing request with fetch middleware (Streamable HTTP transport):
605+
606+
```ts source="../examples/client/src/clientGuide.examples.ts#traceContext_middleware"
607+
const traceContextMiddleware = createMiddleware(async (next, input, init) => {
608+
if (typeof init?.body !== 'string') {
609+
return next(input, init);
610+
}
611+
const message = JSON.parse(init.body) as {
612+
method?: string;
613+
params?: { _meta?: Record<string, unknown>; [key: string]: unknown };
614+
};
615+
// Only requests and notifications carry params._meta; skip responses.
616+
if (message.method === undefined) {
617+
return next(input, init);
618+
}
619+
message.params = {
620+
...message.params,
621+
_meta: {
622+
...message.params?._meta,
623+
// Replace with values from your tracer's active span context.
624+
[TRACEPARENT_META_KEY]: '00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01'
625+
}
626+
};
627+
return next(input, { ...init, body: JSON.stringify(message) });
628+
});
629+
630+
const transport = new StreamableHTTPClientTransport(new URL('http://localhost:3000/mcp'), {
631+
fetch: applyMiddlewares(traceContextMiddleware)(fetch)
632+
});
633+
```
634+
635+
On the server side, handlers can read the incoming trace context from `ctx.mcpReq._meta` — see the [server guide](./server.md#trace-context-propagation).
636+
574637
## Resumption tokens
575638

576639
When using SSE-based streaming, the server can assign event IDs. Pass `onresumptiontoken` to track them, and `resumptionToken` to resume from where you left off after a disconnection:

docs/migration-SKILL.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,10 +503,19 @@ The 2025-11 task side-channel through `Protocol` is removed (was always `@experi
503503

504504
NOT removed (wire surface, kept for 2025-11-25 interop): task Zod schemas + inferred types (`Task`, `TaskStatus`, `TaskMetadata`, `RelatedTaskMetadata`, `CreateTaskResult`, `GetTask*`, `ListTasks*`, `CancelTask*`, `TaskStatusNotification*`, `TaskAugmentedRequestParams`), task members of the request/result/notification unions, the `tasks` capability key, `isTaskAugmentedRequestParams`, `RELATED_TASK_META_KEY`. Inbound `tasks/*` requests → `-32601`.
505505

506-
## 13. Client Behavioral Changes
506+
## 13. Behavioral Changes
507+
508+
### Client
507509

508510
`Client.listPrompts()`, `listResources()`, `listResourceTemplates()`, `listTools()` now return empty results when the server lacks the corresponding capability (instead of sending the request). Set `enforceStrictCapabilities: true` in `ClientOptions` to throw an error instead.
509511

512+
### Server (Streamable HTTP transport)
513+
514+
No code changes required; these are wire-behavior notes:
515+
516+
- Resumability behavior (SSE priming events, `closeSSEStream` / `closeStandaloneSSEStream` callbacks) is only enabled for protocol versions in the transport's supported-versions list that are `>= 2025-11-25`. Unknown future version strings in an `initialize` request body no longer enable it. Behavior for all currently supported protocol versions is unchanged.
517+
- Session-ID mismatch still responds `404 Not Found` with JSON-RPC error code `-32001` (`Session not found`), unchanged from v1. This `-32001` usage is an SDK convention, not a spec-assigned code, and may be re-derived as 2026 protocol revision error handling is adopted — migrated client code should key off the HTTP `404` status, not the `-32001` code.
518+
510519
## 14. Runtime-Specific JSON Schema Validators (Enhancement)
511520

512521
The SDK now auto-selects the appropriate JSON Schema validator based on runtime:

docs/migration.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,14 @@ app.use(hostHeaderValidation(['example.com']));
334334

335335
Note: the v2 signature takes a plain `string[]` instead of an options object.
336336

337+
### Resumability gating for unknown protocol versions (Streamable HTTP server)
338+
339+
The server-side Streamable HTTP transport enables resumability behavior introduced with protocol version `2025-11-25` — SSE priming events and the `closeSSEStream` / `closeStandaloneSSEStream` callbacks — based on the client's protocol version. Previously this was an
340+
open-ended `protocolVersion >= '2025-11-25'` comparison, so an unrecognized future version string in an `initialize` request body (which, unlike the `MCP-Protocol-Version` header, is not validated against the supported-versions list) silently enabled the behavior.
341+
342+
The check is now bounded: the version must be one of the transport's supported protocol versions (after `connect()`, the server's `supportedProtocolVersions`) **and** at least `2025-11-25`. Behavior for all currently supported protocol versions (`2024-10-07` through
343+
`2025-11-25`) is unchanged. Clients claiming an unknown future protocol version in the initialize body are now treated like clients without empty-SSE-data support: no priming event is sent and no early-close callbacks are provided.
344+
337345
### `setRequestHandler` and `setNotificationHandler` use method strings
338346

339347
The low-level `setRequestHandler` and `setNotificationHandler` methods on `Client`, `Server`, and `Protocol` now take a method string instead of a Zod schema.
@@ -1020,6 +1028,10 @@ The following APIs are unchanged between v1 and v2 (only the import paths change
10201028
- All Zod schemas and type definitions from `types.ts` (except the aliases listed above)
10211029
- Tool, prompt, and resource callback return types
10221030

1031+
**Session-ID mismatch responses**: when session management is enabled and a request carries an `Mcp-Session-Id` header that doesn't match the active session, the Streamable HTTP server transport responds `404 Not Found` with a JSON-RPC error body using code `-32001` and
1032+
message `Session not found` — unchanged from v1. Note that this use of `-32001` is an SDK convention, not a spec-assigned error code, and it is expected to be re-derived as error handling for the 2026 protocol revision (`2026-07-28`) is adopted. Avoid hard-coding the
1033+
`-32001` code in client logic; key off the HTTP `404` status instead.
1034+
10231035
## Using an LLM to migrate your code
10241036

10251037
An LLM-optimized version of this guide is available at [`docs/migration-SKILL.md`](migration-SKILL.md). It contains dense mapping tables designed for tools like Claude Code to mechanically apply all the changes described above. You can paste it into your LLM context or load it as

0 commit comments

Comments
 (0)