NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #311 most downloaded on PyPI
Model Context Protocol wire types
Last release 2 days ago
02 Oct 2026
Ships unpredictably
gaps range from 2 weeks to 10 months
Most releases are documented
notes for 6 of 8 stable releases
Nothing withdrawn
no release was ever pulled
1 years old
12 releases · first in 2025
One column per month.
pip install -U mcp . Docs: https://py.sdk.modelcontextprotocol.io/
pip install -U mcp. Docs: https://py.sdk.modelcontextprotocol.io/
Mostly fixes, plus three new options. A few things behave differently, so skim these first:
httpx2>=2.10.0 is now required (#3600)
>=2.5.0. The new max_sse_event_size option needs it.httpx2 below 2.10.A tool with an invalid x-mcp-header annotation fails at registration (#3620)
@mcp.tool(), add_tool and Tool.from_function raise InvalidSignature, naming the tool and the problem.str, int or bool parameter (so also str | None, float, lists and enums), a header name that isn't a valid token, and two names that differ only by case.Annotated[str | None, WithJsonSchema({"type": "string", "x-mcp-header": "Region"})] = None.Empty _meta and params are no longer sent (#3628)
"_meta": {} on every request. Some servers reject that. It is now left out, as in v1.ping and list requests without a cursor go out with no params member.ctx.meta is None rather than {}, and middleware sees ctx.params as None for a request without params.initialize leaves out experimental when none is configured (#3614)
"experimental": {}. server/discover already left it out.capabilities.experimental on a legacy connection should handle None.Mcp-Param-* validation looks the tool up by name (#3630)
MCPServer no longer runs tools/list for every tools/call, so middleware no longer sees that extra request.tools/list no longer affects it.An interactive OAuth login no longer counts against request timeouts (#3635)
OAuthClientProvider waits on redirect_handler and callback_handler.Client(mode="auto") settling on 2025-11-25 when the login took longer than 10 seconds.callback_handler if you need one.max_sse_event_size= on streamable_http_client and StreamableHttpParameters. The default stays 1 MiB per SSE event; raise it, or pass None, for larger tool results (#3600).MCPServer(subscriptions=False) stops serving subscriptions/listen and advertises listChanged and subscribe as false (#3626).Server(get_tool_input_schema=...) lets a low-level server supply a tool's schema for header validation without running its tools/list handler (#3630).Client.call_tool re-lists the tools and retries once after a HeaderMismatch (-32020) rejection (#3627).ctx: Context[AppState] works on prompts and resource templates, not only on tools (#3624)."structuredContent": null is checked against the output schema instead of being treated as missing (#3621).progress_callback that raises no longer fails the call on an in-process Client(server) (#3623).mode="auto", connecting to a server without server/discover now shows one ERROR span for the probe (#3629).stdio_client resolves the executable off the event loop on Windows (#3510).Full Changelog: v2.2.0...v2.3.0
Two new MCPDeprecationWarning s ( #3435 , #3447 )
pip install -U mcp. Docs: https://py.sdk.modelcontextprotocol.io/
A few defaults changed in this release. If you run a server or client on 2.x, skim these first:
HTTP client redirects are only followed within the endpoint's origin (#3397)
Client("https://..."), streamable_http_client and sse_client follow a redirect only if it stays on the same scheme, host and port (or upgrades http to https on the same host).MCPError and the session stays usable (an SSE connect fails with httpx2.HTTPStatusError). If that other URL is the server you meant, use it as the endpoint URL.follow_redirects setting on an httpx2.AsyncClient you pass in is no longer used for MCP requests, so you don't need it for the trailing-slash redirect any more.Idle Streamable HTTP sessions now expire (legacy <=2025-11-25 spec( (#3395)
Client does) are not affected. Neither are stateless servers or 2026-07-28 connections.mcp.run(transport="streamable-http", session_idle_timeout=None, max_sessions=None) (also on streamable_http_app() and run_streamable_http_async()).The OAuth client checks the authorization server's issuer on the legacy path too (#3398)
issuer isn't the server's own origin is now rejected with OAuthFlowError: Authorization server metadata issuer mismatch. The protected-resource-metadata path has done this since 2.0.insufficient_scope challenge is returned to the caller instead of retried.Two new MCPDeprecationWarnings (#3435, #3447)
ClientCredentialsOAuthProvider / PrivateKeyJWTOAuthProvider without issuer=. Pass your authorization server's issuer URL; 3.0 will require it.AuthSettings with resource_server_url set but validate_token_resource unset. Set it to True or False; 3.0 defaults it to True.AuthSettings.validate_token_resource: only accept tokens your TokenVerifier reports as issued for this server (#3447).issuer= on ClientCredentialsOAuthProvider and PrivateKeyJWTOAuthProvider (#3398).session_idle_timeout= and max_sessions= on the Streamable HTTP server entry points (#3395).DELETE frees its session immediately, and a refused opening request no longer leaves a session behind (#2455, #3228, #3300).$refs in a tool's outputSchema resolve within that schema only; an unresolvable one surfaces as RuntimeError: Invalid schema for tool ... (#3394).The tasks extension (SEP-2663), DPoP (SEP-1932) and the jwt-bearer grant are not implemented yet; https://github.com/modelcontextprotocol/python-sdk/blob/main/ROADMAP.md tracks them.
Full Changelog: v2.1.1...v2.2.0
Point imports of mcp.server.fastmcp at the migration guide by @maxisbey in #3388
Full Changelog: v2.1.0...v2.1.1
Stop framing breaking changes as a workflow in AGENTS.md by @maxisbey in #3286
Client accepts StdioServerParameters directly: Client(StdioServerParameters(command="uv", args=["run", "server.py"])) (#3321).Image and Audio, prompt functions may return bare content blocks, and Message / UserMessage / AssistantMessage are exported from mcp.server.mcpserver (#3320).SseServerTransport and MCPServer.sse_app() take max_request_body_size, and the SSE message endpoint answers 405 to non-POST requests (#3336).Error executing tool <name> (or the resource/prompt equivalent) rather than the exception text. Raise ToolError / ResourceError when the message is meant for the model; those still reach the client and are logged at INFO without a traceback.TextContent, EmbeddedResource, Image, Audio, or lists/unions of them no longer advertises outputSchema or returns structuredContent; its content is unchanged. Pass structured_output=True to keep the previous shape.NotRequired keys are omitted instead of serialized as null, and registration no longer fails on Python 3.10 (#3224, #3227); recursive return types get an object-rooted outputSchema that pre-2026 clients accept (#3337).notifications/cancelled is acknowledged with 202 instead of rejected with 400 (#3324).list_tools() (#3223), and accept boolean sub-schemas in tool schema properties (#3353).mcp install reads and preserves a Claude Desktop config containing non-ASCII text on any Windows code page (#3296).Full Changelog: v2.0.0...v2.1.0
One off backport of the FastMCP import warning for 2.0.x , this is due to a lot of people running into this error and making issues on other repos abo
One off backport of the FastMCP import warning for 2.0.x, this is due to a lot of people running into this error and making issues on other repos about it. Ideally either pin mcp<2 or upgrade to 2.
Full Changelog: v2.0.0...v2.0.1
v1.x is in maintenance mode and will only receive security fixes from now on The 1.x line lives on the v1.x branch , continues to receive critical bug…
This is v2.0.0, the stable v2 release of the MCP Python SDK. It supports the 2026-07-28 revision of the Model Context Protocol and serves every earlier revision from the same server. pip install mcp now installs 2.x.
pip install "mcp[cli]"
# or
uv add "mcp[cli]"The documentation has the full tutorial and API reference. Coming from v1? What's new in v2 is the tour of what changed and why, and the migration guide lists every breaking change with before-and-after code.
v1.x is in maintenance mode and will only receive security fixes from now on The 1.x line lives on the v1.x branch, continues to receive critical bug fixes and security patches, and is documented at https://py.sdk.modelcontextprotocol.io/v1/. If your project is not ready to migrate, keep a <2 upper bound on your requirement (for example mcp>=1.28,<2).
v2 speaks the 2026-07-28 revision (stateless requests with no handshake, server/discover, subscriptions/listen, multi-round-trip requests) and still serves every 2025-era client from the same MCPServer, over Streamable HTTP and stdio, with nothing to configure. Client(target) negotiates the version automatically.
FastMCP is now MCPServer, and there is a first-class ClientThe decorator API is unchanged; the low-level Server is rebuilt around a shared dispatcher engine, and one Client object replaces v1's transport-plus-ClientSession-plus-initialize() layering. It connects to a URL, a stdio subprocess, a custom transport, or straight to a server object in memory for tests.
At 2026-07-28 the server can no longer call the client, so tools return the question instead. A Resolve(fn) parameter is filled by your function invisibly to the model and can put a question to the user; one tool body serves both eras.
Servers and clients compose protocol extensions through pluggable extension APIs (MCP Apps built in); OpenTelemetry tracing ships on by default; every protocol type is its own package, mcp-types (imported as mcp_types), published in lock-step with mcp.
stdio servers keep handler subprocesses and stray prints off the wire, and stdout is diverted to stderr while serving. OAuth adds RFC 9207 issuer validation, the SEP-990 identity-assertion flow, and the client-credentials extension.
Since the last release candidate: the per-version wire packages are private (mcp_types._v*), mcp.types is a permanent alias for mcp_types, the auth registration request model is split from the registered-client record, cancelled requests are no longer answered, and log notifications are gated on the per-request log-level opt-in at 2026-07-28. Since the betas: Client(cache=False) is now cache=None with CacheConfig() the default; Context.client_id, RFC7523OAuthClientProvider, and OAuthClientProvider(timeout=) are removed; the client-credentials providers take scope=; message_handler receives notifications and exceptions only; FileResource(is_binary=) becomes encoding; MCP_* env vars are gone with pydantic-settings; Streamable HTTP servers reject bodies over 4 MiB with HTTP 413. The migration guide covers all of it.
The tasks extension (SEP-2663) is not part of this release. On the client, the DPoP proof binding (SEP-1932) and the workload-identity jwt-bearer grant are not implemented; both are additive and can land in 2.x.
Something rough, confusing, or broken? Open an issue or find us in #python-sdk-dev on the MCP Contributors Discord.
Full Changelog: v2.0.0rc1...v2.0.0
Remove the deprecated RFC7523OAuthClientProvider by @maxisbey in #3169
First v2 release candidate. Pre-releases are opt-in only; pip install mcp still resolves to the stable 1.x line.
pip install mcp==2.0.0rc1
# or
uv add "mcp==2.0.0rc1"The documentation has the full tutorial and API reference, and the migration guide covers coming from v1. Stable v2 is planned for 2026-07-28 alongside the spec release - keep pinning an exact version until then.
The last pre-release pass over the public surface; every item has a migration guide entry.
Client(cache=False) is now Client(cache=None): CacheConfig() is the default and None switches the response cache off (#3164).Context.client_id is removed - read _meta via ctx.request_context.meta, or the authenticated client via get_access_token().client_id (#3167).RFC7523OAuthClientProvider and JWTParameters are removed - use ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider, or IdentityAssertionOAuthProvider (#3169).scope=, not scopes= (#3166).OAuthClientProvider(timeout=...) is removed; it never bounded anything (#3165).message_handler receives ServerNotification | Exception only; the dead RequestResponder arm and the mcp.shared.session module are gone (#3168).FileResource(is_binary=...) is replaced by encoding: str | None (#3171).MCP_* environment variables never configured MCPServer and are no longer advertised; pydantic-settings is dropped from the runtime dependencies (#3170).max_request_body_size if you accept larger messages (#3095).The request-side clientInfo _meta key is optional (the required pair is protocolVersion + clientCapabilities), and serverInfo moved out of the server/discover result body into every 2026-era result's _meta; client.server_info is now Implementation | None. This tracks spec change #3002 and fixes interop with servers that already omit body serverInfo.
A stdio (or in-memory) server now decides the protocol era from the client's opening request, so subscriptions/listen and every other 2026-07-28 feature serve over stdio, not only Streamable HTTP.
stdio_server() serves from private duplicates of stdin/stdout and points fd 0 at the null device and fd 1 at stderr while it runs, so a stray print() or a chatty child process can no longer corrupt the JSON-RPC stream. This fixes the classic print-corrupts-the-wire class (#409) and the Windows tool-call hang (#671).
exclude-newer cooldown: mcp pins mcp-types to the exact same version, so exempt both packages - exclude-newer-package = { mcp = false, mcp-types = false }.Full Changelog: v2.0.0b2...v2.0.0rc1
Second v2 beta. Pre-releases are opt-in only; pip install mcp still resolves to the stable 1.x line.
Second v2 beta. Pre-releases are opt-in only; pip install mcp still resolves to the stable 1.x line.
pip install mcp==2.0.0b2
# or
uv add "mcp==2.0.0b2"The documentation has the full tutorial and API reference, and the migration guide covers coming from v1. Stable v2 is still targeted for 2026-07-28 alongside the spec release - keep pinning an exact version.
The SDK's HTTP stack now runs on httpx2 (>=2.5.0), the next-generation httpx fork with SSE support built in, replacing httpx + httpx-sse. Most code needs no changes; if you pass your own http_client into a transport, change the import to httpx2. Runtime behavior that changes:
truststore) instead of certifi's bundle. SSL_CERT_FILE / SSL_CERT_DIR are honored first.httpx -> httpx2, httpcore.* -> httpcore2.* - update logging filters that match on those names.Accept: application/json, text/event-stream (previously exactly text/event-stream).The client half of subscriptions/listen (SEP-2575), promised in the b1 notes: one context manager, async for consumption, typed events.
async with client.listen(tools_list_changed=True, resource_subscriptions=["note://todo"]) as sub:
print(sub.honored) # the subset the server agreed to deliver
async for event in sub:
match event:
case ToolsListChanged():
tools = await client.list_tools()
case ResourceUpdated(uri=uri):
body = await client.read_resource(uri)Entering waits for the server's acknowledgment, so sub.honored is always populated and pre-ack failures raise instead of degrading silently.
Cancelling or timing out a client request now actually stops it: over streamable HTTP the request's own POST/SSE stream is closed (the spec's cancellation signal), and over stdio the client sends notifications/cancelled. Callers can also supply the request id for a call - the seam the listen driver builds on.
Resolver dependency injection now covers all three multi-round-trip request kinds (SEP-2322): a dependency can return Sample(...) or ListRoots() in addition to Elicit(...), so a tool can ask the client's LLM or fetch its roots mid-call, on both protocol eras.
exclude-newer cooldown: mcp pins mcp-types to the exact same version, so exempt both packages - exclude-newer-package = { mcp = false, mcp-types = false }.Full Changelog: v2.0.0b1...v2.0.0b2
Spec deprecations : roots, sampling, and logging/setLevel are deprecated per SEP-2577 - advisory warnings only; everything keeps working for sessions…
First v2 beta, and the first release with full support for the 2026-07-28 MCP specification. Pre-releases are opt-in only; pip install mcp still resolves to the stable 1.x line.
pip install mcp==2.0.0b1
# or
uv add "mcp==2.0.0b1"The documentation has the full tutorial and API reference, and the migration guide covers coming from v1. Beta means the architecture is settled and changes from here should be much smaller than between alphas, but the API can still shift before stable v2, targeted for 2026-07-28 alongside the spec release - keep pinning an exact version.
The whole v2 line so far (alphas included), condensed:
ServerRunner is a pure handler kernel, transports are thin drivers over it, and one endpoint serves both protocol eras side by side.FastMCP is now MCPServer. The decorator API stays; the low-level Server takes handlers as constructor parameters, fields are snake_case, and traffic is validated against the negotiated spec version on the wire.Client. Client(target, mode='auto') speaks every protocol version - it probes server/discover and falls back to initialize automatically. The target can be a URL, a stdio subprocess, a custom transport, or a server object in memory (great for tests).mcp-types (imported as mcp_types) depends only on pydantic and typing-extensions, so tooling can speak MCP without the transport stack. Published in lock-step with mcp.Client(extensions=[...]).(ctx, call_next), and OpenTelemetry tracing ships on by default with GenAI semantic conventions.Client and server:
server/discover, scale-out on plain HTTP with no session affinity - progress and log notifications stream within the same single POST exchange.MCPServer, requestState is sealed by default (authenticated encryption) so clients cannot read or forge it.Mcp-Method / Mcp-Name / Mcp-Param-* headers stamped by the client and validated by the server (SEP-2243), and ttlMs / cacheScope caching hints stamped by servers and honored by the client-side response cache (SEP-2549).logging/setLevel are deprecated per SEP-2577 - advisory warnings only; everything keeps working for sessions on 2025-11-25 or earlier.v2 passes the official MCP conformance suite, client and server, except the tasks suite: tasks moved to an extension in 2026-07-28, and support is in review to ship in an upcoming pre-release.
mcp, add a <2 upper bound now (for example mcp>=1.27,<2) so the stable release doesn't surprise your users.Full Changelog: v2.0.0a3...v2.0.0b1
See the migration guide for the full list of breaking changes.
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.
The public API is likely to change between alpha releases, and ideally less-so between beta releases.
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.
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.
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.
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).
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.
iss authorization-response parameter (RFC 9207 / SEP-2468) by @Kludex in #2921redirect_uri wire-format change in OAuth migration note by @Kludex in #2929application_type during Dynamic Client Registration (SEP-837) by @Kludex in #2930(ctx, call_next) and add OpenTelemetryMiddleware by @Kludex in #2941mcp-types package by @Kludex in #2973Full Changelog: v2.0.0a2...v2.0.0a3
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →