What changed in MCP spec 2026-07-28
Version 2026-07-28 of the Model Context Protocol was released as stable on 28 July 2026. It replaces the previous revision, 2025-11-25. The headline change is that MCP is now a stateless request/response protocol.
The major changes#
| Change | What it means for a server author |
|---|---|
No handshake. The initialize / notifications/initialized exchange is removed. | Every request carries its protocol version and client capabilities in _meta (io.modelcontextprotocol/protocolVersion, io.modelcontextprotocol/clientCapabilities). Don't assume anything from earlier requests. |
No sessions. Protocol-level sessions and the Mcp-Session-Id header are removed from Streamable HTTP. | Any request can hit any instance behind a load balancer. If you need state across calls, return an explicit handle from one tool and accept it as an argument on the next. |
server/discover is new. | Servers MUST implement it to advertise supported versions, capabilities and identity. Clients may call it first, but don't have to. |
subscriptions/listen replaces the HTTP GET stream and resources/subscribe. | Change notifications such as notifications/tools/list_changed go only to clients that opened a listen stream and opted in. |
| Multi Round-Trip Requests. Server-initiated requests (sampling, elicitation, roots) are replaced. | When a tool needs more input, return a result with resultType: "input_required" and inputRequests; the client retries the original request with inputResponses. |
resultType is required on all results. | Return "complete" for normal results. Clients treat a missing field from older servers as complete. |
Removed: ping, logging/setLevel, notifications/roots/list_changed, SSE resumability. | Log level is set per request in _meta. A broken HTTP response stream loses that request, and the client re-sends it with a new id. |
| Tasks move out of the core into an official extension. | If you used experimental tasks, migrate to the io.modelcontextprotocol/tasks extension. |
Other changes worth knowing#
- Header-based routing. Method and tool names travel in
Mcp-MethodandMcp-NameHTTP headers, and tools can mirror chosen parameters intoMcp-Param-*headers withx-mcp-header. Never mark secrets this way, because proxies can see headers. - Cacheable lists. List results carry
ttlMsandcacheScope, and servers SHOULD return tools in a deterministic order. - Authorization hardening, including RFC 9207 issuer validation and a move away from Dynamic Client Registration towards Client ID Metadata Documents.
- A formal deprecation policy with a minimum twelve-month window.
- SDKs. The MCP blog says the TypeScript, Python, Go and C# SDKs (Tier 1) support 2026-07-28, with Rust support in beta.
Deprecated, not yet removed#
These still work in 2026-07-28 but are on the way out under the new deprecation policy. Don't build anything new on them:
- Roots, Sampling and Logging as core features
- The old HTTP+SSE transport (use Streamable HTTP)
- Dynamic Client Registration, in favour of Client ID Metadata Documents
New and changed error codes#
| Code | Meaning |
|---|---|
-32020 | Header mismatch: an Mcp-* header disagrees with the request body |
-32021 | Missing required client capability |
-32022 | Unsupported protocol version |
-32602 | Now also used for resource not found (previously -32002) |
What to do next#
Follow the step-by-step migration guide for server authors, then re-run your tool list through the linter, which checks the 2026-07-28 tool rules including x-mcp-header.
Frequently asked questions#
Do old MCP clients still work with 2026-07-28 servers?
They can, if the server supports both. The official TypeScript quickstart's serveStdio negotiates per client, answering both 2026-07-28 clients and clients that still send initialize.
Is the Mcp-Session-Id header still used?
No. 2026-07-28 removes protocol-level sessions from Streamable HTTP. Use explicit handles in tool arguments if you need state.