Releases: modelcontextprotocol/python-sdk
v2.0.0a3
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
- Pass a list to parametrize in test_docs_examples (pytest 9.1.0 compat) by @maxisbey in #2890
- docs: add AI-assisted contribution policy to CONTRIBUTING.md by @maxisbey in #2887
- Resolve protocol version per request and expose it as ctx.protocol_version by @maxisbey in #2886
- tests/interaction: era-axis machinery for the requirements manifest by @maxisbey in #2909
- ci(conformance): add 2026-07-28 carried-forward leg + bump harness to 0.2.0-alpha.4 by @maxisbey in #2911
- Re-vendor 2026-07-28 schema and absorb spec #2907 error-code renumber by @maxisbey in #2912
- Relax monolith ElicitRequestURLParams.elicitation_id for 2026-07-28 by @maxisbey in #2913
- First end-to-end 2026-07-28 stateless tools/call (experimental entry + ClientSession pin) by @maxisbey in #2917
- Add uv ecosystem to dependabot and drop weekly lockfile workflow by @Kludex in #2919
- Return -32602 for resource not found (SEP-2164) by @Kludex in #2920
- fix: correct MCPServer call_tool result type by @fengjikui in #2816
- Ignore pre-2026 protocol_version pins at the StreamableHTTP transport by @maxisbey in #2923
- Preserve empty URL paths on OAuth metadata models by @Kludex in #2925
- Validate the
issauthorization-response parameter (RFC 9207 / SEP-2468) by @Kludex in #2921 - ci(conformance): bump harness to 0.2.0-alpha.5 preview by @maxisbey in #2927
- Document
redirect_uriwire-format change in OAuth migration note by @Kludex in #2929 - Send
application_typeduring Dynamic Client Registration (SEP-837) by @Kludex in #2930 - Pass json-schema-ref-no-deref conformance scenario (SEP-2106) by @Kludex in #2924
- Deprecate roots, sampling, and logging methods per SEP-2577 by @Kludex in #2926
- Union previously requested scopes on step-up re-authorization (SEP-2350) by @Kludex in #2931
- Move scope step-up test to top-level function by @Kludex in #2932
- Bind client credentials to their authorization server (SEP-2352) by @Kludex in #2933
- Server-side 2026-07-28 stateless support: classifier, driver split, server/discover by @maxisbey in #2928
- OAuth client: harden SEP-2352/SEP-2350 edge cases; fix conformance comment by @maxisbey in #2936
- Slim ServerMiddleware to
(ctx, call_next)and addOpenTelemetryMiddlewareby @Kludex in #2941 - OAuth client: keep refresh_token on non-rotating refresh; restore same-origin issuer binding by @maxisbey in #2946
- Buffer per-request StreamableHTTP streams to avoid serial-router head-of-line block by @maxisbey in #2934
- lowlevel Server: widen on_* return types for InputRequiredResult; add subscriptions/listen slot by @maxisbey in #2967
- Client-side 2026-07-28 support: .discover()/.adopt() + Client(mode=); request-metadata green by @maxisbey in #2950
- Add GenAI semantic-convention attributes to OpenTelemetryMiddleware by @Kludex in #2970
- Stop flagging snake_case is_error results as tool errors in OTel span by @Kludex in #2971
- Client call_tool: input_responses/request_state retry params; InputRequiredResult via allow_input_required by @maxisbey in #2968
- Split protocol types into a standalone
mcp-typespa...
v2.0.0a2
Second v2 alpha. Pre-releases are opt-in only; pip install mcp still resolves to the stable 1.x line.
pip install mcp==2.0.0a2
# or
uv add "mcp==2.0.0a2"See the migration guide for the full list of breaking changes.
Highlights
Full 2026-07-28 types added along with per-version protocol types and version-gated wire validation (#2849)
The SDK now ships three type sets:
mcp.types- the hand-maintained superset monolith. This remains the public API you import from; it covers every field from every supported spec version.mcp.types.v2025_11_25- generated verbatim from the 2025-11-25 schema (also serves earlier versions).mcp.types.v2026_07_28- generated verbatim from the 2026-07-28 schema.
The generated per-version packages are wired into both ServerRunner and ClientSession via mcp.types.methods, which maps each (method, version) pair to its request/result/notification types. At runtime, the negotiated protocol version selects which generated set is used to validate traffic on the wire:
- Inbound requests and notifications are validated against the negotiated version's types. A spec method that does not exist at that version returns
METHOD_NOT_FOUND; a malformed payload returnsINVALID_PARAMS. - Inbound results (in both directions) are validated against the negotiated version's result type before being parsed into the monolith type.
- Outbound results are serialized through the negotiated version's type, so fields that only exist in a newer spec version are stripped before they reach an older peer.
User code keeps working with the monolith mcp.types; the per-version packages are an internal validation layer. 2026-07-28 is modeled but not yet negotiable - SUPPORTED_PROTOCOL_VERSIONS is unchanged in this alpha.
This makes validation stricter than a1: handlers that returned spec-invalid output (for example Tool(inputSchema={}) without "type": "object") now fail with INTERNAL_ERROR, and clients now reject spec-invalid server output that was previously tolerated.
ClientSession now runs on the dispatcher (#2838)
ClientSession has been rewritten to sit on the same JSONRPCDispatcher receive path that ServerRunner adopted in a1, and BaseSession is removed. The public surface (constructor, typed request methods, initialize(), context-manager lifecycle) is unchanged, but the internals fix several long-standing v1 issues:
- Server-initiated requests (sampling, elicitation, roots) now run concurrently instead of inline in the receive loop, so a slow callback no longer blocks the whole session and a callback that itself sends a request no longer deadlocks.
- A raising notification or request callback is contained at the dispatcher and no longer takes down the connection.
- Timed-out or caller-cancelled requests now send
notifications/cancelledto the peer. - Server-to-client cancellation now actually interrupts the running client callback.
A new keyword-only dispatcher= constructor argument lets you pass a pre-built dispatcher (for example DirectDispatcher for in-process embedding) instead of the read/write stream pair.
What's Changed
- Fix unknown-method error code and add a protocol version registry by @maxisbey in #2836
- Flush the stdio subprocess's coverage data before the clean-exit line by @maxisbey in #2840
- Fix 404 links in v1 README to renamed example files by @jerome3o-anthropic in #2822
- [v2] ClientSession runs on JSONRPCDispatcher; BaseSession removed by @maxisbey in #2838
- ci(conformance): pin harness to 0.2.0-alpha.3 with expected-failures baseline by @maxisbey in #2877
- ci(conformance): run server --suite draft and baseline the 2026-07-28 scenarios by @maxisbey in #2878
- Deflake the issue-1363 tests: wait for lifespan startup instead of sleeping by @maxisbey in #2879
- Widen the stdio round-trip test's termination grace and overall timeout by @maxisbey in #2880
- chore(deps): bump the github-actions group across 1 directory with 9 updates by @dependabot[bot] in #2636
- Protocol types for 2026-07-28: superset monolith, committed per-version packages, and wire-method maps by @maxisbey in #2849
- Expand site-absolute spec links in generated docstrings to full URLs by @maxisbey in #2885
- Drop stale superset-leniency note from ElicitResult.content docstring by @maxisbey in #2884
Full Changelog: v2.0.0a1...v2.0.0a2
v1.28.0
Deprecations
Two API surfaces now emit DeprecationWarning ahead of their removal in v2. Nothing is removed in 1.x, and the warnings fire only when the deprecated API is called - importing the modules stays silent.
- WebSocket transport -
mcp.client.websocket.websocket_clientandmcp.server.websocket.websocket_server. WebSocket was never part of the MCP specification; use the streamable HTTP transport instead. The TypeScript SDK has likewise removed its WebSocket client for v2 (modelcontextprotocol/typescript-sdk#1783). - Experimental tasks API -
ClientSession.experimental,Server.experimental,ServerSession.experimental, and theexperimental_task_handlers=kwarg onClientSession. Tasks (SEP-1686) were removed from the MCP specification and are expected to return as a separate MCP extension.
If your test suite runs with filterwarnings = ["error"] and exercises these paths, add a scoped ignore such as ignore:The experimental tasks API is deprecated:DeprecationWarning or ignore:The WebSocket .* transport is deprecated:DeprecationWarning.
See #2828 for full details.
What's Changed
- [v1.x] Support Python 3.14 by @maxisbey in #2769
- fix: omit null optional fields from task result payloads by @liuzemei in #2809
- [v1.x] Deprecate the WebSocket transport and the experimental tasks entry points by @maxisbey in #2828
- [v1.x] Add a v2 status banner to the README by @maxisbey in #2835
- [v1.x] Deflake the child process cleanup tests by @maxisbey in #2839
New Contributors
Full Changelog: v1.27.2...v1.28.0
v2.0.0a1
First V2 Alpha Release
This is the first alpha of v2 of the MCP Python SDK.
Publishing this alpha changes nothing for existing users. Installers don't pick up pre-releases unless you explicitly opt in, so if you do nothing you stay on v1.x.
Why v2
The upcoming MCP spec release (2026-07-28) has significant protocol changes, including moving from a stateful, bidirectional protocol to stateless request/response. The v1 SDK is built around long-lived sessions, so supporting the new spec means replacing the SDK's core. Since that's breaking anyway, v2 also fixes some long-standing API problems.
What's in this alpha
- A new Dispatcher pipeline replaces ServerSession on the server side (ServerSession remains as a thin proxy). The same change is coming to ClientSession, which will most likely stay as a shim.
- The low level Server interface has changed quite a bit: handlers are now constructor parameters instead of decorators, and return values are no longer auto-wrapped.
- Server middleware, partially added.
- Type changes throughout, including snake_case field names and stricter validation.
- FastMCP is renamed to MCPServer.
The full list is in the migration guide, which is currently the most complete documentation for v2.
NOTE: that this alpha release only implements the 2025-11-25 spec revision. Support for 2026-07-28 feature will be added over time through each alpha release with full 2026-07-28 support targeted for beta release on 2026-06-30.
Stability and timeline
Right now v2 is very breaking, and each alpha will likely contain breaking changes from the previous one, so pin exact versions if you try it. Before the stable release we plan to add a good amount of backwards compatibility shims to reduce the breakage.
Alphas run from now through late June, with a beta targeted for 2026-06-30 and stable v2 targeted for 2026-07-27 (the spec releases 2026-07-28). v1.x is the only stable version of the SDK for now: it stays in maintenance mode and continues to get critical bug fixes and security patches.
TLDR:
- Today (v2.0.0.a1) - Only 2025-11-25 spec functionality support
- Today -> 2026-06-30 - New MCP 2026-07-28 spec functionality will be added to v2 alpha versions and released regularly during this time
- Each alpha release during this should be considered breaking
- 2026-06-30 (estimated) - A beta version of the SDK will be released with full MCP 2026-07-28 spec support
- 2026-07-01 -> 2026-07-27 - Bug fixes and cleanup
- Ideally significantly less breaking that each alpha release, although not guaranteed
- 2026-07-28 - A stable v2.0.0 version of the Python SDK will be released along side the MCP 2026-07-28 spec release.
What you should do
If you maintain a package that depends on mcp, add an upper bound now. 84% of the 10,000+ PyPI packages that depend on mcp declare no upper bound, and they'll all resolve to v2 the day the stable release ships. Add <2 to your existing constraint, for example mcp>=1.27,<2, and your users stay on v1 until you've migrated.
If you want to try v2:
pip install mcp==2.0.0a1
# or
uv add mcp==2.0.0a1One ask: only pin an mcp pre-release from a pre-release of your own package, otherwise you'll drag your users onto the alpha.
Feedback is much appreciated in #python-sdk-dev on the MCP Contributors Discord, or open an issue with the v2-alpha label.
v1.27.2
What's Changed
- [v1.x] ci: deploy docs to py.sdk.modelcontextprotocol.io via Pages artifact by @maxisbey in #2635
- [v1.x] Add subject and claims to AccessToken by @maxisbey in #2690
- [v1.x] Bind transport sessions to the authenticated principal by @maxisbey in #2719
- [v1.x] Scope experimental tasks to the session that created them by @maxisbey in #2720
Full Changelog: v1.27.1...v1.27.2
v1.27.1
What's Changed
- [v1.x] fix: catch PydanticUserError when generating output schema (pydantic 2.13 compat) by @maxisbey in #2435
- [v1.x] fix(auth): coerce empty-string optional URL fields to None in OAuthClientMetadata by @felixweinberger in #2405
- [v1.x] build: restrict httpx to <1.0.0 by @maxisbey in #2559
- [v1.x] refactor: import SSEError from httpx_sse public API by @maxisbey in #2561
Full Changelog: v1.27.0...v1.27.1
v1.27.0
What's Changed
- fix: remove unused
requestsdependency from simple-chatbot example by @maxisbey in #1959 - ci: backport conformance tests from main to v1.x by @felixweinberger in #2068
- fix: add RFC 8707 resource validation to OAuth client by @felixweinberger in #2069
- feat: add idle timeout for StreamableHTTP sessions by @felixweinberger in #1994
- [v1.x] fix: prevent command injection in example URL opening by @maxisbey in #2085
- Add VERSIONING.md, ROADMAP.md, and DEPENDENCY_POLICY.md by @felixweinberger in #2084
- docs: restructure README into docs/ pages by @felixweinberger in #2091
- docs: comprehensive feature documentation for SEP-1730 Tier 1 by @felixweinberger in #2090
- docs: fix stub pages and improve docs structure by @felixweinberger in #2101
- docs: fix GitHub links to point to v1.x branch by @felixweinberger in #2102
- docs: add snippet verification for docs/ pages by @felixweinberger in #2115
- docs: add server-side tool error handling documentation by @felixweinberger in #2129
- Backport: Add missing TasksCallCapability to v1.x by @BabyChrist666 in #2137
- [v1.x] fix: handle non-UTF-8 bytes in stdio server stdin by @maxisbey in #2303
- [v1.x] fix: handle ClosedResourceError when transport closes mid-request by @owendevereaux in #2334
New Contributors
- @owendevereaux made their first contribution in #2334
Full Changelog: v1.26.0...v1.27.0
v1.26.0
What's Changed
- ci: add all-green job to pull-request-checks workflow by @maxisbey in #1929
- Backport: Support for Resource and ResourceTemplate metadata by @maxisbey in #1928
- [v1.x] fix: return HTTP 404 for unknown session IDs instead of 400 by @LucaButBoring in #1945
Full Changelog: v1.25.0...v1.26.0
v1.25.0
Branching Update
Starting with this release, the repository has adopted a new branching strategy for v2 development:
main— v2 development (breaking changes)v1.x— v1 maintenance (security and critical bug fixes only, with very rare feature additions ported frommain)
Users who need to stay on v1.x should pin to mcp>=1.25,<2.
The current plan is to work through v2 and have it released some time in Q1. This also relies on the next upcoming spec release which will heavily change how the transport layer works, which in turn will guide a lot of how we architect v2.
What's Changed
- Fix for Url Elicitation issue 1768 by @gopitk in #1780
- ci: add v1.x branch to main-checks workflow by @maxisbey in #1802
New Contributors
Full Changelog: v1.24.0...v1.25.0
v1.24.0
What's Changed
- feat: client-side support for SEP-1577 sampling with tools by @jlowin in #1722
- Fix JSON-RPC error response ID matching by @crondinini-ant in #1720
- Add
streamable_http_clientwhich acceptshttpx.AsyncClientinstead ofhttpx_client_factoryby @Kludex in #1177 - fix: use correct python command name in test_stdio.py by @WOnder93 in #1782
New Contributors
Full Changelog: v1.23.3...v1.24.0