MCP Transport Checker

Work out which MCP transport an exchange is using and why it failed. Streamable HTTP and the older HTTP+SSE are different protocols with similar names, and a mismatch shows up as a 404 or a hang rather than a version error.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Check the exchange. Nothing leaves this tab.

Wanted a different tool?

  • MCP OAuth Flow Debugger if the transport is right and the server still returns 401, because that is the authorization flow rather than the protocol.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

A POST that accepts only JSON

The server picks JSON or a stream per request, so this works until the first response it chooses to stream

> POST /mcp HTTP/1.1
> Host: localhost:3000
> Accept: application/json
> Content-Type: application/json
> MCP-Protocol-Version: 2025-06-18
> Origin: http://localhost:3000
< HTTP/1.1 200 OK
< Content-Type: application/json

A 404 carrying a session id

Not a routing fault: it is the documented signal that the session is gone, and retrying gets the same 404 forever

> POST /mcp HTTP/1.1
> Host: localhost:3000
> Accept: application/json, text/event-stream
> Content-Type: application/json
> MCP-Protocol-Version: 2025-06-18
> Mcp-Session-Id: 1868a90c-8d3f-4a1b-9e2c-7f5a6b3d0e11
> Origin: http://localhost:3000
< HTTP/1.1 404 Not Found

The 2024-11-05 two-endpoint transport

A GET that streams plus an endpoint event is the deprecated HTTP+SSE form, which a Streamable HTTP client cannot talk to at all

> GET /sse HTTP/1.1
> Host: localhost:3000
> Accept: text/event-stream
< HTTP/1.1 200 OK
< Content-Type: text/event-stream

event: endpoint
data: /messages?sessionId=8f3a

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Assuming "MCP over HTTP" names one protocol

    HTTP+SSE from 2024-11-05 and Streamable HTTP from 2025-03-26 are different wire protocols. A client on one and a server on the other fail with a 404 on a path that exists, or a stream that opens and never delivers, never with a version error.

    Instead:Check which one the server implements before debugging anything else. Two endpoints with an `endpoint` event is the old one; a single endpoint answering POSTs is the new one.

  2. Sending `Accept: application/json` alone on a POST

    The server chooses per request whether to answer with JSON or an SSE stream. A client that accepts only one gets a 406, or worse, works until the first response the server decides to stream.

    Instead:Send `Accept: application/json, text/event-stream` on every POST, whatever you expect back.

  3. Retrying a 404 that carried a session id

    That 404 is the documented signal that the session expired or was terminated, not a routing fault. Retrying the same request with the same id gets the same 404 forever.

    Instead:Discard the `Mcp-Session-Id` and run `initialize` again. Retry is correct for a 5xx and wrong here.

  4. Omitting `MCP-Protocol-Version` after initialization

    Since 2025-06-18 a server that does not see the header is told to assume 2025-03-26. So a newer client silently gets older behaviour rather than an error, and the difference surfaces later as a feature that quietly does nothing.

    Instead:Send the negotiated version on every HTTP request after `initialize`, not only on the first one.

Two protocols, one name

HTTP+SSE from 2024-11-05 and Streamable HTTP from 2025-03-26 are both MCP over HTTP. A client on one side and a server on the other fail with a 404 or a connection that hangs, never with a version error.

The old transport uses two endpoints, the new one uses a single endpoint

HTTP+SSE opens a GET that streams, and the server delivers a separate POST URL in an endpoint event. Streamable HTTP has one endpoint that accepts POSTs and answers with either JSON or an SSE body, whichever it chooses for that request. A client POSTing to a server that only implements the old form gets a 404 on a path that exists.

HTTP+SSE          GET  /sse         stream opens
                  POST /messages    URL from the endpoint event

Streamable HTTP   POST /mcp         JSON or a stream
                  GET  /mcp         optional server stream

A POST must accept both content types

The server decides whether to answer with application/json or text/event-stream, and it can decide differently per request. A client sending Accept: application/json alone gets a 406, or worse, works until the first response the server chooses to stream. Send both, on every POST.

A 404 carrying a session id means the session is gone

The server returns Mcp-Session-Id on initialize and the client echoes it afterwards. A 404 on a request that carries one is the documented signal that the session expired or was terminated, which is why it reads as a routing problem so often. The correct response is to discard the id and initialize again, not to retry.

MCP-Protocol-Version is required after initialization

Since 2025-06-18 the client sends the negotiated version on every subsequent HTTP request. A server that does not see it is told to assume 2025-03-26, so a newer client silently gets older behaviour rather than an error, and the difference only shows up as a feature that quietly does not work.

Origin has to be validated, and local servers belong on loopback

A local MCP server on HTTP is reachable from any web page the user visits unless it checks Origin. That is DNS rebinding, and the specification requires servers to validate it. Bind to 127.0.0.1 rather than 0.0.0.0 as well: the two together are what keep a local server local.

What this cannot see

It reads pasted headers and connects to nothing, so it cannot tell you the server is unreachable, that TLS failed, or that a proxy is buffering. A stream that opens and delivers no data is usually buffering somewhere in between rather than a protocol fault, and curl with no proxy is the fastest way to confirm that. It also does not read the JSON-RPC payload: the MCP JSON-RPC message validator on this site does that.