在MCP(Model Context Protocol)中,为客户端-服务器通信定义了两种默认标准传输机制:
-
stdio(标准输入输出) 适用于本地通信
-
HTTP with SSE(Server-Sent Events) 适用于远程通信
其差异主要体现在通信场景、传输方式、协议实现等方面。
https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/
一、通信场景与部署方式
1、stdio(标准输入输出)
适用于客户端与服务端在同一台机器上的场景。
客户端通过启动服务端子进程(如命令行工具),利用操作系统的管道机制(stdin/stdout)进行数据传输。
是个同步阻塞模型,通信基于顺序处理,需等待前一条消息完成传输后才能处理下一条,适合简单的本地批处理任务。
2、HTTP with SSE(Server-Sent Events)
客户端与服务端可部署在不同节点,通过HTTP协议实现跨网络通信。
是个异步事件驱动。
-
服务端通过SSE长连接主动推送数据,
-
客户端通过HTTP POST端点发送请求,
支持实时或准实时交互,适合分布式系统或需要高并发的场景。
二、传输机制与协议实现
特性 | stdio | HTTP with SSE |
---|---|---|
协议基础 | 操作系统管道 | HTTP/1.1长连接 |
消息格式 | JSON-RPC 2.0,以换行符分隔 JSON-RPC | 2.0,通过SSE事件流传输 |
连接方向 | 双向(客户端↔服务端) | 客户端通过POST发送请求,服务端通过SSE单向推送响应 |
错误处理 | 依赖管道机制 | 支持HTTP状态码和SSE自动重连机制 |
适用场景 | 本地工具链、CLI应用 | 分布式系统、实时监控、远程服务调用 |
三、技术细节对比
1、stdio传输的核心规则
-
消息必须为UTF-8编码的JSON-RPC格式,以换行符
\n
分隔。 -
服务端通过
stderr
输出日志,客户端可选择处理或忽略。 -
严格禁止在
stdout
中写入非协议消息,避免解析错误。
服务端:
https://github.com/modelcontextprotocol/python-sdk/blob/main/src/mcp/server/stdio.py
async def run_server():
async with stdio_server() as (read_stream, write_stream):
# read_stream contains incoming JSONRPCMessages from stdin
# write_stream allows sending JSONRPCMessages to stdout
server = await create_my_server()
await server.run(read_stream, write_stream, init_options)
anyio.run(run_server)
read_stream
来自stdin
的传入JSONRPCMessages
write_stream
将JSONRPCMessages
发送到stdout
2、SSE传输的实现要求
-
服务端需提供两个端点:
-
SSE端点:客户端通过此建立长连接,接收事件流(如
/sse
)。 -
HTTP POST端点:客户端发送请求至此(如
/messages
)。
-
-
消息推送流程:客户端首次连接时,服务端返回SSE端点的URI;后续所有请求通过POST发送,响应通过SSE事件流返回。
以 Python 实现为例:
服务端:
https://github.com/modelcontextprotocol/python-sdk/blob/main/src/mcp/server/sse.py
# Create an SSE transport at an endpoint
sse = SseServerTransport("/messages/")
# Create Starlette routes for SSE and message handling
routes = [
Route("/sse", endpoint=handle_sse),
Mount("/messages/", app=sse.handle_post_message),
]
# Define handler functions
async def handle_sse(request):
async with sse.connect_sse(
request.scope, request.receive, request._send
) as streams:
await app.run(
streams[0], streams[1], app.create_initialization_options()
)
# Create and run Starlette app
starlette_app = Starlette(routes=routes)
uvicorn.run(starlette_app, host="0.0.0.0", port=port)
在 routes 中,只有 Route("/sse", endpoint=handle_sse)
是用于长连接的。这个路由设置了一个 SSE (Server-Sent Events) 的长连接终端点,用于持续向客户端推送消息。
而 Mount("/messages/", app=sse.handle_post_message)
则是用于处理客户端发送的 POST 请求,这通常是短连接。
四、协议扩展性
1、自定义传输机制:
MCP允许开发者实现其他传输方式(如WebSocket、gRPC),但需满足JSON-RPC 2.0的消息格式和生命周期管理。
如需实现双向实时通信(如游戏或双向聊天),就需要基于 MCP 自定义其他传输(如 WebSocket)。
2、远程连接支持:
当前MCP官方仅支持本地通信,远程连接功能(如OAuth认证、服务发现)计划在2025年路线图中实现。
五、总结与选择建议
1、选择stdio的场景:
本地调试、资源受限环境、简单流水线任务(如grep | awk式处理)。
2、选择SSE的场景:
需要低延迟、跨网络通信、多客户端订阅(如实时日志推送、分布式微服务)