For Remote MCP, Design for Streamable HTTP
When MCP leaves a single machine, Streamable HTTP takes over from stdio. It has one MCP endpoint: each request is sent as a separate POST, and the response can be either JSON or a request-scoped SSE stream. It's worth fixing at once what it is not: this is an HTTP transport for JSON-RPC, not an arbitrary REST API where tool names turned into URL paths.
Here is what a remote tools/call looks like at the wire level - with the revision and routing headers.
POST /mcp HTTP/1.1
Host: tools.example.com
Content-Type: application/json
Accept: application/json, text/event-stream
Authorization: Bearer …
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: review_release
{
"jsonrpc": "2.0",
"id": "call-42",
"method": "tools/call",
"params": { … modern _meta … }
}And here is the routing logic on the server side - a description of behavior, not a ready-made file.
POST /mcp
validate Origin + authentication
validate version/method/name headers against body
parse one JSON-RPC request
authorize capability + arguments
return application/json
or request-scoped text/event-stream
POST /mcp method=subscriptions/listen
long-lived SSE stream for opted-in change notifications
GET /mcp and DELETE /mcp
405 Method Not Allowed in 2026-07-28The key shift here is that the modern transport doesn't tie lists, calls, and results to a TCP connection. That means cache and application state must be explicit. A plain JSON response fits a fast result - it's easier to proxy, observe, and retry. A request-scoped SSE is needed where progress and related notifications flow during a specific request. For long work use the task extension or a domain job id, not the hope that the next request lands on the same pod.
A broken stream doesn't resume automatically. The 2026-07-28 revision removed SSE redelivery via Last-Event-ID. A lost in-flight request is repeated with a new request id only if the operation allows a safe retry. Design idempotency up front, not after the first lost connection.The transport is chosen - but a production client must manage more than the happy path. Let's give it progress, cancellation, notifications, and a cache.