TL;DR: The 2026-07-28 revision of the Model Context Protocol deletes protocol-level sessions, the Mcp-Session-Id header, the initialize handshake, and the GET stream endpoint. Every request is now self-describing: version and capabilities ride in _meta, server-to-client interactions became a retry loop called MRTR, cancellation happens by closing the response stream, and long-running work moved to the official Tasks extension. Every existing MCP server and client is affected, and both official SDKs shipped v2 rewrites in June–July 2026 MCP 2026-07-28 Key Changesmodelcontextprotocol/typescript-sdkmodelcontextprotocol/python-sdk.


The transport evolution: three generations in eighteen months

MCP’s HTTP story is a rapid succession of designs, each fixing the failure mode of the last:

  1. HTTP+SSE (2024-11-05) — the original transport exposed two endpoints: a GET endpoint that opened an SSE stream for server-to-client messages, and a POST endpoint for client-to-server requests Streamable HTTP transportfka.dev — Why MCP deprecated SSE. It required clients to maintain a permanent outbound connection, which broke behind NATs, proxies, and serverless deployments — a major reason it was deprecated barely four months later fka.dev — Why MCP deprecated SSEChannel — MCP SSE to Streamable HTTP migration.
  2. Streamable HTTP with sessions (2025-03-26) — collapsed everything to a single POST endpoint, but kept protocol-level sessions identified by the Mcp-Session-Id header, established through the initialize/notifications/initialized handshake, and terminated with HTTP DELETE MCP 2026-07-28 Key ChangesStreamable HTTP transportMCP 2025-11-25 transports.
  3. Stateless Streamable HTTP (2026-07-28) — the subject of this post. Sessions, the handshake, the GET endpoint, and SSE resumability are all gone MCP 2026-07-28 Key ChangesStreamable HTTP transport.

The session-based design of generation two was the problem. A session pinned a client to server-side state, which forced stateful load balancing and sticky sessions in production — exactly the kind of constraint that makes MCP hard to operate at scale behind standard infrastructure TrueFoundry — MCP stdio vs Streamable HTTPWebMCP Guide — Streamable HTTP enterprise guide. The stateless rewrite means any server instance can serve any request, list endpoints no longer vary per connection, and intermediaries (CDNs, load balancers, gateways) can treat MCP traffic like ordinary HTTP MCP 2026-07-28 Key ChangesWebMCP Guide — Streamable HTTP enterprise guide.

What the 2026-07-28 revision removes

The changelog is blunt about the deletions MCP 2026-07-28 Key Changes:

  • Protocol-level sessions and Mcp-Session-Id — removed via SEP-2567. List endpoints (tools/list, resources/list, prompts/list) no longer vary per-connection; servers that need cross-call state must now mint explicit, server-owned handles and pass them as ordinary tool arguments MCP 2026-07-28 Key Changes.
  • The initialize/notifications/initialized handshake — removed via SEP-2575. There is no connection to set up anymore, so there is nothing to initialize MCP 2026-07-28 Key Changes.
  • The GET stream endpoint — the server now exposes a single endpoint that accepts POST only Streamable HTTP transport. Old clients that GET or DELETE it will get 405 Method Not Allowed from a modern server Streamable HTTP transport.
  • ping, logging/setLevel, and notifications/roots/list_changed — log level is now a per-request _meta field (io.modelcontextprotocol/logLevel), and servers MUST NOT emit notifications/message for requests that didn’t include it MCP 2026-07-28 Key Changes.
  • SSE stream resumability — the Last-Event-ID header and SSE event IDs are gone. A broken response stream loses the in-flight request; the client MUST re-issue it as a new request with a new request ID MCP 2026-07-28 Key ChangesStreamable HTTP transport. Modern servers simply ignore a Last-Event-ID header if one arrives Streamable HTTP transport.

The new wire shape

In exchange for the deleted machinery, the revision makes every request self-contained MCP 2026-07-28 Key ChangesStreamable HTTP transport:

  • Version and capabilities per request. Every request carries io.modelcontextprotocol/protocolVersion and io.modelcontextprotocol/clientCapabilities in its _meta. Clients SHOULD also identify themselves (io.modelcontextprotocol/clientInfo), and servers SHOULD echo identity in each result’s _meta MCP 2026-07-28 Key Changes. A version mismatch returns UnsupportedProtocolVersionError MCP 2026-07-28 Key Changes.
  • server/discover. Servers MUST implement this RPC to advertise supported protocol versions, capabilities, and identity. Clients MAY call it before anything else for up-front version selection, or use it as a backward-compatibility probe on stdio MCP 2026-07-28 Key Changes.
  • Required headers. Every POST must send Accept: application/json, text/event-stream, MCP-Protocol-Version (which MUST match the _meta version or the server rejects with a HeaderMismatch error), plus Mcp-Method (mirroring the JSON-RPC method) and Mcp-Name (mirroring params.name or params.uri for tools/call, resources/read, prompts/get) so intermediaries can route and inspect requests without parsing the body Streamable HTTP transport. SEP-2243 also added x-mcp-header, a schema annotation that lets servers designate tool parameters to be mirrored into Mcp-Param-{name} headers MCP 2026-07-28 Key ChangesStreamable HTTP transport.
  • resultType on every result. All results now carry resultType: "complete" — or "input_required" for MRTR interim results. Clients MUST treat results from older servers that omit the field as "complete" MCP 2026-07-28 Key Changes.
  • OpenTelemetry trace context. The spec now documents traceparent, tracestate, and baggage propagation conventions in _meta (SEP-414) MCP 2026-07-28 Key Changes.
  • Cacheable results. tools/list, prompts/list, resources/list, resources/read, and resources/templates/list results must include ttlMs (a freshness hint in milliseconds) and cacheScope ("public" or "private") via the new CacheableResult interface — letting clients cache responses and cut polling, and letting shared intermediaries cache only what’s marked public MCP 2026-07-28 Key Changes. Tools should also be returned in deterministic order to improve LLM prompt-cache hit rates MCP 2026-07-28 Key Changes.

A request on the wire in 2026-07-28

Here is what a conforming tools/call looks like now — every header and _meta field is required:

POST /mcp HTTP/1.1
Host: mcp.example.com
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: get_weather
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": { "location": "Seattle, WA" },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": { "name": "niteagent", "version": "1.0.0" },
      "io.modelcontextprotocol/clientCapabilities": {
        "extensions": { "io.modelcontextprotocol/tasks": {} }
      }
    }
  }
}

The server responds either with a single JSON object (application/json) or a request-scoped SSE stream (text/event-stream) carrying progress notifications followed by the final response, which SHOULD terminate the stream Streamable HTTP transport. Streaming servers SHOULD also send X-Accel-Buffering: no so reverse proxies don’t buffer events Streamable HTTP transport.

Multi round-trip requests replace server-initiated calls

The most architecturally significant change: servers can no longer send their own JSON-RPC requests (like roots/list, sampling/createMessage, or elicitation/create) on SSE streams MCP 2026-07-28 Key ChangesStreamable HTTP transport. Instead, the Multi Round-Trip Requests (MRTR) pattern (SEP-2322) inverts the flow MCP 2026-07-28 Key ChangesMulti Round-Trip Requests (MRTR) pattern. When a server needs input, it returns an InputRequiredResult with resultType: "input_required", an inputRequests map, and optionally an opaque requestState blob. The client gathers the input, then retries the original request — with a new JSON-RPC id — including inputResponses and echoing requestState verbatim Multi Round-Trip Requests (MRTR) pattern. Because requestState round-trips through the client, servers MUST treat it as attacker-controlled input and integrity-protect it (HMAC or AEAD) if it influences authorization or business logic, with expiry and principal binding to bound replay Multi Round-Trip Requests (MRTR) pattern.

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "resultType": "input_required",
    "inputRequests": {
      "github_login": {
        "method": "elicitation/create",
        "params": {
          "mode": "form",
          "message": "Please provide your GitHub username",
          "requestedSchema": {
            "type": "object",
            "properties": { "name": { "type": "string" } },
            "required": ["name"]
          }
        }
      }
    },
    "requestState": "AEAD-protected-blob"
  }
}
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "create_github_issue",
    "arguments": { "title": "Broken link in docs" },
    "inputResponses": {
      "github_login": { "action": "accept", "content": { "name": "octocat" } }
    },
    "requestState": "AEAD-protected-blob",
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": { "name": "niteagent", "version": "1.0.0" },
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

MRTR is only legal on tools/call, resources/read, and prompts/get Multi Round-Trip Requests (MRTR) pattern. Crucially, each leg of the exchange is an independent request: the server processing the retry needs nothing beyond what’s in the retry itself, which is what keeps the whole protocol stateless Multi Round-Trip Requests (MRTR) pattern.

Cancellation is now a transport-level signal

With request-scoped SSE streams, cancellation semantics simplify dramatically: closing the request’s SSE response stream IS the cancel signal Streamable HTTP transport. Because each request has its own stream, the disconnect is unambiguous. The server SHOULD stop work as soon as practical and MUST NOT send further messages for that request Streamable HTTP transport. The notifications/cancelled message still exists, but only on the stdio transport — this revision defines no client-to-server notifications over Streamable HTTP at all Streamable HTTP transport.

Subscriptions: one long-lived POST

resources/subscribe/resources/unsubscribe and the GET endpoint are replaced by subscriptions/listen: the client POSTs a request whose response is a single long-lived SSE stream, and the server delivers only the notification types the client opted into — toolsListChanged, promptsListChanged, resourcesListChanged, resourceSubscriptions — tagging each with io.modelcontextprotocol/subscriptionId MCP 2026-07-28 Key ChangesStreamable HTTP transport. Request-scoped notifications like notifications/progress and notifications/message do NOT flow on the listen stream; they stay on the response stream of the request they relate to Streamable HTTP transport. Servers are encouraged to emit periodic SSE comment lines (:) as keep-alives so proxies and idle timeouts don’t kill quiet streams Streamable HTTP transport.

HTTP/1.1 200 OK
Content-Type: text/event-stream
X-Accel-Buffering: no

: keep-alive

event: message
data: {"jsonrpc":"2.0","method":"notifications/tools/list_changed","params":{"_meta":{"io.modelcontextprotocol/subscriptionId":"sub-8f2a"}}}

event: message
data: {"jsonrpc":"2.0","method":"notifications/resources/updated","params":{"uri":"file:///projects/myapp/config.json"}}

What got deprecated

The revision also formalized a feature lifecycle policy (Active → Deprecated → Removed, with a minimum twelve-month deprecation window) and used it to retire several pillars of the 2025-era protocol MCP 2026-07-28 Key Changes:

  • Roots, Sampling, and Logging are deprecated (SEP-2577). They remain functional during the deprecation window, but new implementations should not adopt them. Suggested migrations: pass directories/files via tool parameters or resource URIs instead of Roots; call LLM provider APIs directly instead of Sampling; log to stderr on stdio or use OpenTelemetry instead of Logging MCP 2026-07-28 Key Changes.
  • OAuth 2.0 Dynamic Client Registration (RFC 7591) is deprecated in favor of Client ID Metadata Documents, remaining only for backwards compatibility with authorization servers that don’t support the replacement [MCP 2026-07-28 Key Changes](https.0“, “id”: 1, “result”: { “resultType”: “task”, “taskId”: “task_9f3c2a”, “status”: “working”, “ttlMs”: 3600000, “pollIntervalMs”: 2000 } }

The client then polls `tasks/get`; if the task needs input it moves to `input_required` and the poll response carries an `inputRequests` map, which the client fulfills via `tasks/update`; `tasks/cancel` requests cooperative cancellation (the server acknowledges but isn't obligated to stop). Terminal states are `completed` (with the `result` the synchronous call would have returned), `failed` (with the JSON-RPC `error`), and `cancelled` [MCP Tasks extension overview](https://modelcontextprotocol.io/extensions/tasks/overview). Task IDs are durable handles, so polling survives client crashes and reconnects — the exact problem sessions were originally invented to solve, solved without any server-side connection state [MCP Tasks extension overview](https://modelcontextprotocol.io/extensions/tasks/overview). Servers may also push `notifications/tasks` status updates over `subscriptions/listen`, letting clients skip polling entirely [MCP Tasks extension overview](https://modelcontextprotocol.io/extensions/tasks/overview). Both sides must opt in: the client via the `extensions` field in its per-request `clientCapabilities`, the server by advertising the extension in `server/discover` capabilities [MCP Tasks extension overview](https://modelcontextprotocol.io/extensions/tasks/overview).

## Migration checklist

Both official SDKs have already done the heavy lifting — but the breaking change is real. The TypeScript SDK's "Implement MCP 2026-07-28" landed June 26, 2026 (#2286), with v1 preserved on a long-lived `v1.x` branch and v2 docs at a separate path [modelcontextprotocol/typescript-sdk](https://github.com/modelcontextprotocol/typescript-sdk). The Python SDK shipped its v2 with per-version wire packages (`mcp_types._v*`) and now links the released 2026-07-28 spec, pointing migrators at the v1 docs [modelcontextprotocol/python-sdk](https://github.com/modelcontextprotocol/python-sdk). Anyone hand-rolling a server or client, or pinning old SDK versions, has work to do.

**Server checklist:**
- Implement `server/discover` and advertise protocol versions, capabilities, and identity [MCP 2026-07-28 Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog).
- Delete session handling: no `Mcp-Session-Id` minting, no `initialize` state machine, no GET/DELETE endpoints (return `405` for old clients) [MCP 2026-07-28 Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog)[Streamable HTTP transport](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http).
- Emit `resultType` on every result; implement `CacheableResult` (`ttlMs`/`cacheScope`) on list/read results and sort `tools/list` deterministically [MCP 2026-07-28 Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog).
- Replace server-initiated requests with `InputRequiredResult` + `inputRequests`; integrity-protect `requestState` [MCP 2026-07-28 Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog).
- Implement `subscriptions/listen` and tag notifications with `subscriptionId`; use per-request `io.modelcontextprotocol/logLevel` instead of `logging/setLevel` [MCP 2026-07-28 Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog).
- Honor cancellation by stream close; send `X-Accel-Buffering: no` and keep-alive comments on long streams [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http).
- Validate `Origin` (403 on invalid) and consider binding to localhost when running locally [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http).

**Client checklist:**
- Send `Accept`, `MCP-Protocol-Version`, `Mcp-Method`, `Mcp-Name` (and `Mcp-Param-*` where the server's schema declares `x-mcp-header`) plus full `_meta` on every POST [MCP 2026-07-28 Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog)[Streamable HTTP transport](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http).
- Drop the handshake; call `server/discover` for version selection and treat `UnsupportedProtocolVersionError` as a signal to negotiate [MCP 2026-07-28 Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog).
- Handle polymorphic results: `complete`, `input_required` (gather input, retry with a new `id`), and `task` (poll `tasks/get`, answer `tasks/update`, send `tasks/cancel`) [MCP 2026-07-28 Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog)[MCP Tasks extension overview](https://modelcontextprotocol.io/extensions/tasks/overview).
- Cancel by closing the response stream — never send `notifications/cancelled` over HTTP [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http).
- Re-issue requests after stream failures (no `Last-Event-ID` recovery exists) [MCP 2026-07-28 Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog)[Streamable HTTP transport](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http).
- For legacy servers, keep the HTTP+SSE fallback probe: a POST that fails with `400`/`404`/`405` and a non-JSON-RPC body means try the old GET endpoint and look for an `endpoint` event [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http).

## The bottom line

The 2026-07-28 revision is the first MCP release that treats the network as a genuinely unreliable, load-balanced, cacheable substrate rather than a set of long-lived conversations [MCP 2026-07-28 Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog)[TrueFoundry — MCP stdio vs Streamable HTTP](https://www.truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise)[WebMCP Guide — Streamable HTTP enterprise guide](https://webmcpguide.com/articles/mcp-streamable-http-transport-enterprise-guide). The cost is real migration work — every server and client must speak the new wire format — but the payoff is that MCP servers finally deploy like normal HTTP services: stateless, horizontally scalable, and cacheable at the edge. If you haven't moved to the v2 SDKs yet, that's the single highest-leverage migration step available right now [modelcontextprotocol/typescript-sdk](https://github.com/modelcontextprotocol/typescript-sdk)[modelcontextprotocol/python-sdk](https://github.com/modelcontextprotocol/python-sdk).

---

*Sources:*
- [MCP 2026-07-28 Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog) [MCP 2026-07-28 changelog](https://modelcontextprotocol.io/specification/2026-07-28/changelog)
- [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http) [Streamable HTTP transport (2026-07-28)](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http)
- [MCP 2025-11-25 transports](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports) [Transports (2025-11-25)](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports)
- [MCP Tasks extension overview](https://modelcontextprotocol.io/extensions/tasks/overview) [MCP Tasks overview](https://modelcontextprotocol.io/extensions/tasks/overview)
- [modelcontextprotocol/typescript-sdk](https://github.com/modelcontextprotocol/typescript-sdk) [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
- [modelcontextprotocol/python-sdk](https://github.com/modelcontextprotocol/python-sdk) [Python SDK](https://github.com/modelcontextprotocol/python-sdk)
- [TrueFoundry — MCP stdio vs Streamable HTTP](https://www.truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise) [TrueFoundry — MCP stdio vs Streamable HTTP for enterprise](https://www.truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise)
- [fka.dev — Why MCP deprecated SSE](https://blog.fka.dev/blog/2025-06-06-why-mcp-deprecated-sse-and-go-with-streamable-http/) [Why MCP deprecated SSE — fka.dev](https://blog.fka.dev/blog/2025-06-06-why-mcp-deprecated-sse-and-go-with-streamable-http/)
- [Channel — MCP SSE to Streamable HTTP migration](https://www.channel.tel/blog/mcp-sse-to-streamable-http-migration) [Channel — MCP SSE to Streamable HTTP migration](https://www.channel.tel/blog/mcp-sse-to-streamable-http-migration)
- [WebMCP Guide — Streamable HTTP enterprise guide](https://webmcpguide.com/articles/mcp-streamable-http-transport-enterprise-guide) [WebMCP Guide — Streamable HTTP enterprise guide](https://webmcpguide.com/articles/mcp-streamable-http-transport-enterprise-guide)
- [Multi Round-Trip Requests (MRTR) pattern](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr) [Multi Round-Trip Requests (MRTR) pattern](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr)

## References
- [MCP 2026-07-28 Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog)
- [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http)
- [MCP 2025-11-25 transports](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports)
- [MCP Tasks extension overview](https://modelcontextprotocol.io/extensions/tasks/overview)
- [modelcontextprotocol/typescript-sdk](https://github.com/modelcontextprotocol/typescript-sdk)
- [modelcontextprotocol/python-sdk](https://github.com/modelcontextprotocol/python-sdk)
- [TrueFoundry — MCP stdio vs Streamable HTTP](https://www.truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise)
- [fka.dev — Why MCP deprecated SSE](https://blog.fka.dev/blog/2025-06-06-why-mcp-deprecated-sse-and-go-with-streamable-http/)
- [Channel — MCP SSE to Streamable HTTP migration](https://www.channel.tel/blog/mcp-sse-to-streamable-http-migration)
- [WebMCP Guide — Streamable HTTP enterprise guide](https://webmcpguide.com/articles/mcp-streamable-http-transport-enterprise-guide)
- [Multi Round-Trip Requests (MRTR) pattern](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr)

<!-- crosslinks -->

## 📖 Related Reads

- **[Hermes Tutorials](https://hermes-tutorials.dev/)** — Hermes Agent setup, configuration, and advanced workflows
- **[ToolBrain](https://toolbrain.net/)** — tool reviews, LLM comparisons, and AI workflow guides

*Cross-links automatically generated from NiteAgent.*
← Back to all posts