On July 28, 2026, the Model Context Protocol (MCP) officially released its final specification, "2026-07-28." At its core is not the addition of metadata fields. Rather, it restructures MCP into a stateless, request/response-style protocol by eliminating the initialize handshake that clients and servers previously performed at connection time, along with the Mcp-Session-Id used over HTTP.
With this revision, each request now carries its own protocol version and capability information. Since any server instance can handle the same request, it becomes easier to remove sticky sessions and protocol-specific shared session stores, and to move to ordinary round-robin configurations. Operationally, MCP has moved away from being a specialized bidirectional connection and closer to a workload that can be handled by existing HTTP infrastructure.
However, this doesn't mean state or security responsibilities have disappeared. State-indicating IDs have moved into tool inputs and outputs, and authorization must now be verified on a per-request basis. Rather than simplifying MCP, this revision decomposes what was previously implicit connection state into explicit data and existing Web standards.
Elimination of initialize and Mcp-Session-Id
In the previous version, 2025-11-25, clients would first send initialize to exchange protocol version, client information, and available capabilities. When a Streamable HTTP server issued an Mcp-Session-Id, clients would attach that same ID to subsequent requests. Running servers across multiple instances could require either routing based on that ID back to the same instance, or a shared state store accessible from all instances.
2026-07-28 removes initialize and notifications/initialized. Protocol version and client capabilities now go into each request's _meta, and over HTTP, the MCP-Protocol-Version header is also used. For clients that want to know the server's supported version or capabilities ahead of time, server/discover has been provided, but it is not something that must always be called prior to actual processing.
| Item | Flow up to 2025-11-25 |
2026-07-28 |
|---|---|---|
| Connection start | Exchange version and capabilities via initialize |
Each request carries the necessary information |
| HTTP session | Resend issued Mcp-Session-Id |
Protocol sessions eliminated |
| Pre-fetching capabilities | initialize response |
Optional server/discover |
| Routing | Depends on connection state or JSON body | Operations identifiable via HTTP headers |
With this change, load balancers can distribute requests to any instance. This makes it easier to avoid configurations where connections get pinned to a failed server, and scaling instances up or down no longer requires consideration of MCP-specific session transfer. The official project reports approximately 500 million monthly downloads across the four Tier 1 SDKs combined, with TypeScript and Python each exceeding 1 billion cumulative downloads. While this isn't a figure showing the number of users, removing horizontal scaling constraints carries significant meaning for developers operating remote MCP at this scale.
Requests Get Lighter, Operational Information Increases
While connection-time state has been reduced, the information available to gateways for decision-making has increased. Streamable HTTP POST requests now require Mcp-Method, and for operations with a target name such as tools or resources, Mcp-Name is also attached. Load balancers, rate limiters, and WAFs can select routing and policy per operation and target without opening the JSON-RPC body. Servers reject requests where the header and body disagree, preventing a situation where inspection and execution end up looking at different operations.
ttlMs and cacheScope have been added to list retrieval and resource reads. The former indicates freshness in milliseconds, while the latter conveys whether something can be placed in a shared cache as public, or must be separated per user as private. It is also recommended that the ordering of tools/list be made deterministic. If the order of tool definitions doesn't change across reconnections, the prompt passed to the LLM also stays stable, making it easier to reuse upstream prompt caching.
Situations where user confirmation or additional information is needed mid-process are handled by Multi Round-Trip Requests (MRTR). Rather than the server continuing to send requests directly to the client, it returns resultType: "input_required" along with inputRequests and a requestState for resumption. The client places the answer into inputResponses and resends the original request. Since the necessary state resides in the payload, the resend destination need not be the same instance as the original.
Long-lived connections haven't disappeared entirely. Notifications for tool list or resource changes have been consolidated into subscriptions/listen, which clients subscribe to. Notifications belonging to a single request, such as progress updates, flow through that request's response stream. This is a design that separates always-open connections from temporary processing, narrowly defining what each stream is for.
Where Authorization Responsibility Moves Under Statelessness
State for things like shopping baskets, browser operations, or long-running processes cannot be eliminated entirely. What the new specification recommends is a method where tools return identifiers such as basket_id or browser_id, which are then passed as ordinary arguments in subsequent calls. This is not about adding a new "state handle type" to MCP. On the wire, it's just an ordinary string, and the application implements state storage, expiration, and access control.
When a state ID is visible to the model, it becomes easier to hand off to another tool, and the same state can be referenced when resuming a conversation. However, that ID also appears in chat logs, copied text, and inputs to sub-agents. SEP-2567 requires authenticated servers to verify the combination of handle and authenticated principal on every call. For servers without authentication, since the handle itself becomes the access right, a minimum of 128 bits of cryptographically secure random data and a finite expiration period are recommended.
The authorization specification has been tightened in the same direction. When an authorization response includes iss, the client must verify that it matches the recorded issuer before exchanging the authorization code. This is a check to prevent OAuth mix-up—where, in environments where a client deals with multiple MCP servers and authorization servers, a response gets mistaken for coming from a different issuer. Stored client credentials must also be bound to their issuer and must not be reused with a different authorization server.
In Dynamic Client Registration (DCR), application_type is now made explicit, avoiding the problem where desktop or CLI clients get treated as web and have their localhost redirects rejected. However, DCR itself has been Deprecated in favor of prioritizing Client ID Metadata Documents (CIMD). It continues to function for backward compatibility, but new implementations are directed toward CIMD.
Even with more HTTP headers, authentication is still needed separately. Mcp-Method and Mcp-Name serve as material for routing decisions and policy evaluation. Authorization decisions require, at minimum, confirming that the received token is valid, that the issuer and target resource match, and that the scope permits that operation. Statelessness doesn't eliminate the need for authorization—it returns decisions that were previously hidden behind the connection back to each request.
Extensions That Separate UI, Long-Running Processes, and Enterprise Authorization
In 2026-07-28, a framework has also been formalized for evolving use-case-specific features as optional extensions rather than cramming them into the core. Official extensions carry IDs starting with io.modelcontextprotocol, and only function when both client and server agree on them via capability information. If one side doesn't support an extension, communication can proceed on the base protocol without using it.
The three representative extensions arriving together this time serve different roles. MCP Apps displays UI such as charts, forms, and videos within the conversation. Tasks creates processes that take anywhere from minutes to hours as persistent tasks, retrieving status with tasks/get and passing mid-process input via tasks/update. Enterprise-Managed Authorization (EMA) places the enterprise's IdP at the center of authorization decisions, letting administrators centrally manage permissions per employee and per server.
Tasks in particular is not simply the previous version's experimental core feature promoted as-is. The new io.modelcontextprotocol/tasks extension is not wire-compatible with the old approach, and tasks/result and tasks/list have been removed. Results of long-running processes are now polled via tasks/get, and cancellation uses tasks/cancel. Because a safe listing scope cannot be implicitly determined in an environment without sessions, tasks/list was not retained.
Conversely, Roots, Sampling, Logging, and the old HTTP+SSE transport have moved to Deprecated. Roots shifts its role to tool arguments or resource URIs, Sampling to LLM providers' APIs, and Logging to stderr or OpenTelemetry. Deprecated does not mean already removed. These will continue to function for at least 12 months, and actual removal will require a separate proposal and process.
Extensions and deprecation grace periods change not only technical features but also how the specification itself is cultivated going forward. Features with limited use cases are updated via independent versioning, and features removed from the core are given advance notice periods. Whether large-scale wire changes like this one can be avoided going forward depends on whether this operational discipline is maintained.
Four Tier 1 SDKs and the Reality of Migration
At the time of official release, four Tier 1 SDKs—TypeScript, Python, Go, and C#—support 2026-07-28, with the Rust SDK also supporting it in beta. However, the specification date is not a cutover deadline. Old-version clients and servers did not stop functioning on July 28, and compatible SDKs have a pathway for negotiating between old and new versions.
For example, in the TypeScript SDK, whether to speak the new version is explicitly chosen. Under automatic negotiation, it attempts server/discover, and if the server only handles up to 2025-11-25, it can fall back to the conventional initialize. In configurations pinned to the new specification, there is no fallback. This means the SDK's own major update and the actual work of enabling the new wire format can be tested separately.
Migration requires checking things beyond sessions as well. resultType is now required in all results, and the error code for a resource not being found has changed from -32002 to the JSON-RPC standard -32602. Clients that directly check for the old numeric code will need fixing. Implementations that were using experimental Tasks will not be sufficient just by matching method names—they must be restructured for the new task state transitions.
Therefore, the criterion for judging production migration readiness cannot simply be "did we install the latest SDK." One must survey the state a server had been tying to session IDs and bind explicit handles to authenticated principals. Negotiation between old and new versions, MRTR resends, cache user-boundary handling, and issuer verification by authorization servers must be confirmed under real traffic. MCP has moved closer to ordinary HTTP infrastructure, but reaping those benefits requires shifting, one by one, the responsibilities that had been entrusted to the connection over to the application.
