TL;DR
- The MCP
2026-07-28specification is the largest revision since the protocol launched. The release candidate was locked on May 21, 2026, and the final spec ships on July 28, 2026 (MCP Blog). - The headline change is a stateless core: no
initialize/initializedhandshake (SEP-2575) and noMcp-Session-Idheader (SEP-2567). Every request now carries its own protocol version, client identity, and capabilities on_meta. - This is a breaking change at the transport layer for remote servers, but not at the feature layer.
roots,sampling, andloggingare deprecated, not removed, with a guaranteed minimum 12-month window (SEP-2596). - Streamable HTTP is not going away. What changes is that the connection is no longer the unit of session, so a remote server can finally run behind a plain round-robin load balancer.
- Three required operability headers (
Mcp-Method,Mcp-Name, plus W3Ctraceparent) make MCP traffic routable and traceable like any normal HTTP API. - Authorization gets six hardening SEPs. The one to ship first is SEP-2468: validate the
issparameter per RFC 9207 to block OAuth mix-up attacks. - The time pressure is real. If you operate a remote MCP server, you have until late July to externalize session state, send the routing headers, and audit your auth code. After July 28 the new spec is the bar clients and registries check against.
- This article is based on a release candidate. The architectural shape is final, but exact spec text and SDK APIs can still shift during the validation window — treat the code below as illustrative patterns, not copy-paste production code.
What You Will Learn Here
- Why MCP is moving to a stateless model, and which production failure modes it fixes.
- Exactly what changes on the wire: the removed handshake, the removed session ID, and the
_metaenvelope. - How server-initiated work survives without a long-lived connection (the Multi Round-Trip pattern).
- The three required headers and what they unlock for routing, caching, and tracing.
- The six authorization SEPs, and which one is most urgent.
- What the Extensions framework, MCP Apps, and Tasks mean for your server.
- A concrete before/after migration of a stateful remote server into a stateless one.
- A week-by-week migration plan and the mistakes that bite teams first.
- What PMs should take away about timing and risk.
This guide is for engineers who build or operate remote MCP servers (HTTP transport), and for PMs who need to scope the migration. If you only ship a local stdio server for a single desktop client, most of this matters less — but the deprecations still apply to you.
Why MCP Is Changing
The old design had two problems, and the release candidate is the technical answer to both (MCP Blog).
Problem 1: a stateful handshake fights production HTTP. Before this release, every session opened with initialize from the client, initialized back from the server, and an Mcp-Session-Id header echoed on every subsequent request. The server held that session in memory. The original stateless proposal, SEP-1442 (opened September 8, 2025), named the consequence directly: a simple stateless load balancer cannot be used, because it would route a client’s requests to different backend servers that do not share the session. In practice that meant sticky sessions, a shared session store, or a gateway doing deep packet inspection — and a single server restart blew up every in-flight session.
Problem 2: a year of operational debt. There was no standard caching metadata, no standard tracing format, no written deprecation policy, and “experimental” features like Tasks living inside the core spec with no rules for how they graduate.
The 2026 MCP roadmap (published March 9, 2026) committed to four work areas — transport scalability, agent communication, governance maturation, and enterprise readiness. The 2026-07-28 release maps onto all four.
Editorial note (inference, not spec): the through-line of this release is “make agentic state explicit and make the wire boring.” Agentic applications are stateful; the protocol carrying them does not need to be. HTTP has worked this way for two decades.
The Five Pillars
It is easy to drown in the 20-plus SEPs. They cluster into five load-bearing changes (MCP.Directory analysis):
┌──────────────────────────────────────────────────────────┐
│ MCP 2026-07-28 — five pillars │
├──────────────────────────────────────────────────────────┤
│ 1. Stateless core no handshake, no session id │
│ 2. Operability layer routing headers, ttl, tracing │
│ 3. Extensions MCP Apps + Tasks + framework │
│ 4. Auth hardening 6 SEPs aligning with OAuth/OIDC │
│ 5. Deprecation policy 12-month window, written rules │
└──────────────────────────────────────────────────────────┘
Hold these five in your head and the spec gets a lot shorter.
Pillar 1: The Stateless Core
This is the change that touches every remote server.
- SEP-2575 removes the
initialize/initializedhandshake. - SEP-2567 removes the
Mcp-Session-Idheader.
Instead of negotiating once and remembering, every request now carries its own protocol version, client identity, and negotiated capabilities inside the _meta object on the JSON-RPC envelope. When a client genuinely needs to discover what a server can do, it calls a new server/discover method — which is itself stateless and cacheable.
Here is the operational payoff, in the release candidate’s own framing: a remote MCP server that previously needed sticky sessions, a shared session store, and deep packet inspection at the gateway can now run behind a plain round-robin load balancer, route on a header, and let clients cache tools/list responses.
BEFORE (2025-11-25) AFTER (2026-07-28)
client client
│ initialize ───────────► server │ tools/call (+ _meta) ─► LB ─► any replica
│ ◄──────────── initialized │ │ ◄──────────────────────────── result
│ Mcp-Session-Id: abc123 │ tools/call (+ _meta) ─► LB ─► any replica
│ tools/call (echo abc123) │ │ ◄──────────────────────────── result
│ server holds session in memory │ no session; any replica answers
│ sticky routing required │ round-robin is fine
What you must do
If your server keeps anything per session in process memory — a shopping basket ID, a browser/session handle, a workflow cursor — you have to externalize it into a client-held opaque handle. The server mints it; the client passes it back on the next call; the server reconstructs state from it. This is the same pattern as a signed cookie or an opaque pagination token.
Server-Initiated Work Without a Connection
The thing people miss: in the old model, server-to-client calls (asking the user a question mid-tool-call) needed a long-lived SSE stream. With no session, that mechanism changes.
The replacement is the Multi Round-Trip pattern (SEP-2322):
- The server answers a
tools/callwith anInputRequiredResultcontaining aninputRequestsarray and an opaquerequestState. - The client gathers the inputs, then re-issues the call with
inputResponsesand echoes the samerequestStateback. - The server reconstructs whatever it needs from
requestState. The protocol never holds a connection open.
client server (any replica)
│ tools/call "book_flight" ────────►│
│ ◄──── InputRequiredResult │ needs: confirm date
│ { inputRequests, requestState }
│ (ask the user / agent) │
│ tools/call + inputResponses ─────►│ rebuilds from requestState
│ + requestState (verbatim) │
│ ◄──────────────── final result │
Migration trap:
requestStateis opaque to the client but is not a secret. The server signs or encrypts whatever needs to survive the round-trip; the client echoes it verbatim. Treating it like a session ID (storing it server-side, keying memory off it) reintroduces exactly the statefulness the redesign removed.
Pillar 2: Operability — Routing, Caching, Tracing
Three SEPs make MCP traffic behave like normal HTTP from a routing and observability standpoint.
- Required headers (SEP-2243): every Streamable HTTP request must include
Mcp-Method(e.g.tools/call) andMcp-Name(the tool or resource name). Load balancers route on these without parsing JSON-RPC bodies. - Caching metadata (SEP-2549):
tools/list,resources/list, andresources/readresults carryttlMsandcacheScope, modeled on HTTPCache-Control. Clients get a defined way to cache; servers get a defined way to invalidate. - Distributed tracing (SEP-414): W3C Trace Context (
traceparent,tracestate,baggage) is propagated by default, so OpenTelemetry collectors see MCP end-to-end with no glue code.
A routable request after 2026-07-28 looks like this:
POST /mcp HTTP/1.1
Host: server.example.com
Authorization: Bearer <token>
Mcp-Method: tools/call
Mcp-Name: search_issues
Mcp-Protocol-Version: 2026-07-28
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
{"jsonrpc":"2.0","id":"req-1","method":"tools/call",
"params":{"name":"search_issues","arguments":{"query":"crash"},
"_meta":{"clientInfo":{"name":"claude","version":"3.5"}}}}
The routing headers are easy to overlook and required. Gateways that validate MCP traffic will reject requests missing Mcp-Method or Mcp-Name, so an old client SDK that does not send them will simply stop working through a strict gateway.
Pillar 3: Extensions, MCP Apps, and Tasks
MCP gets a real extension system. Extensions are identified by reverse-DNS IDs, live in their own ext-* repos with their own maintainers, version independently of the core spec, and are negotiated through an extensions map in the capability advertisement. Two ship official on day one:
- MCP Apps (SEP-1865): a server can declare an HTML interface that the client renders inside a sandboxed iframe. Tools declare which UI templates they use ahead of time so the client can prefetch and security-review them. The rendered UI talks back over the same JSON-RPC protocol — no new wire format.
- Tasks (migrated out of experimental core): long-running work. The server answers a
tools/callwith a task handle; the client drives it viatasks/get,tasks/update, andtasks/cancel. Task creation is server-directed. Notetasks/listwas removed — without sessions, “list tasks across clients” has no well-defined scope.
Why this matters beyond features (inference): the extensions framework is the governance answer to the long tail of requests — rich UIs, durable jobs, agent handoff — that do not belong in a wire spec. A protocol stays useful only if its evolution surface is bounded.
Pillar 4: Authorization Hardening
Six SEPs sharpen MCP’s OAuth 2.1 / OpenID Connect story. The highlights:
| SEP | What it does |
|---|---|
| SEP-2468 | Clients must validate the iss parameter on every auth response per RFC 9207 (mix-up attack defense). |
| SEP-837 | Clients declare an OIDC application_type during Dynamic Client Registration (most providers refuse DCR without it). |
| SEP-2352 | Registered client credentials are bound to the authorization server’s issuer. |
| SEP-2207 | Refresh-token request semantics clarified for OIDC-style providers. |
| SEP-2350 | Scope accumulation during step-up authentication is now defined. |
| SEP-2351 | Well-known discovery uses a stable suffix so metadata lives at predictable paths. |
If you only act on one, make it SEP-2468. OAuth mix-up attacks have been exploited in the wild for years, and treating MCP servers as protected resources means MCP clients inherit that threat model. If you already built an authenticated server (for example following Building an MCP Server with Auth0 Login in Go), this is an additive audit, not a rewrite.
Also Worth Knowing: Schemas and Error Codes
- JSON Schema 2020-12 (SEP-2106): tool
inputSchemaandoutputSchemamove to draft 2020-12. You get composition (oneOf,anyOf,allOf), conditionals (if/then/else), and$ref/$defs. Output schemas are no longer forced into an object wrapper. Auto-dereferencing external$refURIs is prohibited and validators must bound depth/time — both are denial-of-service guards. - Error code change (SEP-2164): the MCP-custom
-32002“missing resource” code is replaced by standard JSON-RPC-32602Invalid Params. Generic JSON-RPC tooling now works without an MCP-specific code table.
Deprecations, Not Removals
The release candidate is firm: no feature is removed in 2026-07-28. Three are deprecated with documented replacements, and the lifecycle policy (SEP-2577 + SEP-2596) guarantees a minimum 12 months between Deprecated and Removed.
| Deprecated | Replacement |
|---|---|
roots | Tool parameters, resource URIs, or server configuration |
sampling | Direct LLM provider API integration |
logging | stderr for stdio; OpenTelemetry for structured observability |
SDK code that calls roots/list on July 29 still gets a valid response. Do not break your own API surface on finalization day — migrate at your SDK’s pace.
A Concrete Migration
Here is the shape of the work for a stateful remote server. The example is a tool that adds an item to a shopping basket — the canonical “I kept state in the session” case. The code is illustrative pseudocode (TypeScript-flavored) to show the pattern, not a specific SDK API.
Before: state lives in the server process
// 2025-11-25 style: the server remembers the basket per session.
const baskets = new Map<string, Basket>(); // keyed by Mcp-Session-Id
server.tool("add_to_basket", async (args, ctx) => {
const basket = baskets.get(ctx.sessionId) ?? newBasket();
basket.items.push(args.item);
baskets.set(ctx.sessionId, basket); // breaks if the next request hits another replica
return { content: [{ type: "text", text: `Basket has ${basket.items.length} items` }] };
});
The problem: baskets is in-process memory keyed by a session ID. Behind a load balancer, the next request can land on a different replica that has never seen that basket.
After: the client holds an opaque handle
// 2026-07-28 style: no session. State travels as a signed, opaque handle.
server.tool("add_to_basket", async (args, ctx) => {
// Reconstruct prior state from the handle the client passed back (if any).
const basket = args.basketHandle
? decodeAndVerify(args.basketHandle) // server-signed; tamper-evident
: newBasket();
basket.items.push(args.item);
// Mint a fresh opaque handle for the client to echo on the next call.
const basketHandle = signAndEncode(basket);
return {
content: [{ type: "text", text: `Basket has ${basket.items.length} items` }],
structuredContent: { basketHandle }, // JSON Schema 2020-12: any JSON value is fine
};
});
The state is now externalized. Any replica can serve any request because the truth travels with the client. If the basket grows large, store it in Redis/Postgres and let the handle be the key (plus a signature) rather than embedding the whole object — the protocol does not care, as long as no replica needs sticky routing.
And the deployment simplifies
BEFORE AFTER
┌────────────┐ ┌────────────┐
│ Gateway │ parses JSON-RPC, │ Gateway │ routes on Mcp-Method/
│ (sticky) │ pins session→replica │ round-robin│ Mcp-Name header
└─────┬──────┘ └─────┬──────┘
│ always replica A │ any replica, any request
┌────▼────┐ ┌─────────┐ ┌─────▼───┐ ┌─────────┐ ┌─────────┐
│replica A│ │replica B│ │replica A│ │replica B│ │replica C│
│ baskets │ │ (empty) │ │ stateless autoscale freely │
└─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘
A Week-by-Week Migration Plan
Adapted from the release candidate’s guidance. The RC is locked; the architecture is final.
- Now (June): read the draft spec. Inventory which of your servers hold session state and decide where to externalize each piece. Audit your auth code against the six auth SEPs — start with SEP-2468.
- June–July: rebuild against the RC SDKs as they land (Tier 1 SDKs — TypeScript, Python, C#, Java, Swift — are expected to ship RC support inside the validation window). Verify your client of choice (Claude Desktop, Cursor, Claude Code, VS Code, ChatGPT) sends
Mcp-MethodandMcp-Name. - July: deploy a stateless variant of a remote server behind a plain HTTP load balancer. Measure it: does it autoscale? Does a rolling deploy break in-flight tool calls? If you previously held connections open for server-initiated input, port to Multi Round-Trip.
- July 28 and after: flip your declared protocol version to
2026-07-28. Keep deprecated features (roots,sampling,logging) functional — do not remove them for at least 12 months.
Migration Mistakes to Avoid
- Storing session state in the server process. The new contract expects you to externalize per-session data into a client-held opaque handle. Porting a stateful server unchanged will fail behind a load balancer.
- Skipping the routing headers because “the body has the same info.” They are required. Strict gateways reject requests without them.
- Mishandling
requestState. Opaque to the client, signed by the server, echoed verbatim. Not a session ID, not a client-readable structure. - Rushing to remove deprecated features. Deprecated is not removed. You have a 12-month minimum window; do not break your API surface on July 28.
- Assuming Streamable HTTP is dead. It is still the transport. Only the session binding is gone — open/close per request or multiplex, both work.
What This Means for PMs
- It is a dependency risk, not a feature. If your product ships or depends on a remote MCP server, there is non-trivial transport and auth work due before late July. Scope it now.
- The window is generous on features, tight on transport. Deprecated capabilities last 12+ months, but the stateless transport and required headers are the bar clients and registries will check against from July 28.
- The upside is real. After migration, MCP servers autoscale on ordinary infrastructure, route through standard gateways, and trace through OpenTelemetry — lower operating cost and fewer pager incidents.
- It is still a release candidate. The shape is final, but plan for minor spec/SDK churn during the validation window.
Sources
Primary:
- The 2026-07-28 MCP Specification Release Candidate — MCP Blog (May 21, 2026)
- The 2026 MCP Roadmap — MCP Blog (March 9, 2026)
- Exploring the Future of MCP Transports — MCP Blog (December 19, 2025)
- RFC 9207 — OAuth 2.0 Authorization Server Issuer Identification (referenced by SEP-2468)
Governance and analysis:
- MCP Is Growing Up — Agentic AI Foundation (May 27, 2026)
- MCP 2026-07-28: The Stateless Release Candidate, Explained — MCP.Directory
- Is MCP the Future of AI Integration? Roadmap and What’s Next — Knit
Related reading on this site: