curl -s https://www.pathwren.workers.dev/mcp-transport.json # this page, as JSON
No key, no account, no handshake — every page here has a JSON twin one hop away. Machine doors: 6 keyless GET tools · documents.json · changes · llms.txt · openapi.json · agent card · mcp · a2a
Every request shape our three MCP endpoints can be sent, what it returns, and why.
Applies identically to /mcp, /mcp/triage, /mcp/doctor
and to their /c/<channel>/ copies. Measured live, not asserted.
| Request | Status | Body |
|---|---|---|
POST JSON-RPC | 200 | The JSON-RPC result. This is the transport; everything else on this page is discovery. |
GET accept: application/json | 200 | The server card: name, version, protocol versions, capabilities, tools, catalogue. |
GET accept: application/json, text/event-stream;q=0.9 | 200 | The same card. JSON is ranked above the stream, so JSON is what you get — RFC 9110 §12.5.1. |
GET no accept header | 200 | The same card. No Accept means anything is acceptable. |
HEAD (any of the above) | mirrors the GET | Nothing. Same status, same content-type, same allow, and content-length of the body the GET would have sent. |
GET or HEAD accept: text/event-stream | 200 text/event-stream | A real stream: valid, empty, closed immediately, with the one call that needs nothing from you written into its comment lines. See below. |
OPTIONS | 204 | CORS preflight; every origin is allowed. |
PUT, PATCH, anything else | 405 | allow: GET, HEAD, POST, DELETE, OPTIONS — and every method in that list works. |
# check any row of that table yourself curl -si https://www.pathwren.workers.dev/mcp/doctor -H 'accept: application/json' | head -1 # 200 curl -sI https://www.pathwren.workers.dev/mcp/doctor # 200, no body curl -si https://www.pathwren.workers.dev/mcp/doctor -H 'accept: text/event-stream' | head -1 # 200, and the stream says what to POST
A GET that ranks text/event-stream at or above everything else is
asking to open a standalone server-to-client SSE stream. Until 2026-09-03 we answered
405 Method Not Allowed. We now answer 200 with a real, empty,
immediately-closed stream. Both are correct, and the change is worth writing down because the
page previously argued the opposite case in full.
Content-Type: text/event-stream in response to
this HTTP GET, or else return HTTP 405 Method Not Allowed.” (2025-06-18.) The 405 clause
this page used to quote — “HTTP GET or DELETE to the MCP endpoint: respond with 405 Method Not
Allowed” — is addressed to “a server that supports ONLY this revision”, and this host
also speaks 2025-06-18 and 2025-03-26, where the stream exists. Both answers conform; the choice
was ours./c/mcp-registry-official/…. Three were that client's opening request to the
endpoint (node, 08:52:59 on /mcp/robots, 09:04:41 on /mcp/doctor
and /mcp/triage) and none of those three ever came back. A refusal read in context is an
answer; a refusal read as the first row of a scan is a record that this endpoint refused.retry: — no client reconnect-loops on it — writes
the one call that needs nothing from the caller into SSE comment lines, which every parser ignores
and every log keeps, and closes. No client waits for a message that is never coming.What this page said before was that “every client that has met this 405 here went on to
finish its session over POST anyway.” That was true of the log it was written from and stopped
being true: in the window above, undici recovered every time and node
did not once. The revert condition is written into the code beside the change — if
notifications/initialized per initialize does not improve and GET rows
start looping, the 405 document goes back, and it is kept whole in the source for exactly that.
Comments, and nothing else — a client SDK sees a valid empty stream and no JSON-RPC frame it never asked for, while anything that reads bytes gets the complete first call:
curl -s https://www.pathwren.workers.dev/mcp/doctor -H 'accept: text/event-stream'
Not “HEAD returns 200” — mirrors. The endpoint builds the real GET response and
removes the body, so HEAD is still correct after whatever GET does next, including the stream
above: HEAD with accept: text/event-stream returns that 200 with no body.
RFC 9110 §9.3.2.
Until 2026-09-01 HEAD fell through to the unsupported-method branch and returned 405 on every one of these endpoints, which cost at least one real client three failed probes before anybody owned the row.
A 405 carrying allow: GET, … on a refused GET tells a reader that the header
and the behaviour disagree, and it is the first thing an automated grader checks. So:
PUT and friends — allow is the full set
GET, HEAD, POST, DELETE, OPTIONS, and every method in it works.allow is POST, OPTIONS: what works for a client sending
that Accept header. The complete method set is still in the body under
allow_any_accept, and vary: accept marks the response as negotiated,
so nothing is hidden by the narrower header.These servers accept 2026-07-28, 2025-11-25,
2025-06-18, 2025-03-26 and 2024-11-05 for version
negotiation on POST, and POST answers all of them. The mechanisms the older revisions added
around the POST — the standalone GET stream, Mcp-Session-Id sessions,
Last-Event-ID resumption — are not implemented, and per 2026-07-28 a session id
is ignored rather than minted or echoed. If your client needs the deprecated 2024-11-05
HTTP+SSE transport specifically, it will not work here, and the 405 says so rather than
letting you discover it after a handshake.
The six servers: ai-crawler-index, crawler-log-triage, agent-discovery-doctor, robots-policy-lint, crawler-ip-verifier, mcp-endpoint-lint. Specification: modelcontextprotocol.io.
This page as markdown: /mcp-transport.md — the same text, no markup to strip, no JavaScript, no key, CC0. Every page here has one: add .md to any address (also .mdx, <page>.html.md, <page>.html.mdx), or send Accept: text/markdown to this one. All of them in a single index: /sitemap.md.