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
Tighten the public API surface: root exports, listen types, dead-code removal
Root `mcp` package: export `MCPServer` (alongside the existing `Client`,
so `from mcp import MCPServer, Client` works) and `NoBackChannelError`;
drop the v1-carryover `SamplingRole` alias (`mcp.types.Role`). `mcp.client`
now re-exports the types `Client.listen()` yields and raises: `Subscription`,
`SubscriptionLost`, `ListenNotSupportedError`.
Remove dead surface: `StreamableHTTPError`/`ResumptionError` (never raised
from a reachable path) and `StreamableHTTPTransport.get_session_id()` on the
client transport; the no-op `RegistrationRequest`/`TokenSuccessResponse`
auth-handler aliases; the `validate_extension_identifier` re-export alias;
the unreachable `__main__` guard in `mcp/cli/__init__.py`. The unused
lowlevel server `Context` moves to the private `mcp.server._context`
module.
`_handle_resumption_request` now takes the resumption token as a required
argument instead of re-deriving it and carrying an unreachable no-token
branch.
Enable ruff `RUF022` and sort every `__all__`; `mcp_types/__init__.py` is
exempted since its `__all__` is grouped by section comments on purpose.
Copy file name to clipboardExpand all lines: docs/get-started/first-steps.md
-4Lines changed: 0 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -46,10 +46,6 @@ Three plain functions, three decorators. Each decorator is the entire registrati
46
46
47
47
Everything else (the name, the description, the argument schema) the SDK reads from the function itself: its name, its docstring, its type hints. You never declared any of it separately.
48
48
49
-
!!! tip
50
-
The two halves of the SDK have two import paths: `from mcp import Client` and
51
-
`from mcp.server import MCPServer`. There is no `from mcp import MCPServer`.
Copy file name to clipboardExpand all lines: docs/migration.md
+11-2Lines changed: 11 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -265,6 +265,7 @@ The following type aliases and classes have been removed from the protocol types
265
265
|`AnyFunction`| Use `Callable[..., Any]` directly |
266
266
|`ClientRequestType`, `ClientNotificationType`, `ClientResultType`, `ServerRequestType`, `ServerNotificationType`, `ServerResultType`| The union is now the bare name: `ClientRequest`, `ClientNotification`, `ClientResult`, `ServerRequest`, `ServerNotification`, `ServerResult`|
267
267
|`TaskExecutionMode`, `TASK_FORBIDDEN`, `TASK_OPTIONAL`, `TASK_REQUIRED`, `TASK_STATUS_*`| Use string literals; `TaskStatus` remains as the literal-union type |
268
+
|`SamplingRole` (a top-level `mcp` alias for `Role`, never a `mcp.types` name) |`mcp.types.Role`|
268
269
269
270
**Before (v1):**
270
271
@@ -657,6 +658,8 @@ from mcp.server.mcpserver import MCPServer, Context
657
658
mcp = MCPServer("Demo")
658
659
```
659
660
661
+
`MCPServer` is also exported from the top-level `mcp` package, next to `Client` (`from mcp import MCPServer, Client`); `mcp.server` and `mcp.server.mcpserver` keep working as import paths.
662
+
660
663
`Context` is the type annotation for the `ctx` parameter injected into tools, resources, and prompts (see [`get_context()` removed](#mcpserverget_context-removed) below). The `ctx.fastmcp` property is now `ctx.mcp_server`.
661
664
662
665
All submodules under `mcp.server.fastmcp.*` are now under `mcp.server.mcpserver.*` with the same structure. Common imports:
@@ -2166,6 +2169,12 @@ The `headers`, `timeout`, `sse_read_timeout`, and `auth` parameters have been re
2166
2169
2167
2170
`sse_client` is unchanged apart from the `httpx2` retyping: it still takes `url`, `headers`, `timeout`, `sse_read_timeout`, `httpx_client_factory` (which must now return an `httpx2.AsyncClient`), `auth` (now `httpx2.Auth | None`), and `on_session_created`. Only the streamable HTTP transport dropped its transport-level parameters; `StreamableHTTPTransport(url)` now takes just the URL.
2168
2171
2172
+
### `StreamableHTTPError`, `ResumptionError`, and `StreamableHTTPTransport.get_session_id()` removed
2173
+
2174
+
`mcp.client.streamable_http` no longer defines `StreamableHTTPError` or its `ResumptionError` subclass: the transport never raised either from a code path a caller could catch, so `from mcp.client.streamable_http import StreamableHTTPError, ResumptionError` now raises `ImportError`. Transport failures surface as per-request JSON-RPC errors (see [Streamable HTTP: non-2xx responses now surface as per-request JSON-RPC errors](#streamable-http-non-2xx-responses-now-surface-as-per-request-json-rpc-errors)) or as the underlying `httpx2` exception; catch those instead.
2175
+
2176
+
The unused `StreamableHTTPTransport.get_session_id()` method is gone as well; read the `session_id` attribute directly (or capture the header, as in [`get_session_id` callback removed](#get_session_id-callback-removed-from-streamable_http_client) above).
The transport no longer holds per-connection protocol state; era-dependent headers (e.g. `MCP-Protocol-Version`) are now supplied per-message by the session. If you were reading `transport.protocol_version` to learn the negotiated version, read `session.protocol_version` (or `client.protocol_version` on the high-level `Client`) instead.
@@ -2771,7 +2780,7 @@ The user-facing methods for these features now carry `typing_extensions.deprecat
- Logging: `ServerSession.send_log_message()`, `Connection.log()`, `ClientSession.set_logging_level()`, `Client.set_logging_level()`, `mcp.server.context.Context.log()` (the lowlevel `Context`), and the `MCPServer``Context` helpers `log()`, `debug()`, `info()`, `warning()`, `error()`
2783
+
- Logging: `ServerSession.send_log_message()`, `Connection.log()`, `ClientSession.set_logging_level()`, `Client.set_logging_level()`, and the `MCPServer``Context` helpers `log()`, `debug()`, `info()`, `warning()`, `error()`
2775
2784
2776
2785
Registering a handler for a deprecated capability is deprecated too. The `Server.__init__` parameters `on_set_logging_level` (Logging) and `on_roots_list_changed` (Roots) are now split out into a `typing_extensions.deprecated` overload, so passing either is flagged by type checkers and emits `mcp.MCPDeprecationWarning` at construction time. `on_progress` follows the same pattern (see below). The non-deprecated overload omits these parameters, so the common case stays warning-free.
2777
2786
@@ -2804,7 +2813,7 @@ rest of this guide stays focused on the v1-to-v2 upgrade itself.
2804
2813
2805
2814
The 2026-07-28 protocol has no server-initiated requests, so a handler that reaches back to the client mid-request — `ctx.elicit()`, `ctx.elicit_url()`, `ctx.session.create_message()`, `ctx.session.list_roots()`, or any other `ServerSession` request helper — raises `NoBackChannelError` on such a connection instead of sending. An in-process `Client(server)` negotiates 2026-07-28 by default (see [`Client` defaults to `mode='auto'`](#client-defaults-to-modeauto)), so the first smoke test of an unchanged v1 sampling or elicitation tool fails, and setting `sampling_callback=` / `elicitation_callback=` on the client changes nothing because no request ever reaches the client.
2806
2815
2807
-
`NoBackChannelError` lives in `mcp.shared.exceptions` and subclasses `MCPError` (code `-32600`, message `Cannot send '<method>': this transport context has no back-channel for server-initiated requests.`). Raised inside an `@mcp.tool()` it reaches the client as a top-level JSON-RPC error, not `CallToolResult(is_error=True)` — see [`MCPError` raised from an `@mcp.tool()` handler now surfaces as a JSON-RPC error](#mcperror-raised-from-an-mcptool-handler-now-surfaces-as-a-json-rpc-error) — and the [Troubleshooting](troubleshooting.md) page walks through the client-side traceback. The same exception is raised on a legacy session against a `stateless_http=True` server, and on the request-scoped channel of a stateful legacy session against a `json_response=True` server (a JSON body carries exactly one response, so a mid-request `ctx.elicit()` cannot ride it; the session's standalone `GET` stream still carries unrelated messages) — both places v1 dropped the message and stalled ([`Server.run()` no longer takes a `stateless` flag](#serverrun-no-longer-takes-a-stateless-flag)). Notifications never raise it: `send_log_message()`, `send_tool_list_changed()`, and the other notification helpers are dropped with a debug log where no channel exists, and `UrlElicitationRequiredError` from a tool is unaffected (it is an error response, not a request).
2816
+
`NoBackChannelError` is exported from the top-level `mcp` package (`from mcp import NoBackChannelError`; it lives in `mcp.shared.exceptions`) and subclasses `MCPError` (code `-32600`, message `Cannot send '<method>': this transport context has no back-channel for server-initiated requests.`). Raised inside an `@mcp.tool()` it reaches the client as a top-level JSON-RPC error, not `CallToolResult(is_error=True)` — see [`MCPError` raised from an `@mcp.tool()` handler now surfaces as a JSON-RPC error](#mcperror-raised-from-an-mcptool-handler-now-surfaces-as-a-json-rpc-error) — and the [Troubleshooting](troubleshooting.md) page walks through the client-side traceback. The same exception is raised on a legacy session against a `stateless_http=True` server, and on the request-scoped channel of a stateful legacy session against a `json_response=True` server (a JSON body carries exactly one response, so a mid-request `ctx.elicit()` cannot ride it; the session's standalone `GET` stream still carries unrelated messages) — both places v1 dropped the message and stalled ([`Server.run()` no longer takes a `stateless` flag](#serverrun-no-longer-takes-a-stateless-flag)). Notifications never raise it: `send_log_message()`, `send_tool_list_changed()`, and the other notification helpers are dropped with a debug log where no channel exists, and `UrlElicitationRequiredError` from a tool is unaffected (it is an error response, not a request).
Copy file name to clipboardExpand all lines: docs/whats-new.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -24,6 +24,8 @@ from mcp.server import MCPServer # v1: from mcp.server.fastmcp import FastMCP
24
24
mcp = MCPServer("Demo") # v1: FastMCP("Demo")
25
25
```
26
26
27
+
Both halves of the SDK are also on the top-level package, so `from mcp import MCPServer, Client` works.
28
+
27
29
It is also, for a decorator-built server, most of the port. `@mcp.tool()`, `@mcp.resource()`, and `@mcp.prompt()` accept what they accepted in v1 (`@mcp.resource()` adds one optional `security=` keyword), and the input schema still comes from your type hints. Around the edges: everything under `mcp.server.fastmcp.*` now lives under `mcp.server.mcpserver.*`, `ctx.fastmcp` is `ctx.mcp_server`, `get_context()` is gone (declare a `ctx: Context` parameter instead), and the exception base `FastMCPError` is `MCPServerError`. The **[Migration Guide](migration.md#fastmcp-renamed-to-mcpserver)** has the import table.
28
30
29
31
### `Resolve`: the new way to ask the user for input
0 commit comments