You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
2.**`Protocol.connect()`** routes to `_onrequest()`, `_onresponse()`, or `_onnotification()`
163
163
3.**`Protocol._onrequest()`**:
164
-
- Looks up handler in `_requestHandlers` map (keyed by method name)
165
164
- Creates `BaseContext` with `signal`, `sessionId`, `sendNotification`, `sendRequest`, etc.
166
165
- Calls `buildContext()` to let subclasses enrich the context (e.g., Server adds HTTP request info)
167
166
- Calls `dispatcher.dispatch()` which looks up the handler (keyed by method name), runs the middleware chain, invokes the handler, and wraps the result as a JSON-RPC response
- AJV (Node.js): `import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server';`
525
525
- CF Worker: `import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/server/validators/cf-worker';`
526
526
527
-
## 15. Migration Steps (apply in this order)
527
+
## 15. 2026-06 Stateless Support (SEP-2575/2567/2322)
528
+
529
+
`Server`/`Client` are the same classes (still extend `Protocol`); 2026-06 support is additive. `Client.connect()` auto-probes `server/discover` and falls back to legacy `initialize`. `setRequestHandler` is unchanged.
530
+
531
+
**Prefer `ctx.mcpReq.*` inside handlers** (works under both protocols). Inside tool/prompt/resource handler bodies where `ctx` (the handler's second argument) is in scope, replace `<expr>.server.X()` (or `server.X()` on a low-level `Server`) with `ctx.mcpReq.X()`. The `<expr>` prefix varies (`mcpServer.server`, `this.server`, just `server`), so search for `.X(` and rewrite by hand:
532
+
533
+
| Find calls to | Replace with |
534
+
| --- | --- |
535
+
|`.createMessage(`|`ctx.mcpReq.requestSampling(`|
536
+
|`.elicitInput(`|`ctx.mcpReq.elicitInput(`|
537
+
|`.listRoots(`|`ctx.mcpReq.listRoots(`|
538
+
|`.sendLoggingMessage({ level, data })`|`ctx.mcpReq.log(level, data)`|
Add `ctx` to the handler signature if not already present. For tools with an `inputSchema`: `async (args) =>` → `async (args, ctx) =>`. For tools WITHOUT an `inputSchema`: `async () =>` → `async ctx =>` (single parameter).
542
+
543
+
The top-level `server.createMessage()` etc. still work with a connected pre-2026 client; this migration is recommended but not required.
544
+
545
+
`ctx.mcpReq.requestSampling` keeps the same overload narrowing as `server.createMessage`: when `params.tools` is statically present the result type is `CreateMessageResultWithTools`; when statically absent it is `CreateMessageResult`. If `tools` is conditional at the call site, the result is the union; add a runtime `Array.isArray(result.content)` check before indexing.
546
+
547
+
MRTR via `InputRequiredError` works for handlers registered via `setRequestHandler`; `fallbackRequestHandler` is not wrapped by middleware (matches pre-existing behavior).
548
+
549
+
For tests that exercise pre-2026 connection-model behavior, construct the test client with `supportedProtocolVersions` filtered to pre-2026 versions only.
2. Replace all imports from `@modelcontextprotocol/sdk/...` using the import mapping tables (sections 3-4), including `StreamableHTTPServerTransport` → `NodeStreamableHTTPServerTransport`
@@ -536,4 +560,5 @@ Access validators explicitly:
536
560
8. If using server SSE transport, migrate to Streamable HTTP
537
561
9. If using server auth from the SDK: RS helpers (`requireBearerAuth`, `mcpAuthMetadataRouter`) → `@modelcontextprotocol/express`; AS helpers → external IdP/OAuth library
538
562
10. If relying on `listTools()`/`listPrompts()`/etc. throwing on missing capabilities, set `enforceStrictCapabilities: true`
539
-
11. Verify: build with `tsc` / run tests
563
+
11. Inside tool/prompt/resource handlers, replace `server.createMessage`/`elicitInput`/`listRoots`/`sendLoggingMessage` with `ctx.mcpReq.*` per section 15
Copy file name to clipboardExpand all lines: docs/migration.md
+36Lines changed: 36 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -874,6 +874,42 @@ There is no migration path for the removed surface; it was always `@experimental
874
874
875
875
`TaskCreationParams.ttl` (the storage-layer creation parameter) is now `number | undefined`; `null` is no longer accepted. Per the MCP spec, `null` TTL (unlimited lifetime) is only valid in server responses (`Task.ttl`), not in creation requests. Omit `ttl` to let the store decide. This is a storage-interface change and is independent of the Protocol-level removals above.
876
876
877
+
## 2026-06 Stateless Protocol Support (SEP-2575, SEP-2567, SEP-2322)
878
+
879
+
`Server` and `Client` now support the 2026-06 stateless connection model alongside the existing pre-2026 model. They remain the same classes (still extending `Protocol`); the new behavior is additive.
880
+
881
+
### What changed
882
+
883
+
-**`Client.connect()` auto-probes.** On connect, the client sends `server/discover` via the transport's `sendAndReceive` path. If the server responds, the client operates in stateless mode; typed methods (`callTool`, `listTools`, etc.) route via `sendAndReceive` and the MRTR loop. If discover fails (server doesn't support it, transport doesn't have `sendAndReceive`), the client falls back to the legacy `initialize` handshake. Existing code works unchanged.
884
+
-**`Server` gained a stateless dispatch path.**`server.statelessHandlers()` returns `{dispatch, listen}` for transports to call. `connect(transport)` wires this automatically via `transport.setStatelessHandlers?.()`. Handlers registered with `setRequestHandler` serve both paths.
885
+
-**`handleHttp(server, opts)`** is a new Fetch-API entry point: one shared `Server` instance, no `Transport`, no `connect()`. Returns `(Request) => Promise<Response>`. See `examples/server/src/honoWebStandardStreamableHttp.ts`.
886
+
-**`client.subscribe(filter)`** opens a `subscriptions/listen` stream for list-changed and resource-updated notifications (the 2026-06 replacement for unsolicited notifications and `resources/subscribe`).
887
+
-**`Transport` interface gained two optional methods:**`setStatelessHandlers?(handlers)` (server side) and `sendAndReceive?(req, opts?)` (client side). Implement these in custom transports to support 2026-06.
888
+
889
+
### Prefer `ctx.mcpReq.*` for server-to-client interactions
890
+
891
+
Inside a tool/prompt/resource handler, use `ctx.mcpReq.{elicitInput, requestSampling, listRoots, log}` instead of the top-level `server.elicitInput()` / `server.createMessage()` / `server.listRoots()` / `server.sendLoggingMessage()`. The `ctx.mcpReq.*` form works under **both** protocols: with a pre-2026 client it sends a real request; with a 2026-06 client it returns an `input_required` result and the client retries with the response embedded (SEP-2322 MRTR).
The top-level methods still exist and work when a pre-2026 client is connected. They are not removed.
902
+
903
+
MRTR via `InputRequiredError` works for handlers registered via `setRequestHandler`; `fallbackRequestHandler` is not wrapped by middleware (matches pre-existing behavior).
904
+
905
+
### Tests pinning pre-2026
906
+
907
+
If a test exercises pre-2026 connection-model behavior (e.g., `oninitialized`, server-initiated requests, in-band logging) and breaks because the auto-probe now succeeds, construct the client with `supportedProtocolVersions` filtered to pre-2026 versions only, or use a fixture like `LegacyTestClient` that does so. The probe falls back to legacy when no mutual stateless version exists.
908
+
909
+
### Shared instances
910
+
911
+
A single `Server` instance can safely serve many concurrent 2026-06 clients via `handleHttp` or a connected transport's per-message router. For pre-2026 clients, the existing per-session guidance still applies (the legacy path's `_clientCapabilities` is per-connection state).
912
+
877
913
## Enhancements
878
914
879
915
### Automatic JSON Schema validator selection by runtime
Copy file name to clipboardExpand all lines: docs/server.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -478,7 +478,7 @@ For runnable examples, see [`elicitationFormExample.ts`](https://github.com/mode
478
478
479
479
### Roots
480
480
481
-
Roots let a tool handler discover the client's workspace directories — for example, to scope a file search or identify project boundaries (see [Roots](https://modelcontextprotocol.io/docs/learn/client-concepts#roots) in the MCP overview). Call {@linkcode@modelcontextprotocol/server!server/server.Server#listRoots | server.server.listRoots()} (requires the client to declare the `roots` capability):
481
+
Roots let a tool handler discover the client's workspace directories — for example, to scope a file search or identify project boundaries (see [Roots](https://modelcontextprotocol.io/docs/learn/client-concepts#roots) in the MCP overview). Call `ctx.mcpReq.listRoots()` inside the handler (requires the client to declare the `roots` capability). This works under both the pre-2026 connection model and the 2026 stateless model:
| Streamable HTTP server (stateful) | Feature-rich server with tools/resources/prompts, logging, sampling, and optional OAuth. |[`src/simpleStreamableHttp.ts`](src/simpleStreamableHttp.ts)|
31
-
| Streamable HTTP server (stateless) |No session tracking; good for simple API-style servers. |[`src/simpleStatelessStreamableHttp.ts`](src/simpleStatelessStreamableHttp.ts)|
31
+
| Streamable HTTP server (stateless) |Shared instance for 2026-06 clients. Pre-2026 clients need per-session (see stateful row).|[`src/simpleStatelessStreamableHttp.ts`](src/simpleStatelessStreamableHttp.ts)|
32
32
| Resource-Server-only auth | Minimal OAuth RS using SDK's `mcpAuthMetadataRouter` + `requireBearerAuth` (no better-auth). |[`src/resourceServerOnly.ts`](src/resourceServerOnly.ts)|
33
33
| JSON response mode (no SSE) | Streamable HTTP with JSON-only responses and limited notifications. |[`src/jsonResponseStreamableHttp.ts`](src/jsonResponseStreamableHttp.ts)|
34
34
| Server notifications over Streamable HTTP | Demonstrates server-initiated notifications via GET+SSE. |[`src/standaloneSseWithGetStreamableHttp.ts`](src/standaloneSseWithGetStreamableHttp.ts)|
35
35
| Output schema server | Demonstrates tool output validation with structured output schemas. |[`src/mcpServerOutputSchema.ts`](src/mcpServerOutputSchema.ts)|
36
36
| Form elicitation server | Collects **non-sensitive** user input via schema-driven forms. |[`src/elicitationFormExample.ts`](src/elicitationFormExample.ts)|
37
37
| URL elicitation server | Secure browser-based flows for **sensitive** input (API keys, OAuth, payments). |[`src/elicitationUrlExample.ts`](src/elicitationUrlExample.ts)|
38
38
| Sampling server | Demonstrates server-initiated sampling requests. |[`src/toolWithSampleServer.ts`](src/toolWithSampleServer.ts)|
39
-
| Hono Streamable HTTP server | Streamable HTTP server built with Hono instead of Express. |[`src/honoWebStandardStreamableHttp.ts`](src/honoWebStandardStreamableHttp.ts)|
39
+
| Hono `handleHttp`server (2026-06)| Headline 2026-06 stateless entry: `handleHttp()` Fetch handler, no Transport, no connect().|[`src/honoWebStandardStreamableHttp.ts`](src/honoWebStandardStreamableHttp.ts)|
40
40
| SSE polling demo server | Legacy SSE server intended for polling demos. |[`src/ssePollingExample.ts`](src/ssePollingExample.ts)|
0 commit comments