This MCP revision
is a subtraction
Protocol revisions usually accumulate capabilities. The 2026-07-28 release mostly subtracts them: of the nine major changes, five are removals, a separate section moves four more features to Deprecated, and the only two new RPCs both replace something taken out. What was cut is precisely what separated MCP from an ordinary HTTP interface specification.
Where MCP has been
The Model Context Protocol, or MCP, is an open protocol for connecting AI applications to external tools and data sources through one interface. Its revisions are identified by dates such as 2026-07-28, rather than by 1.0 or 2.0 numbering, and this is the fifth. Understanding why it warrants separate attention begins with the shape the first four revisions gave the protocol.
Legacy and Modern are the specification's own terms, and the line between them falls at this revisionThose earlier revisions followed a familiar path: establish how messages travel, then add mechanisms on top. The 2024-11-05 revision used HTTP+SSE as its transport, the layer that carries protocol messages over the network. SSE kept a long-lived HTTP connection open so that a server could continue pushing messages to a client. The largest change to that foundation came with 2025-03-26, when Streamable HTTP replaced HTTP+SSE and the older transport became deprecated.
The carrier changed, but the operating premise did not. A client connected and performed a handshake, an opening exchange in which both sides agreed on identity, protocol version and supported capabilities. In earlier MCP revisions, the client made initialize as its first call. The server could then assign a session marker that tied later requests together and allowed it to retain state shared across them. Each request depended on what had already been agreed.
That premise remained through the 2025-06-18 compatibility boundary and the previous 2025-11-25 revision. For clients using versions earlier than 2025-06-18, a server MAY treat a request without the version header as 2025-03-26. The sequence still belonged to the same protocol era: connect, establish shared context once, and rely on it afterward.
The specification gives the two eras its own names. Legacy covers protocol versions that establish a session with an initialize handshake, meaning 2025-11-25 and earlier. Modern covers protocol versions that convey version, identity, and capabilities as per-request metadata, meaning 2026-07-28 and later. Per-request metadata places the necessary context on every request instead of relying on an agreement made at connection time.
The dividing line is not a feature. It is whether the server has to remember what the client said before.
Why this revision reads differently
The official release description says 2026-07-28 moves MCP to a stateless core, while hardening authorization and graduating official extensions. The shift to a stateless core produces the longest chain of changes, and it is the through-line here.
A stateful server must remember information associated with a client across requests. Keeping that memory available can require a shared session store or stateful load balancing, where the load balancer repeatedly sends one client to the same server because that server still holds the relevant session state. A stateless server remembers nothing between requests because each request carries what it needs.
That makes an MCP server deployable as an ordinary HTTP workload. Requests can reach any available instance without first recovering shared session state or being pinned to the instance that handled the previous call. It also makes serverless deployment, where code runs for each request rather than remaining resident, a viable fit. The same applies at the edge, where a service runs across nodes closer to users and consecutive requests may land on different nodes.
The cost follows from removing the server's dependence on prior exchanges. Protocol-level sessions and the initialize handshake no longer anchor later calls. A stream can no longer rely on the protocol's previous resumability mechanism. More consequentially, the server loses the ability to initiate a request toward the client.
Several capabilities depended on that direction of travel. Sampling allowed a server to ask the client to run a model call on its behalf, avoiding the need for the server to hold model credentials. Roots allowed the server to ask which directories or files it could access. Elicitation allowed the server to pause execution while the client collected additional input from the user. These mechanisms made MCP more than an interface through which a client calls server methods.
For Sampling, the stated migration path is Integrate directly with LLM provider APIs. The model call therefore moves out of the client-mediated protocol flow, and each server making such calls must connect to a provider API and hold the required credentials itself.
The revision consequently changes both deployment and protocol scope. MCP becomes easier to operate across interchangeable HTTP instances because requests no longer depend on retained client state. At the same time, it narrows from a bidirectional protocol in which either side could initiate requests into a tool catalogue and a calling convention, with RPC methods such as tools/call defining what the client may invoke.
The document also formalizes how change will be managed. It introduces a feature lifecycle policy, a deprecation window of at least twelve months, a deprecation registry and a compatibility matrix spanning the Legacy and Modern eras. Deprecated features still exist and continue to work, but new implementations should not adopt them, and they become eligible for later removal under the specification's process. That leaves the concrete boundary of the new core to examine: what was removed, and what replaced it.
Removal and deprecation are separate. The changelog keeps Major changes and Deprecated in distinct sections: five of the nine major changes are removals that take effect now, while four features move to Deprecated, meaning they still work and new implementations should not adopt them. The two counts do not add up to one number.
"Earliest removal" is not a removal date. All four deprecations read 2027-07-28, which marks when a feature becomes eligible for removal. Whether it is actually removed is a Core Maintainer decision taken during release preparation and may happen later.
Authorization aligns with OAuth 2.0 and OIDC. The official wording is production OAuth 2.0 and OIDC, not 2.1.
Five of the nine major changes are removals
MCP is settled infrastructure now. The official figures are monthly SDK downloads past 400M, a 4x increase this year, and over 950 MCP servers in Claude's connectors directory. At that size a spec revision does not just alter implementation detail; it changes how a great many clients and servers connect to each other.
The official blog compresses the release into three moves: a stateless core, hardened authorization, and official extensions graduating into a versioned framework. The table below groups the nine major changes by what they do. The final row, the error-code renumbering, comes from "Minor changes" and is included because it determines which constants implementers have to update.
| Removed or changed | Replaced by | What it means for implementers |
|---|---|---|
Protocol-level sessions and the Mcp-Session-Id headerSEP-2567 | Explicit, server-minted handles passed as ordinary tool arguments where cross-call state is needed | Shared session storage and sticky load balancing can come out; list endpoints no longer vary per-connection |
The initialize / notifications/initialized handshakeSEP-2575 | Version, identity and capabilities travel in each request's _meta | No opening negotiation; version mismatches surface per request as UnsupportedProtocolVersionError |
The HTTP GET endpoint, resources/subscribe and resources/unsubscribeSEP-2575 | subscriptions/listen, one long-lived stream with explicit per-type client opt-in | A single change-notification channel; on stdio the client MUST re-send its subscription after a reconnect |
SSE resumability, message redelivery and Last-Event-IDSEP-2575 | nothing A broken stream loses the in-flight request; the client MUST re-issue it under a new id | Long-running work can no longer ride one connection; it moves to Tasks-extension polling |
ping, logging/setLevel and notifications/roots/list_changedSEP-2575 | Log level set per request via io.modelcontextprotocol/logLevel in _meta | Servers MUST NOT emit notifications/message for requests that did not include that field |
| Server-initiated requests SEP-2322 · labeled a breaking change | MRTR: return an InputRequiredResult; the client re-sends the original request with inputResponses under a new id | Every elicitation, sampling and list-roots path is rewritten; requestState needs integrity protection |
| Experimental tasks inside the core protocol SEP-2663 | The official io.modelcontextprotocol/tasks extension, tasks/result replaced by tasks/get polling plus tasks/update | Clients must handle two result shapes; tasks/list is gone |
| Results with no explicit type marker SEP-2322 | Every result carries resultType, either complete or input_required | Where an earlier-protocol server omits the field, clients MUST treat the result as complete |
| No up-front way to advertise versions or capabilities SEP-2575 · an addition, not a removal | server/discover, which servers MUST implement, advertising supported protocol versions, capabilities and identity | Clients MAY query first; on stdio it doubles as the probe for which generation the server implements |
| No error-code allocation policy a minor change, not one of the nine | -32000 to -32019 stays implementation-defined; -32020 to -32099 is reserved for the spec | Three codes renumbered: HeaderMismatch to -32020, MissingRequiredClientCapability to -32021, UnsupportedProtocolVersion to -32022 |
Previous MCP coverage on this site was about using it: what breaks in production, one DNS rebinding vulnerability in each of three official SDKs traced to the same default configuration, and the tool-token cost of wiring MCP into a Claude Code harness. This piece takes a different axis, which is where the protocol itself is going.
Sessions leave the protocol
Earlier Streamable HTTP was a stateful arrangement, meaning the server had to remember what a client had said before. That design required the server to hold session state, so multi-instance deployment meant either shared session storage or sticky load balancing, and it fit poorly with serverless and edge, where adjacent requests from one client may land on different instances.
All of that is gone. The server exposes a single HTTP endpoint that accepts POST, and every JSON-RPC message from the client is its own POST. Protocol version, client identity and client capabilities are no longer settled by an opening handshake; they travel in each request's _meta field, and the server returns its own identity in each result's _meta. The spec is blunt about it: There is no negotiation handshake.
Every request now declares its own version and the server accepts or rejects each one independently. An unsupported version comes back as UnsupportedProtocolVersionError together with the list of versions the server does support, from which the client picks one and retries.
Statelessness is not free. Cross-call state that used to hang off the session has to become explicit data: the server mints a handle and passes it back as an ordinary tool argument for the client to carry into the next call. List endpoints can no longer vary their contents by connection either.
MCP gave up the part that made it distinct
Laid out, the deprecation list is not made of edge features. Sampling, Roots and elicitation share one property: the request travels from server to client. That is what made the protocol bidirectional, with either end able to ask for something, and it is what separated MCP from an ordinary HTTP interface specification.
| Feature | What it did | Disposition | Official migration path |
|---|---|---|---|
| Sampling | The server asks the client to run a model completion on its behalf, so the server need not hold model credentials | Deprecated SEP-2577 | Integrate directly with LLM provider APIs |
| Roots | The server asks the client which directories or files it may access | Deprecated SEP-2577 | Pass directories or files via tool parameters, resource URIs, or server configuration |
| Logging | The client sets a log level and the server returns log messages over the protocol | Deprecated SEP-2577 | Log to stderr for stdio transports; use OpenTelemetry for observability |
| Server-initiated requests | The server pauses mid-execution to issue elicitation, sampling or list-roots requests to the client | changed outright labeled a breaking change | Use the MRTR pattern (below) |
Server-initiated requests were not deprecated. They were changed outright. The MRTR page carries the spec's own label, This is a breaking change., and states that servers MUST use the new pattern because The previous pattern of server-initiated requests is no longer supported. The transport page marks the same thing as a behavioral change relative to 2025-03-26 through 2025-11-25, revisions in which servers could send their own JSON-RPC requests on SSE streams. This revision says MUST NOT.
The client sends a request
Only prompts/get, resources/read and tools/call may take this path.
The server answers "more input needed"
Rather than calling the client, it returns an InputRequiredResult whose resultType is input_required. Its inputRequests field lists what the client must satisfy, with values limited to elicitation, sampling and list-roots; requestState is an opaque string meaningful only to the server.
The client does the work
It gathers input from the user, or runs a completion on the server's behalf.
It re-sends the original request under a new id
Answers go in inputResponses and requestState is echoed back verbatim. The spec is explicit that the two calls are independent requests and the JSON-RPC id MUST differ.
The server rebuilds context and finishes
The stated goal is a pattern that works without requiring a shared storage layer across server instances or requiring stateful load balancing, and further that it allows servers to request additional information without maintaining any server-side state.
Once state passes through the client it becomes an attack surface. Servers MUST treat requestState as attacker-controlled input. Where it influences authorization, resource access or business logic, servers MUST protect its integrity with HMAC or AEAD and MUST reject state that fails verification. To bound replay, servers SHOULD carry the authenticated principal, a short expiry and an identifier for the originating request inside the integrity-protected payload. These measures do not guarantee single use; a server that needs at-most-once consumption MUST enforce that invariant itself.
A broken stream loses the request
The loss of server-initiated requests is half the consequence. The other half shows up when a connection drops. SEP-2575 removes SSE resumability and message redelivery along with SSE event IDs: a broken response stream loses the in-flight request, and the client MUST re-issue it as a new request with a new request ID.
Last-Event-ID are removed together; a dropped stream cannot be resumedsubscriptions/listen is the only change-notification channelLegacy traffic arriving at such a server has defined handling. A Last-Event-ID header is ignored, since streams are not resumable; an Mcp-Session-Id header is ignored too, and the server neither mints nor echoes session IDs.
With one response stream per request, cancellation semantics get cleaner. Closing that stream is itself the cancellation signal and the server MUST treat it as cancellation, a transport-level disconnect the spec calls unambiguous. This revision of the core protocol defines no client-to-server notifications over Streamable HTTP at all; notifications/cancelled survives only on stdio.
tasks/get until terminalLong-running work leaves the core protocol for the official Tasks extension, identified as io.modelcontextprotocol/tasks (SEP-2663). The redesign swaps blocking for polling: tasks/result gives way to tasks/get, a new tasks/update carries client input mid-flight, and tasks/list is removed.
When a server judges that a request will run long, it answers with a CreateTaskResult identified by resultType: "task", carrying a taskId, an initial status, ttlMs and a suggested pollIntervalMs. The task is durably created before the response is sent, which makes the taskId a durable handle: a client that disconnects or restarts resumes polling with the same identifier.
Ordinary change notifications go through subscriptions/listen. The client opts in explicitly through a filter with four fields, toolsListChanged, promptsListChanged, resourcesListChanged and resourceSubscriptions. The server MUST NOT send types the client has not explicitly requested, and MUST send notifications/subscriptions/acknowledged as the first message, reflecting the subset it agreed to honor.
Request-scoped notifications do not travel on that channel. notifications/progress and notifications/message flow only on the response stream of the request they relate to. On stdio, after a connection is terminated and re-established, the client MUST re-send subscriptions/listen, because the server holds no subscription state across reconnections.
The middle tier becomes a first-class consumer
Beyond how the protocol connects internally, this revision carries a group of changes aimed at the infrastructure sitting in front of it. Reverse proxies and gateways stand ahead of the real service, handling forwarding, routing, rate limiting and authentication. They used to need the JSON-RPC body parsed before they could tell which method or tool a request invoked. SEP-2243 mirrors selected fields into HTTP headers so these components can route and inspect requests without parsing the body.
Every POST MUST carry MCP-Protocol-Version. Mcp-Method carries the method name on all requests; Mcp-Name carries params.name or params.uri on tools/call, resources/read and prompts/get. These headers are REQUIRED for compliance, not an optimization.
Tool parameters can be mirrored too. A server MAY annotate a parameter in a tool's inputSchema with x-mcp-header, and the client then mirrors that value into an Mcp-Param-{name} header. The spec's own example is a tool that executes SQL on Google Cloud Spanner, annotating its region parameter with x-mcp-header: "Region" so the request carries Mcp-Param-Region: us-west1.
Mirroring creates two copies of the same fact, so a server that processes the body MUST compare the mirrored headers against their corresponding body values. The stated reason is direct: to prevent different components in the network from relying on different sources of truth, such as a load balancer routing on the header value while the MCP server executes on the body value. An intermediary enforcing policy on mirrored headers, for instance routing or rate-limiting by tenant, SHOULD additionally verify that the version indicated by MCP-Protocol-Version requires header–body validation, and SHOULD reject the request rather than trust values it cannot confirm.
| New on the client side | What it does |
|---|---|
ttlMs | A freshness hint in milliseconds, letting clients cache and poll less |
cacheScope | public or private, controlling whether shared intermediaries may cache the response |
tools/list ordering | Servers SHOULD keep it deterministic; the spec says the purpose is client-side caching and improving LLM prompt cache hit rates |
| OpenTelemetry keys | traceparent, tracestate and baggage in _meta, propagating the call-chain identifier downstream (SEP-414) |
Under SEP-2549, results from five methods now carry two required cache fields: tools/list, prompts/list, resources/list, resources/read and resources/templates/list. Both complement the existing listChanged notifications rather than replacing them. Observability moves the same direction: trace conventions enter the spec while the Logging feature is deprecated, with stderr or OpenTelemetry as the migration path.
From automatic registration to self-hosted metadata
The official summary of this revision's authorization work is that it now aligns with production OAuth 2.0 and OIDC deployments. Enterprise identity systems are built on those standards, so an MCP server connecting to Entra or Okta no longer needs workarounds. The registration change is more concrete: the spec names three client registration mechanisms and a four-step priority order.
Pre-registered information exists → use it
Use the pre-registered client ID and credentials. Such credentials are inherently specific to one authorization server.
The authorization server advertises CIMD → use CIMD
The signal is client_id_metadata_document_supported in its metadata. Under Client ID Metadata Documents the client publishes its metadata at an HTTPS URL and uses that URL as its client ID.
Only RFC 7591 is supported → fall back to DCR
Dynamic Client Registration is now Deprecated and remains only for backwards compatibility.
Nothing else available → prompt the user
The client asks the user to enter the information by hand.
The change targets a relationship that is common in MCP and unusual elsewhere: This addresses the common MCP scenario where servers and clients have no pre-existing relationship. The client hosts its metadata at an HTTPS URL and that URL becomes the client_id. It MUST use the https scheme and contain a path component; the document MUST include at least client_id, client_name and redirect_uris; and the client_id value inside MUST match the document URL exactly.
Credentials keep a hard boundary. Under SEP-2352, clients using pre-registered credentials, or persisting credentials obtained through DCR, MUST bind them to the issuing server's issuer. When the authorization server changes, the client MUST NOT reuse credentials issued by a different server and MUST register again.
A client ID based on a metadata document is a self-hosted HTTPS URL that the authorization server resolves on demand, which makes it portable across authorization servers: No re-registration is needed when the authorization server changes.
Two further repairs tighten issuer verification. Under SEP-2468, authorization servers SHOULD include the iss parameter specified by RFC 9207, and a client MUST validate a present iss against the recorded issuer before redeeming the authorization code. Under SEP-837, a client performing DCR MUST specify an appropriate application_type: omitting it yields the OIDC default of web, which can conflict with native-style redirect URIs, while desktop applications, mobile apps, CLI tools and locally hosted web applications reached through localhost SHOULD use native.
Deprecation and compatibility, written into policy
For those removals and four deprecations to be absorbable, there has to be a rule set saying when something may go, how long existing implementations have to migrate, and what happens when old and new meet. This revision writes all three into the spec. SEP-2596 adopts a feature lifecycle policy defining the Active, Deprecated and Removed states, together with a minimum twelve-month deprecation window.
Currently deprecated features are collected in the registry. Roots, Sampling, Logging and Dynamic Client Registration all carry First revision released on or after 2027-07-28, meaning the earliest a removal could land is the first revision released on or after that date. The spec attaches a qualifier: The earliest removal marks when a feature becomes eligible for removal; the actual removal is a Core Maintainer decision taken during release preparation and may happen later.
The registry is a derived view; the per-feature deprecation notices and the changelog entries remain the normative records. Its Removed section is currently empty: No features have been removed under this policy yet.
| Feature | Deprecation SEP | Deprecated in | Earliest removal |
|---|---|---|---|
| Roots | SEP-2577 | 2026-07-28 | first revision released on or after 2027-07-28 |
| Sampling | SEP-2577 | 2026-07-28 | as above |
| Logging | SEP-2577 | 2026-07-28 | as above |
| Dynamic Client Registration | PR #2858 | 2026-07-28 | as above |
includeContext: "thisServer" / "allServers" | SEP-2596 | 2025-11-25 | differs follows Sampling |
| HTTP+SSE transport | SEP-2596 | 2025-03-26 | differs three months after SEP-2596 reaches Final |
The last two rows carry different terms from the first four, so this table cannot be read as one 2027-07-28 deadline.
The second policy piece is the compatibility matrix. The spec first sets out three generations: Modern for 2026-07-28 and later, carrying version, identity and capabilities as per-request metadata; Legacy for 2025-11-25 and earlier, establishing a session through an initialize handshake; and Dual-era for implementations supporting both. The matrix enumerates seven combinations, two of which fail.
| Client | Server | Outcome |
|---|---|---|
Modern | Modern | works server/discover is optional; a version mismatch surfaces as UnsupportedProtocolVersionError and the client retries with a mutually supported version |
Modern | Legacy | fails The server may reject with an implementation-defined error, stay silent, or process an era-ambiguous method under legacy semantics. On stdio, clients SHOULD send server/discover first to fail deterministically |
Dual-era | Modern | works The client stays modern |
Dual-era | Legacy | works Falls back to initialize, and on HTTP possibly further to the deprecated HTTP+SSE transport |
Legacy | Modern | fails On stdio the server rejects initialize with a JSON-RPC error; on HTTP the request lacks required headers and is rejected with 400 Bad Request. Legacy clients have no fall-forward mechanism. |
Legacy | Dual-era | works The server answers initialize and serves the client under the negotiated legacy revision |
Legacy | Legacy | works Under the legacy revision, out of scope for this one |
The working bridge is a Dual-era server, which selects its behavior from how the client opens: a request carrying per-request _meta is handled statelessly, an initialize request follows legacy semantics, and the server MAY serve both generations concurrently on the same endpoint or within the same process.
Clients also have to probe which generation they are talking to. Era is a property of the server rather than of a single request, so clients SHOULD cache the result: for the lifetime of the server process on stdio, per origin on HTTP. An HTTP probe attempts a modern request first, and on 400 Bad Request the client SHOULD inspect the response body before falling back, because modern servers also use that status for an unsupported version, a missing required capability and header-validation failures; a recognized modern error in the body means the server is modern and the client should retry rather than downgrade. On stdio the probe is server/discover.
The process itself is pinned down too. SEP-1850 formalizes the SEP workflow, with proposals as markdown files in a seps/ directory, numbering derived from the PR, and status managed through PR labels.
A server supporting only modern versions SHOULD include the protocol versions it supports in any error returned to an initialize request. Since a legacy client cannot fall forward, that error may be the only useful explanation it can present to the user.
Four product pieces, and the shape of the release
Everything above is the open specification. What Anthropic shipped on its own product surface is a separate layer, and the official blog gives it its own section. There are four pieces.
MCP Apps let servers render interactive UI directly in the conversation, so users can see what a connector is doing and work with it inline without switching tabs. Enterprise-managed auth lets admins provision connectors for a whole organization through their identity provider: authorize once, users inherit access through existing IdP groups, and it is connected on first login, which the blog calls zero-touch setup for the end user. Observability for connector developers gives published connectors a dashboard for tracking adoption, diagnosing errors and latency, and breaking down usage by product. MCP tunnels, a research preview, connect Claude to MCP servers inside a private network with no inbound firewall rules, no public endpoints, and no IP allowlisting on the origin.
Claude lists over 950 MCP servers in the connectors directory, used by millions of people every day. Applied at that scale, each removal above means implementations across the ecosystem have to move with it.
Read together, the three point one way: MCP is narrowing its own definition to a tool catalog and a calling convention, and at the same time writing its boundaries and its pace into rules an engineering plan can rely on.