TellWorldAI World Archive
Ask中文

Home›Practice›Practice

Practice

MCP over Streamable HTTP

Run an MCP server over Streamable HTTP: check the spec version first, then learn notifications and progress updates, security basics and how to migrate from SSE.

Who this is for and what you will get

You want to put an MCP server on the network so remote clients can reach it, and you want a long-running tool to report its progress as it works. By the end you should know which transport fits which situation, what notifications and streaming mean in MCP, how to write a server that sends progress notifications and a client that receives them, and what to watch for on security and migration. [1]

Check the specification version first

The examples target MCP specification 2025-11-25. They show the legacy initialize handshake, the Mcp-Session-Id header, the GET event stream and resumability, which MCP 2026-07-28 removes. Under 2026-07-28, a Streamable HTTP request is a self-contained POST carrying MCP-Protocol-Version and Mcp-Method headers, plus Mcp-Name where required. [1]

For a new implementation, read the referenced document "What's Changed in MCP: The 2026-07-28 Specification" first, and confirm which version you are targeting. The material below follows the 2025-11-25 examples and points out differences where they matter. [1]

Choosing a transport

MCP transports fall into three kinds. stdio suits local and command-line tools; it is simple, but it is not suitable for the web or the cloud. HTTP+SSE was the legacy remote transport, deprecated in MCP 2025-03-26 and replaced by Streamable HTTP, and new implementations should not use it. Streamable HTTP is HTTP-based, supports notifications and scales better, and it is recommended for most production and cloud scenarios. [1]

The table lists stdio and Streamable HTTP as current, and HTTP+SSE as deprecated and found only in older examples. [1]

What streaming means

Streaming sends data in small pieces or as a sequence of events instead of waiting for the whole response. The typical uses are large files, real-time updates such as chat or progress bars, and long computations where the user should be kept informed. [1]

Plain HTTP streaming comes first. The Python server uses FastAPI's StreamingResponse with the media type text/event-stream and yields one message per second:

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import time

app = FastAPI()

async def event_stream():
    for i in range(1, 6):
        yield f"data: Message {i}\n\n"
        time.sleep(1)

@app.get("/stream")
def stream():
    return StreamingResponse(event_stream(), media_type="text/event-stream")

The client uses requests with stream=True and prints each line as it arrives:

import requests

with requests.get("http://localhost:8000/stream", stream=True) as r:
    for line in r.iter_lines():
        if line:
            print(line.decode())

There are three requirements: the server uses a streaming response, the client processes the response as a stream, and the content type is usually text/event-stream or application/octet-stream. [1]

How MCP streaming differs

In classic HTTP streaming, progress is part of the main response, sent as data chunks. In MCP, the main result is one response sent at the end, and progress arrives as notifications. The point is that MCP does not chunk the main response; while a tool works, it sends notifications such as progress, logs or other events, and the main result still comes once. [1]

The advice is that plain HTTP streaming is enough for simple needs, while MCP's notification model fits complex interactive applications, and long AI tasks where users should be kept informed of progress. [1]

What a notification is

A notification is a JSON-RPC message with no id, and it receives no response. MCP uses notifications for progress, cancellation and other one-way events. [1]

Under 2025-11-25, the client sends notifications/initialized after the initialization handshake. 2026-07-28 has no initialization handshake, so that notification is legacy behavior. [1]

Logging is one feature that uses notifications. Under the legacy spec, the server enables it by declaring a logging object in its capabilities:

{
  "capabilities": {
    "logging": {}
  }
}

Depending on the SDK, logging may be on by default or may need to be enabled in the server configuration. The levels are debug, info, notice, warning, error, critical, alert and emergency. [1]

Note that under 2026-07-28 the Logging feature is deprecated. It remains for compatibility and is eligible for removal in the first specification revision released on or after July 28, 2027. For new implementations, stderr with stdio or OpenTelemetry is recommended for structured observability. [1]

Sending progress notifications from the server

In the Python example, the tool takes a ctx of type Context. For each file it processes, it calls await ctx.info(), and it finally returns a TextContent result:

@mcp.tool(description="A tool that sends progress notifications")
async def process_files(message: str, ctx: Context) -> TextContent:
    await ctx.info("Processing file 1/3...")
    await ctx.info("Processing file 2/3...")
    await ctx.info("Processing file 3/3...")
    return TextContent(type="text", text=f"Done: {message}")

For notifications to work, the server must use a streaming transport, and this is done with mcp.run(transport="streamable-http"):

mcp.run(transport="streamable-http")

A .NET version is also shown, in which the tool calls ctx.Info() and the server uses UseStreamableHttp(). [1]

Receiving notifications in the client

The client needs a message handler. The Python handler checks whether an incoming message is a types.ServerNotification; if it is, it prints it as a notification, and otherwise it treats it as a regular server message. The handler is passed to ClientSession:

async def message_handler(message):
    if isinstance(message, types.ServerNotification):
        print("NOTIFICATION:", message)
    else:
        print("SERVER MESSAGE:", message)

To connect over Streamable HTTP, the Python client uses streamablehttp_client from the SDK's streamable HTTP module:

from mcp.client.streamable_http import streamablehttp_client

A typical progress pattern

The progress example processes ten documents, sending one ctx.info message per document and a completion message at the end. The client sees "Processing document 1/10" through "Processing complete!" before the final result:

@mcp.tool(description="A tool that sends progress notifications")
async def process_files(message: str, ctx: Context) -> TextContent:
    for i in range(1, 11):
        await ctx.info(f"Processing document {i}/10")
    await ctx.info("Processing complete!")
    return TextContent(type="text", text=f"Done: {message}")

There are three reasons for progress notifications: users see work advancing, clients can show progress bars or logs, and developers can more easily spot where a process is slow or stuck. [1]

Security basics

Security comes first when an MCP server is exposed over HTTP, because Streamable HTTP brings new attack surfaces. It recommends validating the Origin header to prevent DNS rebinding attacks, binding to localhost during local development, adding authentication such as API keys or OAuth in production, configuring CORS, and using HTTPS in production. [1]

It also advises never trusting unvalidated requests, logging and monitoring all access and errors, and keeping dependencies updated. [1]

Migrating from SSE

There are two reasons to move from SSE: Streamable HTTP offers better scalability, compatibility and notification support, and it is the recommended transport for new MCP applications. The migration has four steps: set the server to transport="streamable-http" in mcp.run(), switch the client to streamablehttp_client in place of the SSE client, implement a message handler, and test compatibility with existing tools and workflows. [1]

During the move, it helps to keep SSE clients working, for example by running both transports on different endpoints, and migrating clients gradually. Its named challenges are making sure every client is updated, and handling differences in how notifications are delivered. [1]

Common problems and limits

  • The examples are for an older spec. The examples target 2025-11-25, and the newer specification removes their handshake and session mechanisms. Check the version before copying code. [1]
  • Logging is being removed. Under 2026-07-28 Logging is deprecated, so new implementations should consider stderr or OpenTelemetry. [1]
  • An optional exercise sends data to a third party. The optional exercise connects to a hosted search MCP server. The service receives the search queries and a random session identifier, and readers are asked to use only public information. This guide does not walk through it. [1]

Next steps

A useful test of this material is to build build a server tool that processes a list of items and sends a notification for each one, then write a client whose message handler shows the notifications as they arrive. [1]

Adapted from lesson 6 of the introductory section of Microsoft's open-source course *mcp-for-beginners*, "HTTPS Streaming with Model Context Protocol (MCP)"[1], released under the MIT License.

Sources

  1. 1
    HTTPS Streaming with Model Context Protocol (MCP)Microsoft mcp-for-beginners (MIT)

Cite this page: MCP over Streamable HTTP. TellWorld, https://www.tellworld.net/practice/practice-mcp-streamable-http. Updated 2026-11-14

Related news

View all