Skip to main content
← Blog

What Changes in MCP 2026-07-28: A Before-and-After Walkthrough

The next Model Context Protocol revision is the largest since launch. Here's what actually changes between the 2025-11-25 stable spec and the 2026-07-28 release candidate, flow by flow.

mcp protocol oauth architecture

The Model Context Protocol’s next revision, version 2026-07-28, is the largest change to the protocol since it launched. The release candidate was locked on May 21, 2026, and the final specification is targeted for July 28, 2026. The current stable version remains 2025-11-25, and everything described here is a release candidate — the spec text can still shift during the validation window, so treat the “after” side as forward-looking rather than shipped.

Rather than march through a changelog, this post walks the changes the way you’d actually encounter them: as differences in how a connection behaves, how requests get routed, how authorization works, and what you stop depending on. Each section pairs a “before” with an “after.”

A quick note on version labels before we start: MCP versions are date-stamped to mark the last date backward-incompatible changes were made. So 2026-07-28 is a version identifier, not a publish date. The two strings — 2025-11-25 and 2026-07-28 — are the only two that matter for this post.

The architectural root: a stateless core

Almost every other change in this release descends from one decision — MCP becomes stateless at the protocol layer. Two Specification Enhancement Proposals carry most of the weight. SEP-2575 removes the initialize / notifications/initialized handshake, and SEP-2567 removes protocol-level sessions and the Mcp-Session-Id header.

In the stable spec, a connection opens with a two-step handshake that exchanges protocol version, capabilities, and identity once, then the server issues a session ID that pins the client to one server instance for the life of the connection. Capabilities are remembered server-side, list endpoints like tools/list can vary per connection, and a gateway routes by session affinity. Cross-call state lives implicitly in the session — hidden from the model, tied to the instance, and lost on restart.

The release candidate removes all of that. There is no handshake; a new server/discover RPC, which servers MUST implement, advertises supported versions and capabilities, and clients MAY call it up front. There is no session ID, so any request can hit any instance and list endpoints no longer vary per connection. When a server needs to carry state across calls, it mints an explicit, server-issued handle — a basket_id, a browser_id — and the model passes it back as an ordinary tool argument. State becomes visible to the model, composable across tools, and durable across instance changes.

The practical payoff is operational. A stateful handshake plus sticky sessions meant horizontal deployments needed shared session stores and gateways doing deep packet inspection to route correctly. Round-robin load balancing was off the table and every restart dropped live sessions. The stateless core makes a remote MCP server behave like ordinary HTTP infrastructure: plain round-robin balancing, free autoscaling, harmless restarts.

Connection lifecycle, before and after. The handshake and session ID disappear; per-request context moves into _meta, and cross-call state becomes an explicit, model-visible handle.

Connection lifecycle, before and after

Where context lives now: the _meta channel and header routing

If the handshake is gone, where does the per-request context go? Into _meta. Under the release candidate, every request carries its protocol version, client info, and client capabilities inline under keys such as io.modelcontextprotocol/protocolVersion, /clientInfo, and /clientCapabilities. A version mismatch returns an UnsupportedProtocolVersionError.

This is the change with the most direct security relevance. In the stable spec, _meta is a peripheral extension channel — present, but not required for core operation, since the real context was negotiated once at the handshake and held server-side. In the release candidate, _meta becomes load-bearing: it carries identity and capability data on every single request. That makes validating it mandatory rather than defensive. Anything reading trust-relevant signals out of _meta is now reading untrusted, attacker-influenceable input on every call, and needs to treat it accordingly.

Routing changes to match. SEP-2243 requires two standard headers on Streamable HTTP POST requests — Mcp-Method and Mcp-Name — so infrastructure can route and rate-limit on the named operation without inspecting the request body. A gateway no longer needs to parse JSON-RPC to know what a request is doing. The same SEP adds custom headers from tool parameters via x-mcp-header. Rate limiting shifts naturally toward per-operation and per-token limits, since in a stateless world the token is the only identifier that persists across instances.

There’s a companion change worth knowing: SEP-2549 adds response caching. Results of the list and read endpoints now carry a ttlMs freshness hint and a cacheScope of "public" or "private", borrowed from HTTP Cache-Control. With list endpoints now connection-independent, caching is how clients avoid re-fetching the same tool catalogue on every call.

Request routing and the _meta channel. Context moves from a once-per-session negotiation to a per-request payload; gateways route on headers instead of session affinity.

Request routing and the _meta channel, before and after

Authorization, hardened toward OAuth and OIDC

The release candidate tightens MCP’s authorization model to align more closely with how OAuth 2.0 and OpenID Connect are actually deployed. The maintainers describe this as six SEPs working together, motivated by MCP’s single-client, many-server shape. Worth flagging: the exact authorization SEP set is the least settled part of the release candidate, so treat specific numbers here as provisional.

The core flow doesn’t invert. On a first connection the client still makes a token-less request, receives a 401 whose WWW-Authenticate header points at the server’s resource metadata, discovers the authorization server, runs the OAuth flow, and returns with a bearer token. What changes is what’s mandatory and where the new checkpoints sit.

Several requirements harden from SHOULD toward MUST. Servers MUST implement OAuth 2.0 Protected Resource Metadata (RFC 9728) so clients can discover the right authorization server. Clients MUST implement Resource Indicators (RFC 8707), sending a resource parameter that binds each token to the specific MCP server it’s meant for — which is what stops a malicious server from harvesting a token intended for a different one. Registration shifts to prefer OAuth Client ID Metadata Documents over Dynamic Client Registration.

The one genuinely new step in the flow is issuer validation. The client records the authorization server’s expected issuer before redirecting, and the authorization server returns an iss parameter (RFC 9207) on the callback. The client validates that iss against the recorded value before sending the authorization code to any token endpoint. A mismatch — or an absent iss when the server advertises support — means reject. This is the defense against mix-up attacks, and it moves from advisory toward an enforced checkpoint. If you run an authorization server today and it doesn’t emit iss, that’s the first thing to fix.

First-connection authorization, before and after. The handshake drops out, resource metadata and the resource parameter harden to MUST, and a new iss-validation gate appears before the token exchange.

First-connection authorization, before and after

Once a client has a token and cached metadata, subsequent requests skip discovery entirely — request with a bearer token, get a response, with a 401 or 403 insufficient_scope challenge branch when a token is stale or under-scoped. That fast path is the same in both versions; the difference is that the stateless model re-sends capability context in _meta on each call rather than relying on a negotiated session.

Cached-request flow, before and after. The happy path is unchanged; the visible difference is that _meta now travels on every request.

Cached-request flow, before and after

What to stop depending on

The release candidate adopts a formal feature lifecycle and deprecation policy (SEP-2596) — the first time MCP has had one. It defines three states (Active, Deprecated, Removed) and guarantees a minimum twelve-month window between a feature being marked Deprecated and becoming eligible for removal, measured from the revision that deprecates it. A security-driven expedited removal can shorten that, but must still allow at least ninety days.

That guarantee matters because of what gets deprecated. SEP-2577 deprecates Roots, Sampling, and Logging, and the older HTTP+SSE transport is reclassified as Deprecated. None of these stop working on July 28 — they remain in the spec for at least the twelve-month window. But new work should target the replacements: roots become tool parameters or resource URIs, sampling means calling your LLM provider directly from server code (or using the new Multi Round-Trip Requests pattern when client-side sampling is genuinely needed), and logging moves to stderr or OpenTelemetry.

Tasks gets a different treatment. It shipped as an experimental core feature in 2025-11-25, but production use prompted moving it into an official extension (SEP-2663). The redesign replaces blocking tasks/result with polling via tasks/get, adds tasks/update for client-to-server input, removes tasks/list (it can’t be scoped safely without sessions), and lets servers return task handles unsolicited. Anyone who built against the experimental API will need to migrate to the new lifecycle.

Deprecated capabilities and the Tasks move. Each deprecated mechanism on the left, its replacement on the right, with the twelve-month window noted.

Deprecated capabilities and the Tasks move

What to do about it

If you maintain an MCP server, the stateless core is the change to plan for: read protocol version and capabilities from _meta, implement server/discover, attach ttlMs and cacheScope to your list and read results, and make sure your gateway routes on Mcp-Method and Mcp-Name rather than session affinity. If you run an authorization server, start emitting iss. If you used the experimental Tasks feature, plan the move to polling.

None of it is urgent today. The current finalized version is still 2025-11-25, the deprecation policy buys at least twelve months for anything being phased out, and the release candidate is a target rather than a shipped spec. The right move now is to read the draft changelog, follow the SDK validation work, and avoid building hard dependencies on anything the release candidate deprecates. The ten-week window between the lock and the July 28 final exists precisely so that, by the time the spec ships, your SDK does most of the heavy lifting for you.