Will an MCP server agree to a protocol version that does not exist?

Run: 2026-09-27 15:29 UTC · Sample: 40 servers · Answered the handshake: 18 · Returned 502: 1 · Agreed to the impossible revision: 2

The Model Context Protocol says a server must answer initialize with a revision it supports, and the revision is not decoration: it decides whether MCP-Session-Id is part of the contract, how server-initiated traffic works, and — in 2026-07-28 — whether the conversation is stateful at all. A server that echoes whatever the client asked for makes the handshake information-free, and a client cannot tell the difference from the inside.

So this is measured rather than assumed. It is also the field evidence behind #178: our own governed upstream client used to send a revision and never read the reply, so whatever a server decided here was invisible to us. That was the state of the code when this was measured. As of 2026-09-27 master records what each upstream answered and reports it per server on GET /mcp/tools; that is available from source and from the rolling :latest / :master image tags, which were built from master on 2026-09-27 - but not from the versioned 0.8.0 tag, which predates it. What the gateway should do about a server that names a different revision is still open on the issue.

Method

tools/survey-mcp-revision-tolerance.mjs reads the official MCP registry for streamable-http records — the same first 40 endpoints, in the same order, as the pagination survey — and sends each one initialize with:

{ "protocolVersion": "9999-99-99" }

a revision that has never existed. One request per server, anonymous, no credentials, no writes.

Result

VerdictCountWhat it means
Refused the anonymous handshake (401/403)21not measurable this way
Answered with a revision it supports14correct: 6 chose 2025-06-18, 7 chose 2025-11-25, 1 chose 2024-11-05
Returned a JSON-RPC error (HTTP 400)2correct: strict rejection, the behaviour 2026-07-28 spells out
Echoed 9999-99-99 with HTTP 2002agreed to a protocol version that does not exist
502, no version1upstream failure

The two that agreed:

Of the 18 that produced a JSON-RPC answer, 16 behaved correctly and 2 did not check: 14 named a revision they support, 2 rejected the request outright, 2 echoed the nonsense. A 19th endpoint returned 502 with no revision at all, which is neither a pass nor a failure of this check — it is an upstream that did not answer. That is the honest ratio: 2/18, not 2/40 — 21 of the 40 would not talk to an anonymous client, so they are outside this measurement rather than passing it.

The same seven-way tally came back unchanged when the script was re-run at 18:01 UTC on the same day (auth_required 21, error_object 2, substituted_supported_version 6, AGREED_TO_THE_IMPOSSIBLE 2, answered_2025-11-25 7, no_version_502 1, answered_2024-11-05 1). That caught an arithmetic error in the first version of this page, which described those 18 answers as 19 and counted the 502 as correct behaviour; the table above is the record, and the prose now adds up to it.

The part that is more useful than the headline

Seven servers answered 2025-11-25 when asked for the impossible revision, yet all seven answered 2025-06-18 when the pagination survey asked them for 2025-06-18 an hour earlier. Those two readings together say something a single probe cannot: the server supports both, honours a valid request, and falls back to its newest when the request is nonsense. So the fallback value is the more informative one — it is the revision the server would have preferred, the one a client never learns by asking politely.

One server, ai.adoraads/beauty, answered 2024-11-05 in both probes. Same endpoint, two different requests, same answer: that looks like a server pinned to one revision rather than noise, which is the exact case a gateway that ignores the reply cannot see.

What this does not show

Reproduce

node tools/survey-mcp-revision-tolerance.mjs 40      # this page: does it check the revision?
node tools/survey-mcp-tools-list-pagination.mjs 40   # the paired reading: does it paginate?
node tools/survey-mcp-session-enforcement.mjs 40     # the third: does it require its own session id?

Both scripts make outbound requests to third-party services that are not ours, and neither is wired into CI for that reason. Keep the timestamp with any number quoted from them.