TellWorldAI 世界档案
问档案English

首页›实践›实践

实践

MCP 的 Streamable HTTP 传输怎么用

用 Streamable HTTP 运行 MCP 服务器:先确认规范版本,再了解通知与进度推送、安全要点,以及从 SSE 迁移的步骤。

这篇适合谁、读完能做到什么

你打算把 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 许可证发布。

来源

  1. 1
    HTTPS 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

相关动态