# What changed in MCP 2026-07-28

The stateless revision removed the initialize handshake and made server/discover mandatory. What it means if you run an MCP server.

The Model Context Protocol's **2026-07-28** revision is the largest change since the protocol launched. If you run an MCP server, two of its changes decide whether existing clients can still talk to you.

## The handshake is gone

Before this revision, a client opened a session with an `initialize` call and the two sides negotiated a protocol version once. That is removed. MCP is now **stateless**: every request carries its own version and client capabilities in `_meta`:

```json
"_meta": {
  "io.modelcontextprotocol/protocolVersion": "2026-07-28",
  "io.modelcontextprotocol/clientInfo": { "name": "ExampleClient", "version": "1.0.0" },
  "io.modelcontextprotocol/clientCapabilities": {}
}
```

Protocol-level sessions and the `Mcp-Session-Id` header are gone with it. State that used to live in a session now travels as explicit, server-minted handles passed as ordinary tool arguments. This is what makes the protocol deployable on serverless and edge infrastructure without sticky routing.

## `server/discover` is mandatory

Servers **must** implement `server/discover`. One call returns the revisions a server supports, its capabilities, and its identity:

```json
{
  "resultType": "complete",
  "supportedVersions": ["2026-07-28"],
  "capabilities": { "tools": {} },
  "instructions": "…"
}
```

A client no longer probes `tools/list`, `prompts/list` and `resources/list` separately just to learn what a server can do.

## What else moved

- **Extensions are versioned and official.** MCP Apps (interactive UI in a conversation) and Tasks (long-running work) now ship as extensions, advertised in a capability map, without changing the core protocol.
- **Server-initiated requests are replaced by MRTR.** Instead of the server sending its own request for sampling, elicitation or roots, it returns an `InputRequiredResult` and the client retries the original request with the answers attached.
- **`ping`, `logging/setLevel` and SSE resumability are removed.** A broken response stream loses the in-flight request; the client re-issues it.
- **Authorization hardened.** RFC 9207 `iss` validation, Client ID Metadata Documents in place of Dynamic Client Registration, and enterprise identity systems without workarounds.
- **Roots, Sampling and Logging are deprecated** under a new lifecycle policy with a minimum twelve-month removal window. They still work. New implementations should not adopt them.

## What this means if you run a server

**Nothing breaks on day one.** The spec explicitly allows a server to serve both eras from one endpoint: answer `server/discover` and per-request `_meta` for new clients, keep `initialize` for everyone else. Every widely deployed client today is still handshake-era, so dropping `initialize` now would disconnect your existing users.

Three practical notes:

1. **Streamable HTTP POSTs now require `Mcp-Method` and `MCP-Protocol-Version` headers**, and their values must match the request body. A mismatch is a `400` with error `-32020`.
2. **An unsupported version is `-32022`**, and the error must list the versions you do support. That list is how a well-built client recovers instead of giving up.
3. **Sessions and the new revision are incompatible by design.** If your framework has sessions enabled, it cannot serve 2026-07-28 requests even if the SDK recognises them.

## How to tell what a server actually speaks

Ask it. The answer is one POST:

```bash
curl -X POST https://example.com/mcp \
  -H 'content-type: application/json' \
  -H 'MCP-Protocol-Version: 2026-07-28' \
  -H 'Mcp-Method: server/discover' \
  -d '{"jsonrpc":"2.0","id":1,"method":"server/discover",
       "params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28"}}}'
```

A `DiscoverResult` means the server is on the new revision. A `400` whose body is not one of the spec's own error codes means it is handshake-era — fall back to `initialize`.

One caveat worth knowing: **an SDK that recognises the new error codes is not the same as a server that can serve the new revision.** Some implementations answer `-32022` correctly and then list only handshake-era versions. The versions a server names are the honest answer; the error code alone is not.

## Where we track this

The MCP Census asks every endpoint on record which revision it reports, and publishes the answer per server on [/lookup](/lookup) and in aggregate on [/coverage](/coverage). The number of servers we have not yet asked is published alongside, so the coverage is never mistaken for the whole ecosystem.

We deliberately **do not** score servers on their protocol revision. The revision is days old, and marking down working software for that would be a verdict the evidence does not support. See [Methodology](/methodology).
