{"slug": "the-2026-07-28-mcp-specification-release-candidate", "title": "The 2026-07-28 MCP Specification Release Candidate", "summary": "The Model Context Protocol (MCP) released its 2026-07-28 specification release candidate, the largest revision since launch, which introduces a stateless core that eliminates the need for sticky sessions and shared session stores in production deployments. The update removes the initialize/initialized handshake and Mcp-Session-Id header, allowing any server instance to handle any request behind a plain round-robin load balancer. The final specification is scheduled to ship on July 28, 2026, with breaking changes that include a formal deprecation policy to support future protocol evolution.", "body_md": "The release candidate for MCP ** 2026-07-28** is now available. It is the largest\nrevision of the protocol since launch and delivers on the\n\n[2026 roadmap](/posts/2026-mcp-roadmap/):\n\n**a stateless core** that scales on ordinary HTTP infrastructure**extensions** including server-rendered UIs through[MCP Apps](#mcp-apps-server-rendered-user-interfaces)and long-running work through the[Tasks extension](#tasks-graduates-to-an-extension)**authorization** that aligns more closely with OAuth and OpenID Connect deployments**a formal deprecation policy** so the protocol can evolve without breaking what you’ve built,\n\nand many other changes.\n\nThe practical effect on a production deployment is immediate. A remote MCP\nserver that previously needed sticky sessions, a shared session store, and\ndeep packet inspection at the gateway can now run behind a plain round-robin\nload balancer, route traffic on an `Mcp-Method`\n\nheader, and let clients cache\n`tools/list`\n\nresponses for as long as the server’s `ttlMs`\n\npermits.\n\nThe release candidate is available today and the final specification ships on\n\nJuly 28, 2026. This release contains breaking changes; see[Release Timeline and Validation]for the details.\n\n## A Stateless Protocol[#](#a-stateless-protocol)\n\nThe headline change is that MCP is now stateless at the protocol layer. Six\n[Specification Enhancement Proposals](https://modelcontextprotocol.io/community/sep-guidelines)\n(SEPs) work together to get there, completing the plan we laid out in\n[The Future of MCP Transports](/posts/2025-12-19-mcp-transport-future/) in\nDecember.\n\n### Before and after[#](#before-and-after)\n\nIn [ 2025-11-25](/posts/2025-11-25-first-mcp-anniversary/), calling a tool over\nStreamable HTTP means establishing a session first:\n\n```\nPOST /mcp HTTP/1.1\nContent-Type: application/json\n\n{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\n \"params\":{\"protocolVersion\":\"2025-11-25\",\"capabilities\":{},\n           \"clientInfo\":{\"name\":\"my-app\",\"version\":\"1.0\"}}}\n```\n\nThe server responds with an `Mcp-Session-Id`\n\nthat every subsequent request must\ncarry, pinning the client to whichever instance issued it:\n\n```\nPOST /mcp HTTP/1.1\nMcp-Session-Id: 1868a90c-3a3f-4f5b\nContent-Type: application/json\n\n{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/call\",\n \"params\":{\"name\":\"search\",\"arguments\":{\"q\":\"otters\"}}}\n```\n\nIn `2026-07-28`\n\n, the same call is a single self-contained request that any\nserver instance can handle:\n\n```\nPOST /mcp HTTP/1.1\nMCP-Protocol-Version: 2026-07-28\nMcp-Method: tools/call\nMcp-Name: search\nContent-Type: application/json\n\n{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\n \"params\":{\"name\":\"search\",\"arguments\":{\"q\":\"otters\"},\n           \"_meta\":{\"io.modelcontextprotocol/clientInfo\":{\"name\":\"my-app\",\"version\":\"1.0\"}}}}\n```\n\n### The handshake and session are gone[#](#the-handshake-and-session-are-gone)\n\nThe `initialize`\n\n/`initialized`\n\nhandshake is removed\n([SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575)).\nThe protocol version, client info, and client capabilities that used to be\nexchanged once at connection time now travel in `_meta`\n\non every request, and a\nnew `server/discover`\n\nmethod lets clients fetch server capabilities when they\nneed them up front.\n\nThe `Mcp-Session-Id`\n\nheader and the protocol-level session that came with it are\nalso removed\n([SEP-2567](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2567)).\nWith both gone, any MCP request can land on any server instance, and the sticky\nrouting and shared session stores that horizontal deployments needed before are\nno longer required at the protocol layer.\n\n### Stateless protocol, stateful applications[#](#stateless-protocol-stateful-applications)\n\nRemoving the protocol-level session does not mean your application has to be\nstateless. Servers that need to carry state across calls can do what HTTP APIs\nhave always done: mint an explicit handle (a `basket_id`\n\n, a `browser_id`\n\n) from\na tool and have the model pass it back as an ordinary argument on later calls.\n\nIn practice, we’ve found this pattern (the model threading an identifier from one tool call to the next) to be more than just a workable substitute for session state. It’s often a more powerful one. The model can compose handles across tools, reason about them, and hand them off between steps in ways that externally managed session state, hidden in transport metadata, never really allowed.\n\nThe protocol no longer manages that state for you, but it doesn’t prevent you from managing it yourself. The explicit-handle pattern simply makes the state visible to the model rather than hidden away.\n\n### Server-to-client requests, restructured[#](#server-to-client-requests-restructured)\n\nA stateless protocol still needs a way for servers to ask the client for something mid-call, such as an elicitation prompt. Two SEPs rebuild that flow so it works without a persistent connection.\n\nServer-initiated requests may now only be issued while the server is actively\nprocessing a client request\n([SEP-2260](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2260)).\nEarlier spec versions recommended this; it’s now required. A user is never\nprompted out of nowhere, and every elicitation traces back to something they (or\ntheir agent) started.\n\nMulti Round-Trip Requests\n([SEP-2322](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322))\nchange how those prompts are delivered. Instead of holding a Server-Sent Events\n(SSE) stream open, the server returns an `InputRequiredResult`\n\n:\n\n```\n{\n  \"resultType\": \"inputRequired\",\n  \"inputRequests\": {\n    \"confirm\": {\n      \"type\": \"elicitation\",\n      \"message\": \"Delete 3 files?\",\n      \"schema\": { \"type\": \"boolean\" }\n    }\n  },\n  \"requestState\": \"eyJzdGVwIjoxLCJmaWxlcyI6WyJhIiwiYiIsImMiXX0=\"\n}\n```\n\nThe client gathers the answers and re-issues the original call with\n`inputResponses`\n\nand the echoed `requestState`\n\n. Any server instance can pick\nthat retry up because everything it needs is in the payload.\n\n### Routable, cacheable, traceable[#](#routable-cacheable-traceable)\n\nThree smaller changes make the resulting traffic easier to operate.\n\nThe Streamable HTTP transport now requires `Mcp-Method`\n\nand `Mcp-Name`\n\nheaders\n([SEP-2243](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2243))\nso load balancers, gateways, and rate-limiters can route on the operation\nwithout inspecting the body. Servers reject requests where the headers and body\ndisagree.\n\nList and resource read results now carry `ttlMs`\n\nand `cacheScope`\n\n([SEP-2549](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2549)),\nmodeled on HTTP `Cache-Control`\n\n. Clients know exactly how long a `tools/list`\n\nresponse is fresh and whether it’s safe to share across users, and a long-lived\nSSE stream is no longer the only way to learn that a list changed.\n\nW3C Trace Context propagation in `_meta`\n\nis now documented\n([SEP-414](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/414)),\nlocking down the `traceparent`\n\n, `tracestate`\n\n, and `baggage`\n\nkey names so\ndistributed traces correlate across SDKs and gateways. Several SDKs and tools\nwere already doing this; with the key names fixed in the spec, a trace that\nstarts in a host application can follow a tool call through the client SDK, the\nMCP server, and whatever the server calls downstream, and show up as a single\nspan tree in an [OpenTelemetry](https://opentelemetry.io/)-compatible backend.\n\n## Extensions Become First-Class[#](#extensions-become-first-class)\n\nExtensions existed in the `2025-11-25`\n\nrelease but had no formal process behind\nthem.\n[SEP-2133](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2133)\nadds that: extensions are identified by reverse-DNS IDs, negotiated through an `extensions`\n\nmap on client and server capabilities, live in their own `ext-*`\n\nrepositories\nwith delegated maintainers, and version independently of the specification. A new\nExtensions Track in the SEP process gives them a path from experimental to\nofficial.\n\nThis release includes two official extensions.\n\n### MCP Apps: server-rendered user interfaces[#](#mcp-apps-server-rendered-user-interfaces)\n\n[MCP Apps](/posts/2026-01-26-mcp-apps/)\n([SEP-1865](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1865))\nlets servers ship interactive HTML interfaces that hosts render in a sandboxed\niframe. Tools declare their UI templates ahead of time so hosts can prefetch,\ncache, and security-review them before anything runs. The rendered UI talks back\nto the host over the same JSON-RPC base protocol used everywhere else in MCP, so\nevery UI-initiated action goes through the same audit and consent path as a\ndirect tool call.\n\n### Tasks graduates to an extension[#](#tasks-graduates-to-an-extension)\n\nTasks shipped as an experimental core feature in\n[ 2025-11-25](https://modelcontextprotocol.io/specification/2025-11-25/server/tasks).\nProduction use surfaced enough redesign that the right home for it is an\nextension rather than the specification.\n\nThe [Tasks extension](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2663)\nreshapes the lifecycle around the stateless model: a server can answer\n`tools/call`\n\nwith a task handle, and the client drives it with `tasks/get`\n\n,\n`tasks/update`\n\n, and `tasks/cancel`\n\n. Task creation is server-directed: the client\nadvertises the extension and the server decides when a call should run as a\ntask. `tasks/list`\n\nis removed because it can’t be scoped safely without\nsessions.\n\nAnyone who shipped against the `2025-11-25`\n\nexperimental Tasks API will need to\nmigrate to the new lifecycle.\n\n## Authorization Hardening[#](#authorization-hardening)\n\nSix SEPs harden the\n[authorization specification](https://modelcontextprotocol.io/specification/draft/basic/authorization)\nto align more closely with how OAuth 2.0 and OpenID Connect are deployed in\npractice.\n\nClients must now validate the `iss`\n\nparameter on authorization responses per\n[RFC 9207](https://www.rfc-editor.org/rfc/rfc9207)\n([SEP-2468](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2468)).\nThis is a low-cost mitigation for a class of mix-up attack that is more\nprevalent in MCP’s single-client, many-server deployment pattern. In a future\nversion, clients will be expected to reject responses that omit `iss`\n\n, so\nauthorization servers should begin supplying it now if they don’t already.\n\nClients now declare their OpenID Connect `application_type`\n\nduring Dynamic\nClient Registration\n([SEP-837](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/837)),\navoiding the common case where an authorization server defaults a desktop or CLI\nclient to `\"web\"`\n\nand rejects its localhost redirect URI. Clients bind\nregistered credentials to the issuing authorization server’s `issuer`\n\nand\nre-register when a resource migrates between authorization servers\n([SEP-2352](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2352)).\nThe spec also documents how to request refresh tokens from OpenID Connect-style\nauthorization servers\n([SEP-2207](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2207)),\nand clarifies scope accumulation during step-up\n([SEP-2350](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2350))\nand the `.well-known`\n\ndiscovery suffix\n([SEP-2351](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2351)).\n\n## Roots, Sampling, and Logging Are Deprecated[#](#roots-sampling-and-logging-are-deprecated)\n\nThree core features are deprecated under the new\n[feature lifecycle policy](#how-the-protocol-evolves-from-here)\n([SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577)):\n\n| Feature | Replacement |\n|---|---|\n| Roots |\n|\n\n`stderr`\n\nfor stdio transports; [OpenTelemetry](https://opentelemetry.io/)for structured observabilityThese are annotation-only deprecations. The methods, types, and capability flags continue to work in this release and in every specification version published within a year of it, and removing any of them will require a separate SEP under the lifecycle policy.\n\n## Full JSON Schema 2020-12 for Tools[#](#full-json-schema-2020-12-for-tools)\n\nTool `inputSchema`\n\nand `outputSchema`\n\nare lifted to full\n[JSON Schema 2020-12](https://json-schema.org/draft/2020-12)\n([SEP-2106](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2106)).\nInput schemas keep the `type: \"object\"`\n\nroot constraint but now allow\ncomposition (`oneOf`\n\n, `anyOf`\n\n, `allOf`\n\n), conditionals, and references (`$ref`\n\n,\n`$defs`\n\n). Output schemas are unrestricted, and `structuredContent`\n\ncan now be\nany JSON value rather than only an object. Implementations must not\nauto-dereference external `$ref`\n\nURIs and should bound schema depth and\nvalidation time.\n\nSeparately, the error code for a missing resource changes from the MCP-custom\n`-32002`\n\nto the JSON-RPC standard `-32602`\n\nInvalid Params\n([SEP-2164](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2164)).\nIf your client matches on the literal `-32002`\n\nvalue, update it.\n\n## How the Protocol Evolves From Here[#](#how-the-protocol-evolves-from-here)\n\nThis release contains breaking changes. We don’t intend for that to be the norm.\n\nThree governance SEPs in this release are designed so that future revisions can\nevolve the protocol without breaking core capabilities. The\n[feature lifecycle policy](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2596)\ngives every feature an *Active*, *Deprecated*, and *Removed* lifecycle with at least\ntwelve months between deprecation and the earliest possible removal. The\n[Extensions framework](#extensions-become-first-class) means new capabilities\ncan ship as opt-in extensions and stabilize there before, if ever, moving into\nthe specification. And a Standards Track SEP can no longer reach Final status\nuntil a matching scenario lands in the [conformance suite](https://github.com/modelcontextprotocol/conformance)\n([SEP-2484](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2484)),\nwhich is the same suite the new [SDK tier system](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1777)\nscores official SDKs against.\n\nThe stateless rework in this release is the kind of foundational change that\nneeded a clean break. With it landed, and with deprecation windows and\nextensions as the standard tools going forward, our expectation is that\nimplementers targeting `2026-07-28`\n\nwill be able to adopt future revisions without\nrewriting their transport or lifecycle code.\n\n## Release Timeline and Validation[#](#release-timeline-and-validation)\n\nThe release candidate is locked as of **May 21, 2026**. The final specification\nwill be published on **July 28, 2026**. The ten-week window is for SDK\nmaintainers and client implementers to validate the changes against real\nworkloads; under the [SDK tier system](https://modelcontextprotocol.io/docs/sdk),\nTier 1 SDKs are expected to ship support within this window.\n\nThe full release candidate is in the\n[draft specification](https://modelcontextprotocol.io/specification/draft), and\nthe [changelog](https://modelcontextprotocol.io/specification/draft/changelog)\nwill list every change against `2025-11-25`\n\n.\n\nIf you find a problem, open an issue in the\n[specification repository](https://github.com/modelcontextprotocol/modelcontextprotocol/issues).\nFor implementation questions, the relevant\n[Working Group](https://modelcontextprotocol.io/community/working-interest-groups)\nchannel in the\n[contributor Discord](https://modelcontextprotocol.io/community/communication#discord)\nis the fastest path to an answer.\n\n## Looking Ahead[#](#looking-ahead)\n\nThis release gives MCP the foundation we expect it to grow on for a long time: a\nprotocol that runs statelessly on commodity HTTP infrastructure, an extensions\nframework where capabilities like Tasks and MCP Apps can ship on their own\ntimeline, and a lifecycle policy that lets implementers build on `2026-07-28`\n\nknowing what they ship will keep working.\n\nThank you to everyone who shaped these proposals through the Working Groups and a great deal of patient review. We’re looking forward to making this final with the community on July 28.", "url": "https://wpnews.pro/news/the-2026-07-28-mcp-specification-release-candidate", "canonical_source": "https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/", "published_at": "2026-05-31 11:56:49+00:00", "updated_at": "2026-05-31 12:17:34.056010+00:00", "lang": "en", "topics": ["ai-infrastructure", "ai-tools", "ai-agents", "ai-research", "large-language-models"], "entities": ["MCP", "OAuth", "OpenID Connect", "Specification Enhancement Proposals"], "alternates": {"html": "https://wpnews.pro/news/the-2026-07-28-mcp-specification-release-candidate", "markdown": "https://wpnews.pro/news/the-2026-07-28-mcp-specification-release-candidate.md", "text": "https://wpnews.pro/news/the-2026-07-28-mcp-specification-release-candidate.txt", "jsonld": "https://wpnews.pro/news/the-2026-07-28-mcp-specification-release-candidate.jsonld"}}