Skip to content

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.

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 one server/discover request. There is no initialize, no event stream and no session.
  • Sessions (2025-03-26, 2025-06-18, 2025-11-25): the test sends initialize proposing the revision, then notifications/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 sends initialize and notifications/initialized to 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.

RevisionGenerationNoteSends MCP-Protocol-Version
2024-11-05HTTP+SSE transportdeprecated, eligible for removalNever
2025-03-26sessionsnot the current revisionNever
2025-06-18sessionsnot the current revisionOn every request after initialize
2025-11-25sessionsnot the current revisionOn every request after initialize
2026-07-28statelesscurrentOn 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 (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.

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/discover whose body is not one of the JSON-RPC errors -32020, -32021, -32022 or -32601, or a -32601 reply at any status.
  • On a sessions revision: a 4xx other than 401 and 403 in reply to initialize whose 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.

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.

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.

detect_mcp_protocol is read-only and takes mcpUrl and, optionally, mcpCredentialId. See the API tests tools. The answer carries:

  • outcome: DETECTED when at least one revision is supported, NONE when none is, RATE_LIMITED when the server answered with a rate limit, with its Retry-After value in retryAfterHeader.
  • newestSupported and the server’s serverInfo.
  • revisions, one entry per revision with revision, generation, supported and note, plus serverInfo for a supported revision or evidence for 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).

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. (outcome NONE)
  • 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.

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:

NameCheck depthProtocol revision
Orders MCP 2025-03-26Handshake2025-03-26 · sessions · not the current revision
Orders MCP 2025-06-18Handshake2025-06-18 · sessions · not the current revision
Orders MCP 2026-07-28Handshake2026-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.