MCP Python SDK v2.0.0a3

v2.0.0a3Pre-release
Added 7
  • Add ClientSession.discover() and ClientSession.adopt() methods alongside initialize()
  • Add Client mode parameter supporting 'legacy', 'auto', or specific version strings
  • Add Client prior_discover parameter
  • Add modern_on_request in-process driver for stateless path against in-memory servers
  • Extract protocol types into standalone mcp-types package with only pydantic and typing-extensions dependencies
  • Add subscriptions/listen handler slot
  • Add OpenTelemetryMiddleware that spans requests and notifications with OpenTelemetry GenAI semantic-convention attributes
Changed 10
  • Update LATEST_PROTOCOL_VERSION to 2026-07-28
  • Replace stateless bool flag with negotiable end-to-end protocol support via Connection object with from_envelope and for_loop factories
  • Refactor ServerRunner into pure handler kernel composed by three drivers: serve_one, serve_connection, and serve_loop
  • Add Connection object to own per-peer state with protocol_version always set
  • Make streamable-HTTP transport version-agnostic with per-message headers via CallOptions
  • Widen Server on_* return types to admit InputRequiredResult
Removed 2
  • Remove mcp.types module; import from mcp_types instead
  • Remove mcp.shared.version module; import from mcp_types.version instead
Deprecated 2
  • Deprecate SUPPORTED_PROTOCOL_VERSIONS in favour of HANDSHAKE_PROTOCOL_VERSIONS and MODERN_PROTOCOL_VERSIONS
  • Mark user-facing methods for roots, sampling, and logging/setLevel as deprecated per SEP-2577

Third v2 alpha. Pre-releases are opt-in only; pip install mcp still resolves to the stable 1.x line.

pip install mcp==2.0.0a3
# or
uv add "mcp==2.0.0a3"

See the migration guide for the full list of breaking changes.

Warning

The public API is likely to change between alpha releases, and ideally less-so between beta releases.

Highlights
2026-07-28 stateless protocol is now negotiable end to end (#2928, #2950)

The 2026-07-28 spec revision drops the initialize handshake on streamable HTTP: each POST is self-describing (protocol version, client info, and capabilities ride in params._meta) and the server replies with a single JSON-RPC response. Both sides of that path are now wired up.

Server side: ServerRunner is now a pure handler kernel composed by three drivers (serve_one, serve_connection, serve_loop). A new Connection object owns per-peer state with two factories - from_envelope for the per-request stateless path and for_loop for handshake-driven connections - so protocol_version is always set and the old stateless: bool flag is gone from ServerRunner, ServerSession, and Server.run(). The streamable-HTTP session manager routes by header: known handshake versions go to the legacy transport; everything else hits a new per-POST entry that classifies, builds a Connection.from_envelope, and drives serve_one. server/discover is auto-derived from registered handlers, and lifespan is entered once at manager startup in both modes.

Client side: ClientSession gains .discover() and .adopt() alongside .initialize(), each of which installs an outbound stamp closure at connect time so the send path has no era branch. Client gains mode='legacy'|'auto'|<version> and prior_discover=; mode='auto' probes server/discover and falls back to initialize on -32601 or timeout. The streamable-HTTP transport is now version-agnostic (per-message headers arrive via CallOptions), and an in-process modern_on_request driver lets Client(server, mode='auto') run the stateless path against an in-memory server.

LATEST_PROTOCOL_VERSION is now "2026-07-28". SUPPORTED_PROTOCOL_VERSIONS is deprecated in favour of HANDSHAKE_PROTOCOL_VERSIONS and MODERN_PROTOCOL_VERSIONS.

Protocol types split into a standalone mcp-types package (#2973)

The wire types now ship as a separate mcp-types distribution (imported as mcp_types) that depends only on pydantic and typing-extensions. Tooling and lightweight clients can serialize and validate MCP traffic without pulling in httpx, starlette, uvicorn, or the rest of the transport stack.

mcp.types and mcp.shared.version are removed; import from mcp_types and mcp_types.version instead. The top-level from mcp import Tool re-exports are unchanged. The two packages are version-locked and published together from the same tag.

Multi-round tool calls: InputRequiredResult plumbed through both sides (#2967, #2968, #2974)

The lowlevel Server on_* return types are widened to admit InputRequiredResult, and a subscriptions/listen handler slot is added. On the client, ClientSession.call_tool gains input_responses= and request_state= retry kwargs and returns CallToolResult | InputRequiredResult; Client.call_tool and ClientSessionGroup.call_tool are overloaded on a new allow_input_required flag so existing callers keep their CallToolResult return type. ClientSession.send_request now accepts a TypeAdapter for union result parsing.

ServerMiddleware reshaped to (ctx, call_next) and OpenTelemetryMiddleware added (#2941, #2970)

ServerMiddleware.__call__ goes from (ctx, method, params, call_next) to (ctx, call_next); method and raw params now live on ServerRequestContext, and call_next(ctx) lets middleware rewrite the inbound message via replace(ctx, params=...) before the handler runs. A new context-tier OpenTelemetryMiddleware spans both requests and notifications and sets the OpenTelemetry GenAI semantic-convention attributes.

OAuth client conformance: RFC 9207, SEP-837, SEP-2350, SEP-2352 (#2921, #2930, #2931, #2933)

The OAuth client now validates the iss authorization-response parameter (RFC 9207), sends application_type during Dynamic Client Registration (SEP-837), unions previously requested scopes on step-up re-authorization (SEP-2350), and binds client credentials to the authorization server that issued them (SEP-2352). #2936 and #2946 harden the edge cases (refresh-token retention on non-rotating refresh, same-origin issuer binding).

Roots, sampling, and logging methods deprecated per SEP-2577 (#2926)

The user-facing methods for roots, sampling, and logging/setLevel are now marked with typing_extensions.deprecated. The deprecation is advisory only - capability negotiation and wire behaviour are unchanged, and everything keeps working for sessions negotiating 2025-11-25 or earlier.

What's Changed
New Contributors

Full Changelog: https://github.com/modelcontextprotocol/python-sdk/compare/v2.0.0a2...v2.0.0a3

View original

Upgraded? How did it go?

Discussion