在日常开发中,与AI模型交互的通信协议设计得越优雅,应用构建就越顺畅。Model Context Protocol(MCP,模型上下文协议)正是这样一种专为AI应用打造的客户端-服务器通信协议。它通过标准化的消息格式与生命周期管理,确保客户端(如IDE插件、聊天界面)与服务器(如AI模型后端)之间的高效、可靠交互。要实现这一目标,双方必须依赖一个共同的“传输层”,该传输层定义了消息具体如何被实际发送和接收。
目前,MCP定义了两种标准的传输机制:stdio和Streamable HTTP。stdio主要用于客户端启动并管理服务器子进程的场景,通信通过标准输入输出来进行。而Streamable HTTP专为网络环境设计,允许客户端和服务器作为独立进程,通过HTTP进行通信。今天,我们就重点聊聊Streamable HTTP是什么,以及如何在实际开发中应用它。

MCP的通信基础:JSON-RPC与生命周期
在深入了解HTTP传输之前,我们先弄清楚MCP通信的两个基本前提:消息格式和交互流程。
MCP明确规定,所有消息必须采用JSON-RPC 2.0格式进行编码。JSON-RPC是一种轻量级的远程过程调用协议,它将每一次通信都封装成一个JSON对象,其中包含方法名method、参数params、请求IDid等字段。这样一来,通信内容变得结构化,非常易于解析和调试。
那么,MCP的交互流程是怎样的呢?它遵循一个严格的生命周期,分为三个阶段:初始化(Initialization)、操作(Operation)和关闭(Shutdown)。
- 初始化:这是客户端与服务器的第一次交互。客户端会发送一个
initialize请求,双方交换并协商协议版本、功能支持等信息。 - 操作:初始化成功后,连接进入操作阶段。客户端和服务器可以根据协商好的能力,自由交换各类JSON-RPC消息。
- 关闭:当通信结束时,通过关闭底层连接来终止会话。
理解这个生命周期至关重要,因为它规定了通信的“先后顺序”——客户端必须在发送任何业务请求之前,先完成初始化。
MCP的两种标准传输方式
有了统一的消息格式和交互流程,接下来就是选择一种方式来“搬运”这些JSON-RPC消息。MCP官方定义了两种传输方式。
| 特性 | stdio | Streamable HTTP |
|---|---|---|
| 进程关系 | 客户端启动服务器作为子进程 | 客户端和服务器是独立进程 |
| 通信方式 | 标准输入(stdin)和标准输出(stdout) | HTTP POST 和 GET 请求 |
| 适用场景 | 本地集成工具,如IDE插件 | 网络服务,远程或本地服务器 |
| 连接管理 | 客户端管理子进程的生命周期 | 可处理多个客户端连接 |
| 流式传输 | 天然支持 | 通过Server-Sent Events (SSE) 实现 |
stdio方式简单直接,非常适合本地环境。但一旦客户端和服务器需要解耦、独立部署并通过网络通信时,Streamable HTTP就成了必然选择。它不仅提供了标准HTTP的灵活性,还通过Server-Sent Events (SSE) 实现了高效的服务端推送能力。
深入Streamable HTTP传输
Streamable HTTP的核心设计是提供一个单一的HTTP端点路径(例如https://example.com/mcp),该路径同时支持POST和GET请求,以满足不同的通信需求。
POST请求主要用于客户端向服务器发送消息,而GET请求则用于客户端建立一个持久的连接,以接收来自服务器的主动推送。这种推送通常通过Server-Sent Events (SSE) 实现,它允许服务器在一个长效的HTTP连接上,向客户端单向流式传输数据。
安全性:不可忽视的前提
在网络环境中暴露服务,安全性是第一要务。MCP规范明确提出了在实现Streamable HTTP传输时必须遵守的安全准则:
- 验证Origin头:服务器必须检查所有请求的
OriginHTTP头,以防止DNS重绑定攻击。这种攻击可能让恶意网站冒充合法来源,与本地运行的MCP服务器进行交互。 - 绑定本地主机:在本地开发或运行服务时,服务器应仅绑定到
localhost(127.0.0.1),而不是所有网络接口(0.0.0.0)。这可以防止局域网内的其他设备意外访问到你的服务。 - 实现身份验证:所有连接都应该有适当的认证机制,确保只有授权的客户端才能访问服务器。
忽略这些保护措施,可能会给应用带来严重的安全风险。
客户端向服务器发送消息:POST请求
当客户端需要向服务器发送一个JSON-RPC消息(无论是请求、通知还是响应)时,它必须发起一个HTTP POST请求到MCP端点。
这个POST请求的主体部分就是一个完整的JSON-RPC消息。同时,请求头中必须包含Accept字段,声明客户端能够同时接受application/json和text/event-stream两种响应类型。
服务器收到POST请求后的行为取决于收到的JSON-RPC消息类型:
- 如果消息是通知(
notification)或响应(response),服务器在成功处理后应返回HTTP 202 Accepted状态码,且响应体为空。这表示服务器已经收到并接受了该消息。 - 如果消息是请求(
request),服务器有两种响应方式。它可以返回Content-Type: application/json,将单个JSON-RPC响应作为HTTP响应体返回;或者,它可以返回Content-Type: text/event-stream,开启一个SSE流,在该流上逐步发送一个或多个消息,并最终包含对该请求的响应。
当服务器选择开启SSE流来响应一个请求时,它可以在发送最终的JSON-RPC响应之前,先推送一些相关的通知或中间状态。这种机制非常适合执行时间较长的任务,客户端可以实时收到进度更新。
客户端监听服务器消息:GET请求
除了通过POST请求触发通信,客户端还可以主动发起HTTP GET请求来打开一个专门用于监听服务器消息的通道。这允许服务器在没有任何客户端请求的情况下,主动向客户端推送消息,例如配置更新、全局通知等。
客户端发起GET请求时,必须在Accept头中指明支持text/event-stream。服务器如果支持此功能,就会返回Content-Type: text/event-stream并建立一个SSE连接。
需要注意的是,通过GET请求建立的SSE流,其用途与POST请求响应的流不同。它主要用于承载与特定客户端请求无关的、由服务器主动发起的通信。因此,服务器不应该在这个流上发送JSON-RPC响应,除非是为了恢复一个之前中断的连接。
将生命周期应用于HTTP传输
了解了POST和GET的基本用法后,我们来看看MCP的生命周期是如何在Streamable HTTP上具体实现的。
初始化与会话建立
所有通信都始于初始化。客户端通过向MCP端点发送一个POST请求来启动这个过程,请求体是一个initialize方法的JSON-RPC消息。
{"jsonrpc": "2.0","id": 1,"method": "initialize","params": {"protocolVersion": "2025-06-18","capabilities": {},"clientInfo": {"name": "ExampleClient","version": "1.0.0"}}}
服务器收到后,会返回一个包含其自身能力和信息的JSON-RPC响应。对于Streamable HTTP传输,这个响应中还有一个非常关键的部分:Mcp-Session-Id HTTP头。
这个头字段包含一个由服务器生成的唯一会话ID。客户端在收到后,必须在后续所有请求中都带上这个ID。这标志着一个有状态的会话正式建立。
会话管理与版本控制
一旦会话建立,客户端的每一次后续请求都必须包含两个重要的HTTP头:Mcp-Session-Id和MCP-Protocol-Version。
Mcp-Session-Id:用于标识客户端属于哪个会话,让服务器能够管理和隔离不同客户端的状态。MCP-Protocol-Version:告知服务器客户端当前使用的协议版本,该版本是在初始化阶段协商确定的。
一个典型的后续请求(例如,一个initialized通知)看起来像这样:
POST /mcp HTTP/1.1Host: example.comContent-Type: application/jsonAccept: application/json, text/event-streamMcp-Session-Id: 1868a90c-a57d-4879-881b-90f7d58f4f3cMCP-Protocol-Version: 2025-06-18{"jsonrpc": "2.0","method": "notifications/initialized"}
如果服务器收到一个缺少有效会话ID的请求(初始化请求除外),它应该返回HTTP 400 Bad Request。如果一个会话ID已过期或被服务器终止,服务器则会返回HTTP 404 Not Found,此时客户端需要重新发起初始化流程来建立新会话。
客户端也可以通过发送一个带Mcp-Session-Id头的DELETE请求来主动终结一个会话。
提升通信的可靠性
网络总是不稳定的,连接随时可能中断。Streamable HTTP传输机制也考虑到了这一点,提供了连接恢复的能力。
连接中断与恢复
当服务器通过SSE推送消息时,它可以为每个事件附加一个唯一的id字段。这个ID在会话内是全局唯一的,可以看作是消息流中的一个“光标”。
如果客户端的SSE连接意外断开,它可以重新发起一个GET请求,并在请求头中加入Last-Event-ID字段,其值为它收到的最后一个事件的ID。
服务器收到这个头后,便可以从那个断开点开始,重发所有丢失的消息,然后继续正常推送。这确保了即使在不稳定的网络下,客户端也能收到完整的消息序列,极大地提升了通信的可靠性。
通过POST和GET请求的组合,辅以会话管理和连接恢复机制,MCP Streamable HTTP确实为构建健壮、灵活的AI应用通信架构提供了坚实的基础。


