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
Say 2025-11-25 where the docs said handshake-era, and three review fixes
Four review follow-ups, none of them behaviour changes to the task path itself.
Three sentences claimed a `CreateTaskResult` answers a task-augmented call on a
"handshake-era connection". That term means all four pre-2026 revisions
(`HANDSHAKE_PROTOCOL_VERSIONS`), and only 2025-11-25 defines the shape, so the
section contradicted its own recipe, which already gates on
`ctx.protocol_version`. The earlier revisions still hand `params.task` to the
handler, so a server author testing against 2025-06-18, which is what most
deployed clients negotiate, would have followed the prose into an opaque
internal error. All three now say 2025-11-25 and name why the others reject it.
The tasks capability recipe only worked over stdio. It built an
`InitializationOptions` to pass to `Server.run()`, but the streamable HTTP
manager and the SSE app call `create_initialization_options()` themselves and
take no override, so on the SDK's primary transport there was nowhere to put it.
Overriding that method instead reaches every transport and is the same length.
`_is_excluded` replaces a membership test that could not tell pydantic's
`{"field": True}` (drop the field) from `{"field": {"subkey"}}` (keep the field,
descend into it), so a required nullable field was left out of a dump that
pydantic had kept it in, producing a body that fails its own schema. The two
now agree on every include/exclude shape, which a test pins.
`ServerResult`'s docstring claimed to be every result payload a server can
return. It never was: the five 2025-11-25 task results are all absent, four of
them producible today through `add_request_handler`, and the 2025-11-25 schema's
own `ServerResult` omits them too. The docstring now records the exclusion the
way the sibling unions already do, rather than the union growing one arbitrary
arm of the five.
Copy file name to clipboardExpand all lines: docs/advanced/low-level-server.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -185,7 +185,7 @@ The handshake belongs to the runner. `server/discover`, `ping`, and every other
185
185
Each of these is one idea you now have the vocabulary for; each has its own page.
186
186
187
187
*`on_call_tool`, `on_get_prompt`, and `on_read_resource` may return an `InputRequiredResult` instead of their normal result to pause the call and ask the client for input; see **[Multi-round-trip requests](../handlers/multi-round-trip.md)**. True to this tier, nothing is installed for you: where `MCPServer` seals `requestState` by default, here the `request_state` you set crosses the wire exactly as written until you opt in with `server.middleware.append(RequestStateBoundary(RequestStateSecurity(keys=[...]), default_audience=server.name))`: one line (both names import from `mcp.server.request_state`) for the identical sealing and verification `MCPServer` performs (**[Protecting `requestState`](../handlers/multi-round-trip.md#protecting-requeststate)**).
188
-
*`on_call_tool` may also return a `CreateTaskResult` to answer a task-augmented call on a handshake-era connection, which is the one piece of SEP-1686 the SDK still carries; the store and the `tasks/*` handlers are yours to bring, and the 2026-07-28 revision rejects the shape because tasks left its core protocol. See **[Experimental Tasks runtime removed](../migration.md#experimental-tasks-runtime-removed)**.
188
+
*`on_call_tool` may also return a `CreateTaskResult` to answer a task-augmented call on a 2025-11-25 connection, which is the one piece of SEP-1686 the SDK still carries; the store and the `tasks/*` handlers are yours to bring, and every other revision rejects the shape, the earlier ones because they never defined it and 2026-07-28 because tasks left its core protocol. See **[Experimental Tasks runtime removed](../migration.md#experimental-tasks-runtime-removed)**.
189
189
*`on_list_resources`, `on_read_resource`, `on_list_prompts`, `on_get_prompt`, `on_completion` are the same `(ctx, params) -> result` shape for the other primitives.
190
190
*`on_subscriptions_listen` serves the 2026-07-28 `subscriptions/listen` stream. Pass a `ListenHandler` built over a `SubscriptionBus` and publish events to the bus from your other handlers; see **[Subscriptions](../handlers/subscriptions.md)** for the full composition.
191
191
*`server.streamable_http_app()` returns the same Starlette app `MCPServer`'s does; deploy it the way **[Running your server](../run/index.md)** deploys any other ASGI app. There is no `server.run(transport=...)` down here: `server.run(read_stream, write_stream, server.create_initialization_options())` drives one connection over a pair of streams, and that one line is the whole story.
Copy file name to clipboardExpand all lines: docs/migration.md
+15-18Lines changed: 15 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1657,7 +1657,7 @@ Behavior changes:
1657
1657
1658
1658
The task runtime that shipped behind the `experimental` properties is gone. The `mcp.client.experimental`, `mcp.server.experimental`, `mcp.shared.experimental`, and `mcp.server.lowlevel.experimental` modules have been removed, along with the `experimental` properties on `ClientSession`, `ServerSession`, `Server`, and `ServerRequestContext`. There is no built-in task store, no polling helper, and no automatic `tasks/*` routing. The `TaskExecutionMode` alias is also gone; its literal is inlined on `ToolExecution.task_support`.
1659
1659
1660
-
The task types stay, so a server can still serve Tasks ([SEP-1686](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1686)) on a handshake-era connection by supplying the parts the runtime used to provide. This covers the server side of a task-augmented `tools/call`; the client side of a task-augmented `sampling/createMessage` or `elicitation/create` is not wired, so a client cannot answer one of those with a `CreateTaskResult`. A task-augmented `tools/call` arrives with `params.task` set and may be answered with a `CreateTaskResult`, and the `tasks/get`, `tasks/result`, `tasks/list`, and `tasks/cancel` methods are registered with `Server.add_request_handler`.
1660
+
The task types stay, so a server can still serve Tasks ([SEP-1686](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1686)) on a 2025-11-25 connection by supplying the parts the runtime used to provide. 2025-11-25 is the only revision that defines them: the earlier handshake revisions predate SEP-1686, so a `CreateTaskResult` there is rejected as an internal error even though `params.task` reaches the handler. This covers the server side of a task-augmented `tools/call`; the client side of a task-augmented `sampling/createMessage` or `elicitation/create` is not wired, so a client cannot answer one of those with a `CreateTaskResult`. A task-augmented `tools/call` arrives with `params.task` set and may be answered with a `CreateTaskResult`, and the `tasks/get`, `tasks/result`, `tasks/list`, and `tasks/cancel` methods are registered with `Server.add_request_handler`.
1661
1661
1662
1662
```python
1663
1663
asyncdefcall_tool(
@@ -1680,23 +1680,20 @@ Two things to know about handlers registered this way. They serve every negotiat
1680
1680
1681
1681
The same era check belongs in `on_call_tool`, and `params.task` is not a substitute for it. The handler receives the version-free params model, which carries `task` at every version, so a client can set the field on a 2026-07-28 connection and reach a handler that then answers with a `CreateTaskResult`, which that revision rejects as an opaque internal error. Gate on `ctx.protocol_version == "2025-11-25"` and treat `params.task` as the opt-in within that era, not as the era test.
1682
1682
1683
-
`Server.get_capabilities` does not derive a `tasks` capability from the registered handlers, and a spec-compliant client will not augment a request until it sees one, so build the advertisement explicitly:
`Server.get_capabilities` does not derive a `tasks` capability from the registered handlers, and a spec-compliant client will not augment a request until it sees one, so add the advertisement by overriding `create_initialization_options`. Override rather than building an `InitializationOptions` and passing it in: `streamable_http_app()` and the SSE app call the method themselves and take no override, so only the subclass reaches every transport.
A client sends the augmented request and names the result type through `ClientSession.send_request`, since `call_tool` resolves to the two core result arms:
Copy file name to clipboardExpand all lines: docs/whats-new.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -145,7 +145,7 @@ The renames announce themselves. These do not:
145
145
Each of these is a section in the **[Migration Guide](migration.md)**:
146
146
147
147
* The **WebSocket transport**, both sides, and the `mcp[ws]` extra. It was never part of the MCP specification.
148
-
* The **experimental Tasks** runtime (`mcp.*.experimental`): the task store, the polling helper, and the automatic `tasks/*` routing. The task types stay, so a server can still answer a task-augmented `tools/call` on a handshake-era connection by bringing its own store; 2026-07-28 moves tasks out of the core protocol into an official extension ([SEP-2663](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2663)), which this SDK does not implement yet.
148
+
* The **experimental Tasks** runtime (`mcp.*.experimental`): the task store, the polling helper, and the automatic `tasks/*` routing. The task types stay, so a server can still answer a task-augmented `tools/call` on a 2025-11-25 connection by bringing its own store; 2026-07-28 moves tasks out of the core protocol into an official extension ([SEP-2663](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2663)), which this SDK does not implement yet.
149
149
*`mcp.types`, `mcp.shared.version`, and `mcp.shared.progress` as import paths.
150
150
* The deprecated `streamablehttp_client` spelling, and the `get_session_id` callback from `streamable_http_client` (which now yields exactly two streams).
151
151
*`McpError`, renamed **`MCPError`** with a direct `(code, message, data)` constructor.
0 commit comments