MCP 2026-07-28: What Changed and How to Migrate
A practical guide to MCP's stateless 2026 specification, including per-request metadata, version discovery, multi-round trips, subscriptions, extensions, and legacy compatibility.
On this page
Version verifiedChecked August 25, 2026 against MCP 2026-07-28. Review method.
The short version
- The July 2026 release removes MCP protocol sessions and the initialization handshake; version and capabilities are now required on every request.
- Modern servers expose version discovery, while dual-era clients can probe and fall back to the 2025-and-earlier initialization model.
- InputRequiredResult replaces unsolicited server-to-client requests, and subscriptions/listen replaces the old HTTP GET and resource subscription flow.
- Tasks is now an official extension, while Roots, Sampling, and Logging are deprecated but remain functional during the deprecation window.
The 2026-07-28 Model Context Protocol specification begins a new compatibility era. Earlier releases evolved the original session-oriented architecture; this release removes that architecture from the modern core. There is no initialization negotiation handshake, no MCP protocol session, and no assumption that a server can send a fresh JSON-RPC request to a client whenever it needs more information.
As of this article’s August 25, 2026 review, 2026-07-28 is the current authoritative specification S054. The project published a release candidate in May S053 and the final release announcement on July 28 S058. The changes are deliberate responses to routing, scaling, retry, and interoperability problems—not a cosmetic schema revision.
The companion current host-client-server architecture guide explains how those changes affect each role without treating a logical client relationship as a protocol session.
This guide focuses on what implementers need to change. For the wider context, read the practical introduction to MCP, the MCP vs function calling comparison, or the primary-source protocol history.
Why this release is a protocol boundary
The official versioning and compatibility specification gives the two eras names S056:
- Modern means protocol version 2026-07-28 or later. Version, identity, and capabilities are per-request metadata.
- Legacy means protocol version 2025-11-25 or earlier. The client establishes a session through
initializeandnotifications/initialized. - Dual-era means an implementation deliberately supports both behaviors.
That vocabulary is more precise than “old server” and “new server.” A recently maintained product may still implement a legacy protocol version for compatibility, and a modern client does not automatically know how to speak legacy MCP.
The dividing line is not stdio versus HTTP. Both eras can use stdio, and legacy MCP also used Streamable HTTP. The difference is how protocol context is established and how follow-up interaction works.
| Design question | Legacy MCP | Modern MCP |
|---|---|---|
| How is version chosen? | During initialize | Declared on every request |
| Where are capabilities known? | Negotiated for the session | Carried as per-request metadata |
| Is there an MCP session ID? | Streamable HTTP may use Mcp-Session-Id | No protocol-level session |
| Can the server initiate JSON-RPC requests? | Yes, for features such as sampling and elicitation | No; it returns an input-required result |
| Where do Tasks live? | Experimental core in 2025-11-25 | Optional official extension |
Sessions are replaced by self-contained requests
The 2026 key changes remove initialize, notifications/initialized, protocol-level sessions, and the Streamable HTTP Mcp-Session-Id header S055. Every request instead carries its protocol version and client capabilities in _meta. Clients should identify themselves on each request, and servers should identify themselves in results.
This changes the infrastructure assumptions around MCP:
- Any conforming request contains enough protocol context to be routed and interpreted independently.
- A load balancer does not need session affinity merely to preserve MCP negotiation state.
- Retrying a request is no longer tied to recovering a protocol session.
- Results from
tools/list,prompts/list, and similar discovery calls cannot silently vary because of connection-local negotiation state.
Stateless MCP does not ban application state. A server may persist data, run a long-lived task, or mint a handle that the client passes back as an ordinary tool argument. The important constraint is that state is explicit at the application layer rather than hidden in a protocol session S061.
For migration, first locate every place that creates, stores, refreshes, or routes by MCP session ID. Then separate real application state from protocol bookkeeping. Preserve the former behind explicit identifiers; remove the latter from the modern path.
initialize negotiated the protocol version and capabilities before normal requests [S026]. Streamable HTTP could establish a stateful session [S038]. Keep that code only inside a clearly marked legacy compatibility path.Version discovery replaces handshake negotiation
Modern servers must implement server/discover. Its result allows a client to learn which protocol versions and capabilities the server supports. A client may call discovery before any other operation, but it may also send its preferred operation immediately.
If the server does not support the request’s version, it returns UnsupportedProtocolVersionError and lists supported versions. The client should choose a mutually supported version and retry, or give the user an actionable error when there is no overlap S056. On HTTP, the protocol version is carried both in request metadata and the MCP-Protocol-Version header.
Optional extensions are negotiated separately through the capabilities map. Extension identifiers use qualified names; for example, MCP Apps uses io.modelcontextprotocol/ui S059, and Tasks uses io.modelcontextprotocol/tasks S060. Do not infer extension support from the core version alone.
A dual-era client needs a controlled fallback strategy:
- stdio: probe with
server/discover. A recognized modern result or modern protocol error keeps the client in modern mode. A non-modern error or timeout can trigger fallback toinitialize. - Streamable HTTP: attempt a modern request. A recognized modern JSON-RPC error identifies a modern server; an unrecognized
400 Bad Requestcan trigger the legacy path. - Cache the detected era for the server process or HTTP origin, then re-probe if the assumption fails.
Do not fall back after every error. Authentication failures, invalid parameters, and application errors are not evidence that a server is legacy. The official compatibility rules use recognized modern error bodies to avoid turning a real failure into an ambiguous second protocol attempt.
Modern-only clients and legacy-only servers are not expected to interoperate. Similarly, a legacy client has no standard way to “fall forward” to a modern-only server. A modern server should therefore name its supported versions when rejecting an initialize request, giving an older client the best diagnostic it can display.
Multi-round trips replace server-initiated requests
Earlier MCP allowed a server to initiate requests such as roots/list, sampling/createMessage, or elicitation/create. That fit a bidirectional session, but it complicated stateless routing: the original responder became a new requester on a connection that infrastructure had to preserve.
The 2026 core replaces that behavior with the Multi Round-Trip Requests (MRTR) pattern S062. A server that cannot complete a request returns an InputRequiredResult. Its inputRequests describe the roots, model sampling, or user elicitation it needs. The client obtains the requested input and retries the original request with that information.
Every modern result has a resultType:
completemeans the operation has finished normally.input_requiredmeans the server needs another round trip before it can finish.
For compatibility, a client treats results from earlier-protocol servers that omit resultType as complete. Modern client code, however, should model input-required as a real state rather than an error or a partially populated success.
MRTR keeps initiative with the original client and gives the host a natural point to apply policy. It can refuse a sampling request, constrain roots, or ask the user before supplying sensitive information. A server can preserve its own correlation data in explicit requestState rather than depending on a protocol session.
Migration requires more than renaming methods. Convert every server-to-client request handler into three pieces: an input request in InputRequiredResult, host-side fulfillment with consent checks, and a retry path for the original operation. Test cancellation, duplicate retries, and expired application handles.
Streaming and subscriptions have new mechanics
Modern MCP remains capable of streaming over HTTP. “Stateless” does not mean “one buffered response only.” It means the stream belongs to an explicit request or subscription rather than to a negotiated protocol session.
The 2026 transport specification makes several important changes S057:
- The old Streamable HTTP GET endpoint is removed.
resources/subscribeandresources/unsubscribeare replaced bysubscriptions/listen.subscriptions/listenis a long-lived POST-response stream. Clients opt into change categories, and notifications carry a subscription identifier.- Request-scoped progress and logging notifications stay on the response stream for the request they describe.
- SSE event IDs,
Last-Event-ID, resumability, and message redelivery are removed. If a response stream breaks, the in-flight request is lost and the client issues a new request.
This makes retry semantics visible. A client must decide whether an operation is safe to repeat, and a server should design mutating operations with explicit idempotency or application-level deduplication where appropriate. Reopening a transport stream is not proof that the previous side effect did not occur.
The release also requires Mcp-Method on Streamable HTTP requests and Mcp-Name when the method addresses a named tool, prompt, or resource (tools/call, prompts/get, or resources/read). Those fields help intermediaries route and observe traffic without decoding the entire JSON body. Treat them as routing metadata, not as a substitute for validating the actual request.
Tasks, caching, and deprecations
Tasks were experimental in the 2025-11-25 core S050. In 2026 they became an official extension with a redesigned lifecycle: clients poll with tasks/get, can provide input through tasks/update, and no longer use tasks/list S060. An implementation must advertise and negotiate the Tasks extension; supporting the 2026 core does not imply Tasks support.
The release also adds explicit caching behavior. Results from tools/list, prompts/list, resources/list, resources/read, and resources/templates/list carry ttlMs and cacheScope; deterministic tool ordering is recommended to improve client and model prompt-cache reuse S055. This is operationally useful only if cache keys include the protocol version, relevant capabilities, identity, authorization context, and request inputs. Statelessness must not cause one principal’s discovery result to leak to another.
Several features are deprecated, not removed:
- Roots, Sampling, and Logging remain functional but should not be adopted by new implementations.
- Some Sampling
includeContextvalues are deprecated. - OAuth Dynamic Client Registration remains for compatibility but is deprecated in favor of Client ID Metadata Documents.
The project’s feature lifecycle policy defines Active, Deprecated, and Removed states and normally requires a minimum twelve-month deprecation window S065. Its transition rules give shorter eligibility windows to features already described as deprecated before the policy, including HTTP+SSE. Existing software does not need to delete deprecated behavior immediately. It does need an inventory, an exit plan, and tests that keep compatibility code from contaminating the modern path.
Authorization is still required for protected remote servers. Removing MCP sessions does not remove OAuth or user consent, and the Enterprise-Managed Authorization extension remains available for managed environments S063.
A migration checklist that catches real failures
Use this sequence rather than changing wire fields opportunistically:
- Declare the target. Choose modern-only or dual-era support. Document the exact dated versions; do not advertise “MCP compatible” without a version.
- Separate the code paths. Put legacy initialization, session IDs, and fallback transport behavior behind an explicit adapter. Keep the modern request path self-contained.
- Build request metadata centrally. Attach the required version and client capabilities, the recommended client identity, and any advertised extensions consistently. On HTTP, validate the corresponding protocol header.
- Implement discovery and errors. Add
server/discover, supported-version reporting, retry selection, and useful no-overlap diagnostics. - Replace server-initiated calls. Model
completeandinput_required, fulfill input through the host, and retry the original operation safely. - Rebuild subscriptions. Move long-lived changes to
subscriptions/listen; keep request-scoped notifications on their request stream; remove assumptions about SSE replay. - Move Tasks behind extension negotiation. Update polling and client-input flows, and decide what happens when a peer lacks the extension.
- Audit state and caches. Replace protocol-session state with explicit handles, scope cached results correctly, and define retry/idempotency behavior for side effects.
- Test a compatibility matrix. Cover modern/modern, dual-era/modern, dual-era/legacy, version mismatch, broken streams, duplicate retries, denied input, and unsupported extensions.
- Keep security decisions in the host. A protocol upgrade must not silently broaden roots, credentials, model access, or user-data exposure.
The safest rollout is observable and reversible: log detected era and negotiated version, measure fallback frequency, canary the modern path, and keep legacy support only as long as real peers require it. The 2026 design reduces hidden connection state, but successful migration depends on making version, application state, retries, and permissions explicit everywhere the old session once carried them implicitly.