C.W.K.
Stream
Lesson 02 of 05 · published

Streamable HTTP

~24 min · http, sse, streaming, remote

Level 0Curious Reader
0 XP0/48 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

Streamable HTTP is the transport for any MCP server that wants to live behind a URL: shared services, cloud hosts, multi-tenant servers. It replaces the older "HTTP+SSE" transport (now deprecated) with a single endpoint that handles both directions over standard HTTP.

The wire model: the client POSTs a JSON-RPC request to the server's endpoint and the server responds in one of two ways. For a simple request, it returns a normal HTTP response with the JSON-RPC result in the body. For a long-running or streaming request, it returns a Server-Sent Events (SSE) stream and writes JSON-RPC messages as data: lines as they become ready. Either way, the JSON-RPC framing is the same; the HTTP envelope just lets the server pick "one shot" vs. "stream" at runtime.

Notifications from server to client (e.g. notifications/tools/listChanged) flow over the same SSE stream. The client opens a long-lived GET on the endpoint to receive them; the server pushes notifications down it as they happen. One TCP connection, two logical channels.

The win over the old HTTP+SSE transport is operational: one endpoint, one auth flow, one set of CORS rules, no fan-out across multiple URLs. The win over stdio is obvious: it is the network. It is what an MCP server-as-a-service looks like.

Code

Streamable HTTP — request/response·text
POST /mcp HTTP/1.1
Content-Type: application/json
Authorization: Bearer ...

{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{...}}

HTTP/1.1 200 OK
Content-Type: application/json

{"jsonrpc":"2.0","id":1,"result":{...}}
Streamable HTTP — SSE for streaming results·text
POST /mcp HTTP/1.1
Content-Type: application/json
Accept: text/event-stream
Authorization: Bearer ...

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"build_codebase",...}}

HTTP/1.1 200 OK
Content-Type: text/event-stream

data: {"jsonrpc":"2.0","method":"notifications/progress","params":{"requestId":2,"progress":0.4}}

data: {"jsonrpc":"2.0","method":"notifications/progress","params":{"requestId":2,"progress":0.8}}

data: {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"build complete"}]}}
Connecting to a Streamable HTTP server (Python client)·python
from mcp.client.streamable_http import streamablehttp_client

async with streamablehttp_client("https://api.example.com/mcp", headers={"Authorization": "Bearer ..."}) as (read, write, _):
    async with ClientSession(read, write) as s:
        await s.initialize()
        tools = await s.list_tools()

External links

Exercise

Spin up a Streamable HTTP MCP server (the Python SDK ships an example) behind something simple like ngrok. Connect to it from a client SDK; then connect from curl and observe the SSE bytes for a long-running tool call. Reading the raw event stream once demystifies streaming forever.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.