The Model Context Protocol’s 2026-07-28 specification, published on July 28, 2026, converts MCP from a bidirectional stateful protocol into a request/response stateless one. The initialize and initialized handshake is removed. The Mcp-Session-Id header is removed. Every request now carries its own protocol version, client identity and capabilities, which means any server instance can serve any request behind a plain round-robin load balancer.
That single architectural decision is what everything else in the release hangs off. Once no request depends on a prior one, sticky sessions stop being necessary, shared session stores stop being necessary, and an MCP server becomes an ordinary HTTP workload that a serverless platform or an edge runtime can host without special handling. The MCP team describes the change as one of the most highly-requested features from developers who were eager to get better reliability and scalability.
This guide covers what changed field by field, why the deployment story shifts, how Multi Round-Trip Requests replace the old server-initiated call pattern, what the authorization rework actually requires, which SDK your team has to touch and in what order, and what genuinely has a deadline versus what only looks urgent. Nothing here breaks a 2025-11-25 server on day one — but two of these changes need real code before you get the new deployment behaviour.
- 01The handshake and the session header are both gone.SEP-2575 removes initialize/initialized in favour of per-request _meta fields; SEP-2567 removes Mcp-Session-Id from Streamable HTTP. These are the two changes that require real code from any server that wants the new stateless behaviour.
- 02Server-initiated requests become a retry pattern.Multi Round-Trip Requests (SEP-2322) replace roots/list, sampling/createMessage and elicitation/create. The server returns resultType input_required with an inputRequests array, and the client retries the original call with inputResponses filled in.
- 03Routing and caching became protocol-level obligations.Mcp-Method and Mcp-Name headers are required on every Streamable HTTP POST (SEP-2243), and list results must now carry ttlMs plus a public or private cacheScope (SEP-2549) rather than relying on listChanged notifications alone.
- 04Auth moves to CIMD, and MCP now mandates RFC 9207.Client ID Metadata Documents become the primary registration path, with Dynamic Client Registration deprecated but retained for compatibility. RFC 9207 issuer validation is newly required — the RFC itself is from March 2022, not new in 2026.
- 05Four Tier 1 SDKs shipped support on spec day; Rust did not.TypeScript, Python, Go and C# all support 2026-07-28 as of publication day. Rust is Tier 2 and in beta. Go kept its existing module path and versioning rather than jumping to a v2 line, so migration effort is not uniform across languages.
01 — The Core ChangeNo handshake, no session ID, no shared state.
Before this revision, an MCP session had a shape. A client opened a connection, sent initialize, received the server’s capabilities, sent initialized, and only then began issuing real calls. On Streamable HTTP, the server handed back an Mcp-Session-Id and every subsequent request carried it. That header is what forced sticky routing: a request had to reach the instance that held the session, or the instances had to share a session store.
The 2026-07-28 revision deletes both halves of that arrangement. Each request now self-describes through _meta fields — io.modelcontextprotocol/protocolVersion, io.modelcontextprotocol/clientCapabilities and io.modelcontextprotocol/clientInfo — and the server echoes io.modelcontextprotocol/serverInfo back. A version the server cannot serve returns UnsupportedProtocolVersionError rather than failing an invisible handshake precondition.
The practical consequence for list endpoints is worth stating plainly: tools/list, resources/list and prompts/list no longer vary per connection. If your server was returning a different tool set depending on what happened during initialize, that behaviour has nowhere to live. Servers that genuinely need cross-call state now mint explicit handles and pass them as ordinary tool arguments — state becomes data in the protocol, not an invisible property of the connection.
The initialize handshake
Protocol version, client capabilities and client info travel with each call; the server echoes serverInfo back. A mismatch returns UnsupportedProtocolVersionError instead of failing a hidden precondition.
Mcp-Session-Id
List endpoints stop varying per connection. Servers needing cross-call state mint explicit handles and pass them as ordinary tool arguments, so the state is visible in the call rather than implied by the socket.
server/discover
Clients can probe supported protocol versions, capabilities and identity before the first real call — useful over HTTP, and as a backward-compatibility probe on STDIO. Servers must implement it.
"The new release is MCP's most important since remote MCP first launched over a year ago. It is a leap in serving scalable MCP servers."— David Soria Parra, MTS and MCP co-inventor
02 — Field By FieldThe full before and after, with SEP numbers.
Vendor posts describe this release as a bulleted list of headline features. What a team actually planning a migration needs is the mechanic-by-mechanic diff, with the SEP number attached so an engineer can go read the proposal that changed it. The table below is our own assembly of the published changelog into that shape. Every row traces to the 2026-07-28 changelog; the right-hand column is the tracking identifier the spec itself uses.
| Protocol mechanic | 2025-11-25 (previous) | 2026-07-28 (current) | Tracked as |
|---|---|---|---|
| Transport and lifecycle | |||
| Handshake | initialize / initialized exchange required before any other call | Removed. Every request self-describes protocol version, client identity and capabilities via _meta fields; servers echo serverInfo back. Version mismatches return UnsupportedProtocolVersionError. | SEP-2575 |
| Session identity | Mcp-Session-Id header carried per-connection state | Removed from Streamable HTTP. List endpoints no longer vary per connection; servers that need cross-call state mint explicit handles passed as ordinary tool arguments. | SEP-2567 |
| Capability discovery | Learned from the initialize response | New server/discover RPC. Clients may call it to probe supported versions, capabilities and identity up front; servers must implement it. Useful as a STDIO backward-compat probe. | 2026-07-28 spec |
| Request routing | Gateways had to parse the JSON-RPC body to see the method | Every Streamable HTTP POST must carry Mcp-Method and Mcp-Name headers so proxies, rate limiters and gateways can route and meter without body inspection. Custom tool-parameter headers use x-mcp-header. | SEP-2243 |
| Stream resumability | Last-Event-ID header plus SSE event IDs allowed redelivery | Removed. A broken response stream loses the in-flight request; clients must re-issue it as a new request with a new request ID. | 2026-07-28 changelog |
| Interaction model | |||
| Server-initiated requests | roots/list, sampling/createMessage, elicitation/create | Multi Round-Trip Requests. The server returns resultType input_required with an inputRequests array; the client retries the original call with inputResponses filled in. | SEP-2322 |
| Result envelope | No mandatory type discriminator on results | resultType is mandatory: complete for normal results, input_required for MRTR interim results. Clients treat pre-2026-07-28 servers that omit it as complete. | 2026-07-28 changelog |
| List-result caching | Optional, driven by listChanged notifications | Required. tools/list, prompts/list, resources/list, resources/read and resources/templates/list must carry ttlMs and cacheScope via a new CacheableResult interface, on top of listChanged. | SEP-2549 |
| Task handling | Experimental Tasks in core, with a blocking tasks/result | Moved into a formal extension. Blocking tasks/result is gone in favour of polling via tasks/get plus a new client-to-server tasks/update; tasks/list is removed; servers may return task handles unsolicited. | SEP-2663 |
| Elicitation completion | notifications/elicitation/complete plus an elicitationId field | Both removed. Under MRTR the client learns the outcome by retrying the original request; servers that need correlation encode their own identifier in request state. | 2026-07-28 changelog |
| Resource-not-found error | JSON-RPC error code -32002 | -32602 (Invalid Params), aligning with the JSON-RPC spec. A new allocation policy reserves -32020 to -32099 for MCP; existing SDK use of -32000 to -32019 is grandfathered. | 2026-07-28 changelog |
| Authorization | |||
| Client registration | Dynamic Client Registration (RFC 7591) as the primary path | Client ID Metadata Documents become primary; DCR is formally deprecated as the primary mechanism but stays available for authorization servers that do not yet support CIMD. | PR #2858 |
| Issuer validation | Not required | Authorization servers should include the iss parameter, and MCP clients must validate a present iss against the recorded issuer before redeeming the code. The mechanism is RFC 9207, published in March 2022. | SEP-2468 |
| Credential portability | Not addressed explicitly | DCR-issued or pre-registered credentials must be bound to the issuer that granted them and must not be reused elsewhere. CIMD identities are portable because the client_id is a self-hosted URL resolved on demand. | SEP-2352 |
| Native app registration | application_type omitted, so OpenID Connect defaulted clients to web | application_type (native or web) is required during DCR, fixing the localhost redirect-URI rejections that hit desktop and CLI MCP clients. | SEP-837 |
Read down the middle column and a pattern shows up that no single bullet point communicates: almost every removal takes something that was implicit in the connection and either deletes it or forces it into the message. Session identity becomes a tool argument. Protocol version becomes a _meta field. Result kind becomes a mandatory resultType. Cache freshness becomes ttlMs. Method identity becomes an HTTP header. The protocol got more verbose on the wire in exchange for getting far less stateful in the infrastructure.
03 — DeploymentStateless, therefore serverless, therefore edge.
Several infrastructure vendors commented on the release, and the temptation is to read those as separate endorsements. They are more useful read as one causal chain. No session ID means no request depends on a prior request. No dependence between requests means no sticky routing. No sticky routing means a plain round-robin load balancer is sufficient, which in turn means the compute behind it can be ephemeral — a function invocation, a worker isolate, a container that scales to zero between calls.
The MCP team’s own framing is that the change enables plain round-robin load balancing without shared storage. AWS VP of Agentic AI Swami Sivasubramanian put the operator’s version of it this way: “Developers can deploy MCP servers on standard, scalable infrastructure without managing sessions or persistent connections.” Netlify’s Sean Roberts made the same point from the platform side, describing the stateless core as making MCP a first-class HTTP workload with no session management to work around.
"MCP 2026-07-28 is a major step toward making agent infrastructure work like the rest of the web: stateless, cacheable, routable, and globally scalable."— Brendan Irvine-Broque, Cloudflare
The interpretation worth adding is that this is a normalisation move, not an innovation one. Agent infrastructure has been carrying architectural exceptions — sticky sessions, long-lived connections, back-channels from server to client — that the rest of web infrastructure spent the previous decade engineering away. Those exceptions are precisely why MCP servers have been comparatively awkward to run at scale: they could not use the cheap, boring, horizontally-scalable primitives that every other HTTP service already uses. This revision gives up protocol elegance to buy back operational ordinariness, and for anyone paying an infrastructure bill that is the better trade.
Projecting forward, the constraint that binds next is unlikely to be the protocol. If MCP servers become cheap to host on serverless and edge platforms, the bottleneck moves to authorization and cost attribution — knowing which agent, on whose behalf, invoked which tool, and who pays for it. The header-routing requirement in this same revision is a quiet acknowledgement of that: it exists so gateways can meter traffic without parsing bodies. Expect the next year of MCP tooling to be far more about gateways, quotas and identity than about transports. If you are standing up that layer, our AI transformation engagements typically start by mapping which agent traffic actually needs to be metered before anyone writes a gateway rule.
04 — Interaction ModelMulti Round-Trip Requests replace the back-channel.
The hardest part of removing state is not the session header. It is the fact that MCP servers used to be able to call back to the client. A server could ask for filesystem roots, ask the client’s model to sample a completion, or elicit input from the user mid-request. All three of those patterns assume a live, identified channel back to a specific client — exactly what a stateless request/response model does not have.
Multi Round-Trip Requests (SEP-2322) solve this by inverting who drives. Instead of the server initiating a call, the server returns. A result comes back with resultType set to input_required and an inputRequests array describing what it needs. The client gathers those inputs and retries the original call with inputResponses filled in. There is no open channel to maintain, and no requirement that the retry land on the same server instance.
Two consequences follow that are easy to miss. First, resultType is now mandatory on every result — complete for a normal one — and clients must treat pre-2026-07-28 servers that omit the field as complete for backward compatibility. Second, the elicitation completion signal is gone: both notifications/elicitation/complete and the elicitationId field introduced in 2025-11-25 have been removed, because under MRTR the client learns the outcome by retrying rather than by being told. Servers that need to correlate an out-of-band interaction now encode their own identifier in request state.
requestState: an opaque, HMAC integrity-protected string that round-trips through client retries, with a createRequestStateCodec() helper to produce and verify it. Handlers write once using inputRequired(...), and a legacy shim serves both 2025-era and 2026-era clients from the same code path.05 — Routing & CachingHeaders, TTLs, and a cache scope that finally exists.
Two smaller changes matter more than their SEP numbers suggest, because together they make MCP traffic legible to ordinary infrastructure. Header-based routing means a gateway can see what a request is without deserialising JSON-RPC. Cacheable list results mean a tool catalogue can sit in a CDN instead of being re-fetched per client per connection.
Required on every POST
Streamable HTTP POSTs must carry Mcp-Method and Mcp-Name, so gateways, rate limiters and proxies can route and meter traffic without parsing the JSON-RPC body. Custom tool-parameter headers use the x-mcp-header convention.
Methods that must ship a TTL
tools/list, prompts/list, resources/list, resources/read and resources/templates/list must now carry ttlMs, a freshness hint in milliseconds, via the new CacheableResult interface. This is on top of listChanged notifications, not instead of them.
public or private
cacheScope controls whether shared intermediaries may cache a list result. Public lets a gateway or CDN hold one copy for everyone; private confines it to the requesting client. Getting this wrong is a data-leak class of bug, not a performance one.
The cacheScope field deserves a second look during review. A server that returns a per-tenant tool list and marks it public is inviting a shared intermediary to serve one tenant’s catalogue to another. That is a straightforward mistake to make when a codebase is being converted from a model where lists legitimately varied per connection — which is exactly the codebase most teams are about to convert. If you are debugging what your server actually returns during that conversion, our walkthrough on debugging an MCP server with Inspector covers the inspection loop.
One removal belongs in this section too, because it changes failure handling rather than routing: SSE stream resumability is gone. The Last-Event-ID header and SSE event IDs have been removed from Streamable HTTP, so a broken response stream loses the in-flight request outright. Clients must re-issue it as a new request with a new request ID rather than expecting redelivery. Any client retry logic written against the old resumption behaviour needs revisiting.
06 — AuthorizationCIMD, and an RFC that is four years old.
The authorization rework is the part most likely to be misreported, so it is worth being precise. MCP did not invent new security primitives in this release. It made two existing ones mandatory and reordered how clients register.
The first is RFC 9207 issuer validation (SEP-2468). Authorization servers should include the iss parameter in authorization responses, and MCP clients must now validate a present iss against the recorded issuer before redeeming the authorization code. RFC 9207 itself, “OAuth 2.0 Authorization Server Issuer Identification,” was published by the IETF in March 2022 as a countermeasure to mix-up attacks, where a client talking to several authorization servers can be tricked into sending a code or token to the wrong one. What is new in 2026 is the requirement, not the mechanism.
The second is the shift from Dynamic Client Registration to Client ID Metadata Documents. Under CIMD, a client’s identity is an HTTPS URL with a path — something like https://app.example.com/oauth/client-metadata.json — that dereferences to a JSON document containing at minimum client_id, client_name and redirect_uris. The authorization server fetches and caches that document, respecting HTTP cache headers, and validates that the document’s client_id matches the URL exactly.
The portability argument is the reason this matters operationally. Because a CIMD client_id is a self-hosted URL resolved on demand, changing authorization servers does not require re-registration. DCR-issued and pre-registered credentials go the other way: SEP-2352 requires them to be bound to the specific issuer that granted them and forbids reuse elsewhere.
Pre-registered credentials
If the client already holds credentials for this authorization server, use them. They must be keyed by issuer identifier and must not be reused against a different server.
CIMD metadata document
Used when the authorization server advertises client_id_metadata_document_supported: true in its OAuth Authorization Server Metadata. Portable across issuers because the identity is a URL the client hosts.
Dynamic Client Registration
Retained as a fallback for authorization servers that do not yet support CIMD. Now also requires application_type (native or web), which fixes localhost redirect-URI rejections for desktop and CLI clients under OpenID Connect.
Manual user entry
When none of the above are available, the client falls back to asking the user to supply credentials directly. Treat reaching this rung as a signal that the integration needs attention, not as a normal path.
07 — SDK MigrationWhich SDK you touch, and how much it hurts.
Every language SDK announced its own migration separately, which makes it hard to see that the effort is not remotely uniform. C# shipped a stable 2.0 on spec day and leads with backward compatibility. TypeScript retired its monolithic package and split into three. Python renamed its headline class. Go changed the least of all four and kept its module path. Rust is not in the same conversation yet.
The beta and release-candidate SDKs landed on June 29, 2026 — 29 days before the spec published on July 28, 2026 (June 29 to June 30 is 1 day, plus 28 days of July). The betas carried an explicit warning that public APIs might still change between the betas and the stable releases, so anything pinned to a June beta is worth re-checking against the shipped version.
| SDK | Beta / RC | Stable status | Biggest package or naming change | Backward-compat story |
|---|---|---|---|---|
| Tier 1 — support on spec-publication day | ||||
| TypeScript | v2 beta, June 29, 2026 (ESM-only, Node 20+ / Bun / Deno) | v2 line supports 2026-07-28 as of July 28, 2026 | Monolithic @modelcontextprotocol/sdk retired; split into /server, /client and /server-legacy, plus Express, Fastify, Hono and Node adapters | One server can serve every 2025-era revision (2024-10-07 through 2025-11-25) alongside 2026-07-28 via createMcpHandler(factory); a legacy shim serves both eras from the same handler code |
| Python | 2.0.0b1, June 29, 2026 | 2.0.0rc1 as of July 27, 2026 | FastMCP renamed to MCPServer; imports move from mcp.server.fastmcp.* to mcp.server.mcpserver.*; all fields switch to snake_case (result.is_error, tool.input_schema) | The ctx.elicit() back-channel call is deprecated in favour of InputRequiredResult with state tokens |
| Go | v1.7.0-pre.1, June 29, 2026 | Not stated in the sources cited here | No module-path change. Go kept its existing versioning line rather than jumping to a v2 major | Existing imports keep resolving because the module path is unchanged |
| C# | 2.0.0-preview.1, June 29, 2026 | 2.0.0, July 28, 2026 — shipped on spec day | Composable packages: ModelContextProtocol.Core, ModelContextProtocol, ModelContextProtocol.AspNetCore, plus Tasks and Apps extension packages | The .NET team states v2.0 is backward compatible and that stable v1 code keeps compiling and running |
| Tier 2 — beta | ||||
| Rust | Beta | Not stated in the sources cited here | Not stated in the sources cited here | Tier 2. Do not plan a production migration on the same schedule as the four Tier 1 SDKs |
Two cells in that table are load-bearing for planning. The TypeScript row means a single server can serve every 2025-era revision from 2024-10-07 through 2025-11-25 alongside 2026-07-28 via createMcpHandler(factory) — so a TypeScript team can adopt the new spec without cutting old clients off, provided they accept the package split. The C# row means .NET teams can upgrade the SDK first and migrate protocol behaviour second, since the .NET team states that upgrading does not force you off existing clients and servers and that stable v1 code keeps compiling and running.
The Go row is the one most likely to be misread. Go did not ship a v2 module. Its release candidate was v1.7.0-pre.1 on the same module path, which is a materially different migration experience from a package split or a class rename. If you are planning a multi-language rollout, do not assume the four Tier 1 SDKs cost the same. And if you are writing a new server rather than migrating one, our build an MCP server in TypeScript from scratch walkthrough is the cheaper starting point than retrofitting.
08 — DeprecationsWhat is on a clock, and what to do instead.
The revision also introduces a formal feature-lifecycle policy with a minimum 12-month deprecation window, and then immediately uses it. The legacy HTTP+SSE transport — already deprecated since protocol version 2025-03-26 — is reclassified as formally Deprecated. So are Roots, Sampling and Logging (SEP-2577), along with the includeContext values thisServer and allServers (SEP-2596). The spec publishes a suggested migration for each rather than leaving teams to guess.
Directory and file access
Deprecated under SEP-2577. The suggested migration is to pass files and directories to the server as ordinary tool parameters, rather than exposing a roots/list back-channel that a stateless model cannot support cleanly.
Borrowing the client’s model
sampling/createMessage is deprecated alongside Roots. The suggested migration is for the server to call an LLM provider’s API directly, which also makes cost and model choice explicit instead of implicit.
Protocol-level log messages
The Logging feature is deprecated. Suggested migration: write to stderr, or emit OpenTelemetry, and let the observability stack you already run collect it — which is where most teams were sending these logs anyway.
The legacy transport
Deprecated since protocol version 2025-03-26 and now formally Deprecated under the new lifecycle policy, with the minimum 12-month window running. Streamable HTTP is the destination, and it is also where the new routing headers and stateless behaviour live.
Worth separating urgency from noise here. The deprecations above are on a 12-month-minimum clock and can be scheduled. The two items that are not on a clock — because they are the price of admission for the new behaviour rather than a phase-out — are the handshake removal and the Mcp-Session-Id removal. A server that wants stateless deployment has to make those two changes now; everything else on this page can be planned into a quarter.
The extensions framework is the other structural change in this release, and it is quietly the most consequential for anyone building on top of MCP. The spec adds an extensions field to both ClientCapabilities and ServerCapabilities, and Tasks, Enterprise Managed Authorization and MCP Apps all now ride on it. Note the sequence carefully: MCP Apps was proposed on November 21, 2025 as SEP-1865 and shipped as a standalone extension on January 26, 2026 — this revision formalises the mechanism it uses rather than launching it. Our earlier guide to MCP Apps and interactive UI covers how tools return sandboxed HTML through the ui:// scheme.
09 — AdoptionTwo download numbers that do not agree.
Both organisations behind this release published adoption figures on the same day, and they do not match. The MCP Foundation’s own post says that across its Tier 1 SDKs it is seeing close to half-a-billion downloads a month, with both the TypeScript and Python SDKs individually crossing one billion total downloads. Anthropic’s rollout post reports 400 million monthly SDK downloads at four times year-on-year growth, plus more than 950 MCP servers listed in Claude’s connectors directory.
We are deliberately not reconciling those. Both are primary-sourced, both were published on July 28, 2026, and neither publishes its counting methodology. Our reading — and it is a reading, not a sourced claim — is that they are measuring different populations: one is SDK download volume across all consumers of the Tier 1 packages, the other is a vendor’s own view of the ecosystem it serves. Averaging them would produce a number that neither organisation stands behind. Quote whichever one you need, attribute it to its source in the same breath, and say which is which.
The more durable signal is not the headline count anyway. It is that the ecosystem is now large enough that a protocol owner and its largest implementer publish materially different telemetry on the same day and both are plausible. That is what a maturing infrastructure layer looks like — the same way nobody expects npm-registry download counts and a single cloud vendor’s telemetry to agree about how many people use a JavaScript framework. For where MCP sits relative to the other agent protocols, our map of how MCP fits alongside A2A, ACP and UCP is the wider frame; we also covered what the announced stateless change was expected to break before the final text landed, which is a useful before-and-after read against this one.
10 — ConclusionA protocol that finally looks like the rest of the web.
Stateless is a deployment story first and a protocol story second.
The 2026-07-28 revision is not a feature release. It is a trade: MCP gives up an elegant, connection-oriented interaction model and gets back the ability to run on ordinary infrastructure. Requests carry more. Servers hold less. A round-robin load balancer in front of ephemeral compute is now a supported topology rather than a workaround.
The honest scope of the work: two changes are immediate for anyone who wants the new behaviour — removing the handshake dependency and removing Mcp-Session-Id — and the rest can be scheduled against a minimum 12-month deprecation window. Nothing switched off on July 28. The migration effort also is not uniform: C# leads with backward compatibility, TypeScript costs you a package split, Python costs you a rename, Go costs the least, and Rust is not ready to be planned around.
The forward-looking read is that the interesting problems move up a layer. Once hosting an MCP server is boring, the questions that remain are authorization, metering and attribution — which agent, acting for whom, called which tool, and who pays. The header-routing requirement and the CIMD rework in this same revision both point that way. Teams that treat this release as purely a transport migration will do the work twice; teams that use it as the moment to put a real gateway and identity story in front of their MCP surface will only do it once.