MCP protocol revisions
This page covers the three generations of the MCP protocol and their five revisions, how an MCP test picks the revision it speaks, how Fixter detects what your server speaks, and how to watch that your server keeps accepting the revisions your clients use.
Generations
Section titled “Generations”MCP has had five dated protocol revisions, and they do not all open a conversation the same way. Fixter groups them into three generations by that opening, because the opening is what a test has to get right before it can check anything else, and the app shows the generation beside every revision:
- Stateless (
2026-07-28, the current revision): the test sends oneserver/discoverrequest. There is noinitialize, no event stream and no session. - Sessions (
2025-03-26,2025-06-18,2025-11-25): the test sendsinitializeproposing the revision, thennotifications/initialized, and deletes the session afterwards if the server minted one. It never opens an event stream. - HTTP+SSE transport (
2024-11-05, deprecated): the test opens a GET event stream, waits up to two seconds for its first event,endpoint, then sendsinitializeandnotifications/initializedto that endpoint.
In every generation the test identifies itself as fixter-monitoring. A server that answers
none of these openings has not identified itself, and the run fails mcp.initialize; see
What a failed run says.
Servers move from one revision to the next at their own pace and often accept several at once, so every MCP test speaks one revision: the newest the server accepts, or one you pin. A set of pinned tests watches several revisions at once.
Revisions
Section titled “Revisions”| Revision | Generation | Note | Sends MCP-Protocol-Version |
|---|---|---|---|
2024-11-05 | HTTP+SSE transport | deprecated, eligible for removal | Never |
2025-03-26 | sessions | not the current revision | Never |
2025-06-18 | sessions | not the current revision | On every request after initialize |
2025-11-25 | sessions | not the current revision | On every request after initialize |
2026-07-28 | stateless | current | On every request, server/discover included |
The generation and note columns are the labels the app shows. The Protocol revision picker
in the test editor lists each revision in the same form, for example
2026-07-28 · stateless · current, after Newest supported.
Newest supported
Section titled “Newest supported”Newest supported (NEWEST_SUPPORTED) is the default. The editor’s help text says:
Newest supported runs against the newest protocol revision the server speaks and moves with it when the server changes. A dated revision pins the test and it fails if the server stops accepting it. Over MCP, create_api_test and update_api_test take the revision as
mcpProtocolRevision; leaving it out means NEWEST_SUPPORTED.
The revision the test currently speaks is kept on the test as currentRevision, and the test
page shows Protocol: Newest supported (currently <revision>), or
Protocol: Newest supported (not run yet) before the first run. Fixter looks for a newer or
older revision only when a run meets one of the era signals described under
When a test looks up the revision again.
When a run speaks a different revision from the one before, the run is judged normally: it
passes when its assertions pass. It records the change in protocolRevision and
previousRevision, and its row in the run history reads now <protocolRevision>, was <previousRevision>, for example now 2026-07-28, was 2025-11-25. A move is not an alert: no
notification is sent for it.
When a test looks up the revision again
Section titled “When a test looks up the revision again”The lookup a run does is shorter than a detection you ask for: it tries the newest generation
first, stops at the first that answers, and sends at most four requests. A Newest supported
test with no current revision runs it before its first run. After that, any test runs it again
only when a run meets an era signal, a reply that says the server has moved generation:
- On a stateless revision: a 400, 404 or 405 reply to
server/discoverwhose body is not one of the JSON-RPC errors-32020,-32021,-32022or-32601, or a-32601reply at any status. - On a sessions revision: a 4xx other than 401 and 403 in reply to
initializewhose body is one of those errors. - On the HTTP+SSE transport: a GET that does not open a stream whose first event is
endpoint.
Timeouts, connection errors, 5xx, 401, 403, 429 and failed assertions never trigger it. The
lookup sends server/discover, then initialize proposing 2025-11-25, then the HTTP+SSE GET;
a 401, 403 or 5xx ends it with no server found, and the run fails mcp.initialize with
the target did not identify itself as an MCP server. A run keeps at most one lookup across its
retry attempts, and the test’s timeout covers it. After the lookup, a Newest supported test
repeats the attempt at the revision it found, and a pinned test fails mcp.protocol.revision.
A pinned revision
Section titled “A pinned revision”Pick a dated revision in Protocol revision to pin the test to it. The test page then shows
Protocol: <revision> (pinned). When the server stops accepting the pinned revision, the run
fails assertion mcp.protocol.revision with the sentence:
Server no longer speaks protocol <pin>The assertion’s expected value is the pinned revision, and its actual value is the revision
the server offers instead, or unsupported. A sessions server that answers initialize with
a different sessions revision from the one proposed fails a pin the same way; a
Newest supported test adopts the revision it answered with.
Pin when an agent or client you depend on speaks that revision and must keep working. Use
Newest supported when you only care that the server stays healthy on whatever it speaks.
Detection
Section titled “Detection”A detection asks a server which of the five revisions it accepts. It probes each revision on its own (it does not stop at the first one that answers), in at most eight requests and within 20 seconds. A detection is not a run: it needs no saved test, is never written to a test’s run history and does not change any test’s state or uptime.
With your agent
Section titled “With your agent”detect_mcp_protocol is read-only and takes mcpUrl and, optionally, mcpCredentialId. See
the API tests tools. The answer carries:
outcome:DETECTEDwhen at least one revision is supported,NONEwhen none is,RATE_LIMITEDwhen the server answered with a rate limit, with itsRetry-Aftervalue inretryAfterHeader.newestSupportedand the server’sserverInfo.revisions, one entry per revision withrevision,generation,supportedandnote, plusserverInfofor a supported revision orevidencefor an unsupported one.
NONE is a normal answer, not an error, and every entry then carries its evidence: status,
contentType, bodyPreview, jsonRpcErrorCode, jsonRpcErrorMessage, millis,
reachabilityFailure and message. The tool also gives one sentence per revision, for
example 2026-07-28 (stateless): supported. This is the current protocol revision. or
2025-06-18 (sessions): not supported (HTTP 400, application/json).
In the app
Section titled “In the app”The test editor detects automatically once the URL looks
complete (it starts with http:// or https://, has no spaces, and its host is localhost,
an IP address or a domain whose last label has two or more letters). It detects after a 1.5
second pause in typing, at once when you paste the URL or leave the field, and again when you
change the credential. Editing an existing test does not detect while its URL is untouched.
While it works the editor shows Detecting protocol…. On DETECTED it sets
Protocol revision to Newest supported, shows currently <revision> beside it, and lists
every revision in a table with the columns Revision, Generation, Result (Supported or
Not supported) and Note. For each revision the server does not support, the result also
shows the reply’s status, content type and first bytes. The other results read:
This URL did not identify itself as an MCP server on any revision.(outcomeNONE)The server rate-limited the detection (HTTP 429); try again later.Detection failed.
Once a result or an error is on screen, the Detect again link runs the detection again; it
is the only manual control.
Watching several revisions
Section titled “Watching several revisions”An MCP test speaks one revision. To check that your server keeps accepting several, for example every revision the agents and clients you depend on speak, create one MCP test per revision:
Check depth:Handshake.Protocol revision: the dated revision this test watches.
An agent does the same with create_api_test: type MCP, mcpTier HANDSHAKE and
mcpProtocolRevision set to the revision. Each test runs, fails and notifies on its own. When the
server drops a revision, only the test pinned to it fails, with
Server no longer speaks protocol <pin>, and its notification names the test.
For example, to keep three revisions working on an orders MCP server, create three tests:
Name | Check depth | Protocol revision |
|---|---|---|
Orders MCP 2025-03-26 | Handshake | 2025-03-26 · sessions · not the current revision |
Orders MCP 2025-06-18 | Handshake | 2025-06-18 · sessions · not the current revision |
Orders MCP 2026-07-28 | Handshake | 2026-07-28 · stateless · current |
If the server’s next release drops both sessions revisions, the first two tests fail, one with
Server no longer speaks protocol 2025-03-26 and the other with
Server no longer speaks protocol 2025-06-18, and the third keeps passing.
Saving each test runs it once first and saves it only if it passes, so a revision the server does not accept today cannot be saved as a pinned test. To see which revisions the server accepts right now, run a detection: it lists every revision, supported or not, without creating a test.