From Aryan Vatsa | Product & Market Analysis
MCP's 2026 Spec Dropped Sessions. What Your Server Must Rebuild by July 2027
On this page
On 28 July 2026 the Model Context Protocol shipped its first revision with breaking changes. Protocol-level sessions, the Mcp-Session-Id header and the initialize handshake are gone. Roots, Sampling, Logging and Dynamic Client Registration are deprecated, with a 12-month minimum before any can be removed. If your company runs an MCP server, the changelog is now a work order, and the first date on it is 28 July 2027.
Key takeaways
- Sessions are removed, not deprecated. The 2026-07-28 MCP changelog removes the Mcp-Session-Id header and the initialize handshake outright (SEP-2567, SEP-2575). Every request now carries its protocol version and client capabilities in a _meta field.
- Four MCP features now have an earliest removal date. Roots, Sampling, Logging and Dynamic Client Registration are Deprecated as of 2026-07-28. The registry lists their earliest removal as the first revision released on or after 28 July 2027.
- Nothing on the old version breaks yet. The SDK maintainers wrote on 29 June 2026 that "nothing breaks today, and nothing breaks on July 28 either." New clients fall back to the initialize handshake when they reach a 2025-11-25 server.
- The stateless transport itself has no spec deadline. Only the deprecated features carry a date. Being stateless by mid-2027 is a product decision, and we argue below that you should take it anyway.
What changed in the MCP spec on 28 July 2026
The 2026-07-28 Model Context Protocol specification removed protocol-level sessions, the Mcp-Session-Id header and the initialize handshake. It replaced server-initiated requests with Multi Round-Trip Requests, made two routing headers mandatory, and deprecated Roots, Sampling, Logging and Dynamic Client Registration. Deprecated features keep working for at least 12 months, so the earliest removal is a revision released on or after 28 July 2027.
That is the revision in 60 words.
The release candidate was locked on 21 May 2026, with a ten-week window for SDK and client implementers to test it. Beta SDKs followed on 29 June. The final text landed on 28 July, with all four Tier 1 SDKs (TypeScript, Python, Go and C#) speaking it on launch day.
We covered the politics of MCP as a standard in the piece on the standards fight behind the agent stack. This post is the engineering bill that standard just sent you, written for the head of platform or integrations engineering at a SaaS vendor that runs an MCP server. Two sections are flagged for the product leader they report to.
Sessions are gone, and stateless means something specific
The changelog's first major entry removes sessions from the Streamable HTTP transport. It adds a consequence that is easy to skim past: tools/list, resources/list and prompts/list "no longer vary per-connection". If your server tailors its tool catalogue to who connected, that logic has to move.
The Mcp-Session-Id header is removed (SEP-2567)
The spec's answer for state is that servers use "explicit, server-minted handles passed as ordinary tool arguments". "Dropping the protocol-level session doesn't force your application to be stateless," the maintainers wrote in the release post.
Google's engineers described the old design's failure. With three pods behind a load balancer, a client's second request lands on a different pod and gets a 400 Session Not Found. Their post says the GitHub MCP Server has "already upgraded to this spec and completely removed Redis session storage". That is Google's account of GitHub's work, not GitHub's own, as the limitations section notes.
The handshake is replaced by _meta and server/discover (SEP-2575)
The initialize and notifications/initialized exchange is removed. Every request now carries io.modelcontextprotocol/protocolVersion and clientCapabilities in _meta.
Servers MUST implement a server/discover RPC advertising supported versions, capabilities and identity. Clients MAY call it up front. A version mismatch now returns UnsupportedProtocolVersionError rather than a failed handshake.
Resumability and the GET endpoint are gone too
SSE stream resumability, the Last-Event-ID header and event IDs are removed. A broken response stream now loses the in-flight request, and clients MUST re-issue it as a new request with a new request ID.
Idempotency is the hidden line item in this migration. A tool that creates a ticket, charges a card or sends an email will now do so twice whenever a stream drops, and nothing in the protocol stops it.
The standalone HTTP GET endpoint and resources/subscribe are replaced by a single subscriptions/listen stream that clients opt into per notification type. The exposure of each endpoint is a separate question, covered in the analysis of the MCP design flaw that exposed up to 200,000 servers.
Server-initiated requests become Multi Round-Trip Requests
Under the 2025-11-25 revision a server could, while handling a call, reach back to the client with roots/list, sampling/createMessage or elicitation/create. That needed an open stream. The 2026-07-28 revision replaces all three with one pattern, Multi Round-Trip Requests, or MRTR (SEP-2322).
The server returns an interim result with resultType set to "input_required" and an inputRequests field listing what it needs. The client retries the original request with inputResponses attached. Every result now carries a required resultType field, and clients MUST treat results from older servers that omit it as complete. The design goal, in Google's words, is that "any server instance behind your load balancer can pick up the retry request". The server carries what it needs to resume in an opaque requestState string that the client echoes back.
requestState is now a security surface
Descope's reading, a vendor source but a careful one, notes that requestState "needs integrity protection too" because the retry "can land on any instance in your fleet". The spec's session-hijacking guidance carries over as state-handle hijacking, and servers MUST NOT treat possession of a handle as authentication.
The rule is the one we set out in the piece on agent credentials versus user impersonation. A handle proves continuity, not identity. Sign it, bind it to the verified user, and reject it when the two disagree.
Elicitation flows break, and OAuth state goes with them
The revision removes notifications/elicitation/complete and the elicitationId field from URL-mode elicitation, both added in 2025-11-25. Descope flags a knock-on effect: some SDK documentation had shown elicitationId used as the OAuth state parameter. Your server now mints its own state, stores it against the verified user and checks it at the callback. Cloudflare calls this "a breaking change from the old way of doing elicitations".
Roots, Sampling and Logging now have a removal date
Until July 2026 MCP had no formal policy for retiring a feature. The 2026-07-28 revision adopts one (SEP-2596), with three states, Active, Deprecated and Removed, and a floor of twelve months between the first two and the third. The registry page carries six rows. Four started their clock on 28 July 2026.
| Feature | Deprecated by | Deprecated in | Migration path | Earliest removal |
|---|---|---|---|---|
| Roots | SEP-2577 | 2026-07-28 | Tool parameters, resource URIs or server configuration. | First revision released on or after 2027-07-28. |
| Sampling | SEP-2577 | 2026-07-28 | Integrate directly with LLM provider APIs. | First revision released on or after 2027-07-28. |
| Logging | SEP-2577 | 2026-07-28 | stderr for stdio; OpenTelemetry for observability. | First revision released on or after 2027-07-28. |
| Dynamic Client Registration | PR #2858 | 2026-07-28 | Client ID Metadata Documents. | First revision released on or after 2027-07-28. |
| includeContext "thisServer" / "allServers" | SEP-2596 | 2025-11-25 | Omit the field or use "none". | Follows Sampling. |
| HTTP+SSE transport (2024-11-05) | SEP-2596 | 2025-03-26 | Streamable HTTP. | Three months after SEP-2596 reaches Final. |
Transcribed from modelcontextprotocol.io on 11 October 2026. Note the last row: the old HTTP+SSE transport has a far shorter runway than the twelve-month floor, because it was deprecated before the policy existed.
"Earliest removal" is eligibility, not a date
Read the wording carefully, because the trade press has not. A feature "becomes eligible for removal in the first specification revision released as Current on or after the window elapses". The actual removal is "a Core Maintainer decision taken during release preparation and may happen later".
Removal from the specification "does not oblige an SDK to drop the feature from releases". And the floor can be cut to ninety days for a feature with a published security advisory or documented exploitation. So 28 July 2027 is the earliest a removal can appear in a spec text. It is not the day your server stops working, and not a promise that anything happens then.
Our position: plan to the floor anyway. A date that can only move later is the most useful kind of deadline a platform team ever gets.
The hidden cost of Sampling's exit
Two of the three deprecations are cheap. Roots moves to tool parameters or server configuration. Logging moves to stderr for stdio or OpenTelemetry for anything hosted, and the spec now fixes trace-context keys in _meta (SEP-414).
Sampling is different. Under Sampling your server asked the client's model to generate text on the client's credentials. Under the replacement your server integrates "directly with LLM provider APIs". Descope puts the consequence well: servers "now hold their own provider credentials", a new class of downstream secret to store, rotate and revoke. That is a procurement and security conversation before it is an engineering one, and it moves inference cost onto your side of the ledger, a dynamic we examined in the piece on integration depth as a moat.
The OAuth changes are smaller than the headlines, except one
Authorization is where, in the maintainers' words, "implementers spend most of their integration time". So "tightened OAuth" in coverage of this revision has caused alarm. Read against the six authorization SEPs, it is mostly misplaced.
Authorization servers SHOULD include the iss parameter per RFC 9207 and clients MUST validate it (SEP-2468). Clients declare an OpenID Connect application_type at registration, so localhost redirects for desktop apps stop being rejected (SEP-837). Client credentials are bound to the issuing authorization server (SEP-2352). Refresh tokens are requested through the offline_access scope (SEP-2207). On scope step-up the client requests the union of existing and new scopes (SEP-2350). The .well-known discovery path is clarified (SEP-2351).
Descope's verdict is that for a mature setup "these are configuration checks rather than migration steps". We agree, with one caution. The RC post says a future version will expect clients to reject responses that omit iss. If your authorization server does not emit it today, fix that one first.
Dynamic Client Registration gives way to CIMD
The one authorization change with a clock on it is the deprecation of Dynamic Client Registration (RFC 7591) in favour of Client ID Metadata Documents, or CIMD. DCR "remains available for backwards compatibility with authorization servers that do not support Client ID Metadata Documents", in the changelog's words.
Under DCR your authorization server mints a client_id for each new client. Under CIMD the client_id is a URL that your authorization server fetches to read a metadata document. Identity comes from control of a domain, not a registration record, so your authorization server acquires a new policy decision: which domains do you accept a client ID from? Cloudflare describes a preference order of pre-registered clients, then CIMD, then DCR as fallback, and says DCR "is slated for removal after summer 2027".
Enterprise-Managed Authorization is the new expectation
This is the product leader's section. The revision formalises an extensions framework (SEP-2133), and Enterprise-Managed Authorization, or EMA, becomes an official extension alongside MCP Apps and Tasks. EMA lets a user who signed into an MCP client through their company's identity provider reach your server without a fresh consent flow.
Descope reports that EMA reached stable status in June 2026 and names Atlassian's Rovo MCP rollout as a production example, which we have not verified independently. Enterprise buyers already ask how non-human access is governed, as we set out in the analysis of agent identity and non-human access, and EMA support will be on the security questionnaire within a year.
The MCP server migration checklist, by spec section
Twelve items, each tied to the changelog entry that creates it. "Spec deadline" is what the specification actually binds. Where it says none, the forcing function is commercial, not normative.
| # | Spec change | What your server must do | Spec deadline | Owner |
|---|---|---|---|---|
| 1 | Sessions removed (SEP-2567) | Delete every read of Mcp-Session-Id. Make the three list endpoints identical across connections. Mint explicit handles for cross-call state. | None. Required the day you advertise 2026-07-28. | Platform engineering |
| 2 | Handshake removed (SEP-2575) | Read version and capabilities from _meta per request. Implement server/discover. Return UnsupportedProtocolVersionError on mismatch. | None, as above. | Platform engineering |
| 3 | Routing headers (SEP-2243) | Require Mcp-Method and Mcp-Name on POSTs. Reject header-body mismatches with -32020. | None, as above. | Platform and gateway |
| 4 | Resumability removed (SEP-2575) | Drop Last-Event-ID handling. Make every tool safe to call twice, or key side effects on an idempotency token. | None. Highest-risk item. | Every tool owner |
| 5 | GET stream replaced (SEP-2575) | Move list-changed notifications to subscriptions/listen with per-type opt-in. | None. | Platform engineering |
| 6 | MRTR (SEP-2322) | Rewrite elicitation as input_required results. Emit resultType on every result. Sign and user-bind requestState. | None. Breaking for elicitation. | Platform and security |
| 7 | Cacheable lists (SEP-2549) | Return ttlMs and cacheScope ("public" or "private") on list and read results. Return tools in a deterministic order. | None, but the fields are required. | Product and platform |
| 8 | Roots, Sampling, Logging deprecated (SEP-2577) | Move roots to config. Replace sampling with direct provider calls and own the credentials. Log to stderr or OpenTelemetry. | Earliest removal: revision on or after 2027-07-28. | Platform, security, procurement |
| 9 | Six authorization SEPs | Emit iss. Accept application_type. Key credentials by issuer. Support offline_access, scope step-up and .well-known discovery. | None. Configuration checks. | Identity team |
| 10 | DCR deprecated (PR #2858) | Support Client ID Metadata Documents on your authorization server. Decide which client domains you accept. | Earliest removal: revision on or after 2027-07-28. | Identity and product |
| 11 | Tasks extension (SEP-2663) | If you used experimental tasks, migrate to tasks/get polling and tasks/update. tasks/list is removed. | None. Breaking for 2025-11-25 tasks users. | Platform engineering |
| 12 | Error codes (SEP-2164 and policy) | Return -32602 for a missing resource. Renumber HeaderMismatch to -32020 and UnsupportedProtocolVersion to -32022. | None. | Platform engineering |
What a product leader owns in this list
Items 7 and 10 are product decisions wearing engineering clothes. The cacheScope field forces you to say, per catalogue, whether a tool list is safe to share across users. If your catalogue differs by plan tier or tenant, "public" is wrong and you have just found a packaging question. The accepted-domains rule under CIMD is a partner policy, not a config value.
Item 3 is an opportunity. Once Mcp-Name travels in a header, your gateway can rate-limit, meter and bill per tool without parsing JSON. Our survey of 13 SaaS incumbents' MCP servers found rate limits among the least consistently documented properties, and the header makes a per-tool limit cheap to build and publish. Item 4 is the one we would escalate: a write-capable tool that is not idempotent is a double-posting bug waiting for a dropped connection, which sharpens the question of which agents get write access at all.
Sequence it in three passes, not one cutover
Cloudflare's guidance is the most concrete published so far. Run a strict stateless route alongside the sessionful one, move features across, drain sessions, then remove the legacy path during the deprecation period. Their endpoint "accepts both the new protocol and stateless requests from 2025 Streamable HTTP clients".
The SDKs support that shape. In the Go SDK the transport accepts 2026-07-28 only when you set Stateless to true; leave it unset and clients negotiate down to 2025-11-25. The TypeScript v2 handler serves both revisions from one endpoint, and the maintainers call the v1-to-v2 move "mostly mechanical", with a codemod. A Python v2 server also answers both. The TypeScript team committed to v1.x fixes and security updates "for at least six months" after v2 ships.
Pass one is the SDK upgrade with the new revision switched off. Pass two turns it on behind a separate route and watches error rates. Pass three retires the session code. We would not combine the first two, because one is a dependency change you can roll back in minutes and the other is a protocol change your clients will notice.
Where this argument is weakest
A post that tells you to rebuild by 2027 owes you the places where that date is softer than it sounds.
The spec sets no date for the stateless transport itself
Sessions and the handshake were removed in the new revision, but the 2025-11-25 revision still exists, new clients still fall back to it, and nothing we read states when support for it ends. The lifecycle page defers revision lifecycles to a separate versioning guide we did not read. "By 2027" is our planning choice, anchored on the deprecation floor, not a date the specification sets for statelessness.
The cost claims are qualitative
Google and Cloudflare both argue that stateless servers are cheaper to run. Neither publishes a measured latency or cost delta. Cloudflare's one hard figure, "thousands of requests per second" and "billions of tool calls", describes its own Code Mode server running an unofficial stateless mode before the spec existed. Treat the economics as plausible, not demonstrated.
Two things we could not verify
Google's 5 August post still calls the revision a "release candidate", eight days after the maintainers published it as final. We follow the maintainers. The claim that GitHub's MCP server dropped Redis comes only from Google's post, and GitHub's changelog archive did not render the relevant month for us. DCR's deprecation is recorded against a pull request number rather than a SEP, while the lifecycle policy says deprecation requires a SEP. That may be housekeeping. It may also get relitigated.
Frequently asked questions
What changed in the MCP 2026-07-28 specification?
The 2026-07-28 revision removed protocol-level sessions, the Mcp-Session-Id header and the initialize handshake, so every request now carries its protocol version and capabilities in a _meta field. It replaced server-initiated requests with Multi Round-Trip Requests, made Mcp-Method and Mcp-Name headers mandatory, added required caching fields, and deprecated Roots, Sampling, Logging and Dynamic Client Registration under a new twelve-month lifecycle policy.
Is MCP stateless now?
At the protocol level, yes. The 2026-07-28 revision removed the session header and handshake, so any request can reach any server instance without shared storage. The maintainers stress that this does not force your application to be stateless. A server that needs state across calls mints an explicit handle from a tool and the model passes it back as an ordinary argument on later calls.
When will Roots, Sampling and Logging be removed from MCP?
They are deprecated as of 2026-07-28 and remain fully functional during the window. The deprecated features registry lists their earliest removal as the first specification revision released on or after 28 July 2027. That date is eligibility, not a commitment: removal is a Core Maintainer decision taken during release preparation and may happen later. SDKs are not obliged to drop a feature when the spec does.
Do existing MCP servers break on the new spec?
No. The SDK maintainers wrote that "nothing breaks today, and nothing breaks on July 28 either." A client on the 2026-07-28 revision falls back to the initialize handshake when it reaches a 2025-11-25 server. Breakage happens only when a server starts advertising the new revision without implementing its requirements, or when a client and server disagree on version, which returns UnsupportedProtocolVersionError.
How do I migrate an MCP server to the 2026-07-28 spec?
Upgrade to an SDK that speaks the revision, keep the new protocol switched off, and ship that first. Then expose a stateless route alongside the sessionful one, remove every read of Mcp-Session-Id, implement server/discover, add the routing headers and caching fields, rewrite elicitation as Multi Round-Trip Requests, and make write tools idempotent. Drain sessions and retire the legacy route last.
Where to start this week
One search and one meeting.
The search is for the string Mcp-Session-Id across every repository that touches your MCP server, including the gateway and any analytics code that keys on it. The hit count is your scope estimate, and it is usually larger than the team expects.
The meeting is thirty minutes with whoever owns your authorization server, with two questions on the agenda. Does it emit the iss parameter today? Does it support Client ID Metadata Documents, or have a plan to? Both answers go on a page with 28 July 2027 at the top. Everything else in the checklist can wait for the next planning cycle. Those two cannot.
Earlier coverage of MCP on this site
How MCP became the standard is in the standards fight that decides the agent stack. What incumbents have actually shipped is in the survey of 13 SaaS vendors' MCP servers.
References
- Model Context Protocol, Key Changes, specification 2026-07-28, read 11 October 2026. Used for every removal, replacement, deprecation and SEP number.
- David Soria Parra and Den Delimarsky, The 2026-07-28 Specification, MCP blog, 28 July 2026. Used for download figures, the stateless framing and SDK availability.
- David Soria Parra and Den Delimarsky, The 2026-07-28 MCP Specification Release Candidate, MCP blog, 21 May 2026. Used for the RC date, the ten-week window and the authorization SEPs.
- Felix Weinberger, Max Isbey and Den Delimarsky, Beta SDKs for the 2026-07-28 MCP Spec Release Candidate Are Here, MCP blog, 29 June 2026. Used for SDK behaviour and the v1 support statement.
- Model Context Protocol, Feature Lifecycle and Deprecation Policy and Deprecated Features registry, read 11 October 2026. Used for the twelve-month floor, the eligibility wording and the registry table.
- Kurtis Van Gent and Alan Blount, Scaling AI Agent Infrastructure with the MCP Stateless updates, Google Developers Blog, 5 August 2026. Used for the load-balancer example and the GitHub claim.
- Matt Carey, The next generation of MCP, Cloudflare Blog, 6 August 2026. Used for the migration sequence, the CIMD preference order and DCR timing.
- Descope, What the July 2026 MCP Spec Revision Means for Identity, 31 July 2026. Vendor source. Used for the authorization reading, requestState integrity and EMA status.
This source base is entirely the protocol's own documents plus three vendor posts. No independent party has measured what the migration costs a production team, so every effort statement here is qualitative.
Related reading