这篇适合谁、读完能做到什么
你打算把 MCP 服务器放到网络上,让远程客户端访问,而且希望工具运行时能把进度实时告诉用户。读完这篇,你应该能分清 MCP 几种传输方式的适用场景,理解通知(notification)和流式输出在 MCP 里的含义,写出发送进度通知的服务器和接收通知的客户端,并知道迁移和安全上要注意的事。[1]
先看规范版本
这篇示例针对 MCP 规范 2025-11-25,演示的是旧的 initialize 握手、Mcp-Session-Id、GET 事件流和断点续传机制。提醒,MCP 2026-07-28 去掉了这些功能。新规范下的 Streamable HTTP 请求是独立的 POST 请求,带 MCP-Protocol-Version 和 Mcp-Method 头,需要时还带 Mcp-Name。[1]
因此在新项目里动手前,先读指向的《What's Changed in MCP: The 2026-07-28 Specification》,确认自己用的是哪个版本。下面的内容按 2025-11-25 示例讲解,遇到版本差异时会特别说明。[1]
传输方式怎么选
把 MCP 的传输方式分成三类。stdio 适合本地和命令行工具,简单,但说它不适合网页或云端。HTTP+SSE 是旧的远程传输,在 MCP 2025-03-26 中被弃用,由 Streamable HTTP 取代,说新实现不要再用它。Streamable HTTP 基于 HTTP,支持通知,扩展性更好,推荐用于大多数生产和云端场景。[1]
对比表把 stdio 和 Streamable HTTP 列为当前标准传输,HTTP+SSE 只在旧示例里出现。[1]
流式输出是什么
流式输出是指数据以小块或事件序列的形式发送和接收,而不是等整个响应准备好再一次返回。列出的典型场景有大文件、聊天或进度条这类实时更新,以及需要让用户持续了解进度的长时间计算。[1]
先给了一个普通 HTTP 流式的例子。Python 服务器用 FastAPI 的 StreamingResponse,媒体类型是 text/event-stream,每秒输出一条消息:
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")客户端用 requests 并设置 stream=True,逐行读取,收到就打印:
import requests
with requests.get("http://localhost:8000/stream", stream=True) as r:
for line in r.iter_lines():
if line:
print(line.decode())总结了三条要求:服务器要使用流式响应,客户端要按流来处理响应,内容类型通常是 text/event-stream 或 application/octet-stream。[1]
MCP 的流式和普通流式有什么不同
普通 HTTP 流式把进度当作主响应的一部分,以数据块的形式发出。MCP 则不同:主结果是最后一次性返回的一条响应,进度通过通知单独发送。说法是,MCP 的流式不是把主响应切块,而是在工具处理请求时向客户端发送通知。通知可以是进度、日志或其他事件,主结果仍然只发送一次。[1]
对两者的建议是:简单的流式需求用普通 HTTP 流式就够了;复杂的交互式应用,以及需要向用户持续报告 AI 长任务进度的场景,更适合 MCP 的通知机制。[1]
通知是什么
通知是一种 JSON-RPC 消息,没有 id,也不会收到响应。MCP 用它来传递进度、取消和其他单向事件。[1]
在 2025-11-25 中,客户端完成初始化握手后会发送 notifications/initialized。2026-07-28 已经没有初始化握手,所以这条通知属于旧行为。[1]
日志(Logging)是使用通知的一项功能。旧版规范下,服务器在 capabilities 中声明 logging 即可开启它:
{
"capabilities": {
"logging": {}
}
}提醒,不同的 SDK 可能默认开启日志,也可能需要在服务器配置里显式打开。列出的日志级别有 debug、info、notice、warning、error、critical、alert 和 emergency。[1]
需要注意的是,2026-07-28 中日志功能已被弃用。它仍保留以兼容旧版本,最早可能在 2027 年 7 月 28 日之后发布的规范修订中被移除。建议新实现改用 stdio 下的 stderr,或 OpenTelemetry 来做结构化观测。[1]
服务器怎么发进度通知
Python 例子中,工具的参数里有 ctx,类型是 Context。工具每处理一个文件,就调用一次 await ctx.info(),最后返回 TextContent:
@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}")要让通知生效,服务器必须使用流式传输。写法是调用 mcp.run(transport="streamable-http"):
mcp.run(transport="streamable-http")还给出了 .NET 的写法,工具里用 ctx.Info() 发送信息,服务器用 UseStreamableHttp() 启用 Streamable HTTP 传输。[1]
客户端怎么接收通知
客户端需要一个消息处理函数(message handler)。 Python 写法是判断收到的消息是不是 types.ServerNotification:是通知就打印为通知,否则当作普通的服务器消息处理。创建 ClientSession 时把它传进去:
async def message_handler(message):
if isinstance(message, types.ServerNotification):
print("NOTIFICATION:", message)
else:
print("SERVER MESSAGE:", message)连接远程服务器时,使用的是 Python SDK 里的 streamablehttp_client,它来自 mcp.client.streamable_http:
from mcp.client.streamable_http import streamablehttp_client进度通知的典型做法
进度示例是一个处理十份文档的工具,每份文档发送一条 ctx.info,结束时发送一条完成消息。客户端收到的内容会依次是 "Processing document 1/10" 到 "Processing complete!",最后才是主结果:
@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}")认为,进度通知能让用户看到工作在推进,客户端可以据此显示进度条或日志,开发者也更容易发现哪一步慢或卡住。[1]
安全要点
强调,通过 HTTP 暴露 MCP 服务器时,安全是首要问题。Streamable HTTP 会带来新的攻击面,需要认真配置:
- 校验
Origin请求头,防止 DNS 重绑定攻击。 - 本地开发时把服务器绑定到
localhost,避免暴露到公网。 - 生产环境要做认证,例如 API 密钥或 OAuth。
- 配置 CORS,限制访问来源。
- 生产环境使用 HTTPS 加密流量。[1]
还提醒,不能信任未经验证的请求,要记录并监控所有访问和错误,并及时更新依赖以修补漏洞。[1]
从 SSE 迁移到 Streamable HTTP
认为,迁移的理由有两条:Streamable HTTP 的扩展性、兼容性和通知支持都比 SSE 好,并且它是新 MCP 应用推荐的传输方式。迁移步骤有四步:把服务器改为在 mcp.run() 中使用 transport="streamable-http";客户端改用 streamablehttp_client,不再用 SSE 客户端;在客户端实现消息处理函数;测试与现有工具和工作流的兼容性。[1]
迁移期间,建议保持对旧 SSE 客户端的兼容,例如让两种传输运行在不同的端点上,然后逐步迁移客户端。也提到两个难点:要确保所有客户端都已更新,以及两种方式的通知投递方式有差异。[1]
常见问题和限制
- 示例版本较旧。 示例针对
2025-11-25,新规范已经移除了其中的握手和会话机制。照抄前先核对规范版本。[1] - 日志功能会被移除。 在
2026-07-28中日志已弃用,新实现应考虑 stderr 或 OpenTelemetry。[1] - 可选练习会把查询发给第三方。 有一个可选练习,连接托管的搜索 MCP 服务器,说明服务会收到搜索词和一个随机的会话标识,并建议只用公开信息。本文不展开这个练习。[1]
下一步
可以自己写一个服务器工具,处理一组条目并为每一项发送通知,再写一个客户端,用消息处理函数实时显示这些通知。这是检验本篇内容最直接的办法。[1]
本文改编自 Microsoft 开源课程 *mcp-for-beginners* 入门部分第 6 课《HTTPS Streaming with Model Context Protocol (MCP)》[1],原文以 MIT 许可证发布。
来源
- 1HTTPS Streaming with Model Context Protocol (MCP)Microsoft mcp-for-beginners (MIT)
引用本页: MCP 的 Streamable HTTP 传输怎么用. TellWorld, https://www.tellworld.net/zh/practice/practice-mcp-streamable-http. 更新于 2026-11-14