You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4.1 KiB
4.1 KiB
MCP Server (Model Context Protocol Server),即模型上下文协议服务器, 是一种基于标准化协议的服务端程序。 它的核心作用是为大语言模型 (LLM) 提供外部数据和功能支持。 可以将其理解为一个标准化的 工具接口 。 例如,Fetch MCP Server 能够抓取网页内容,而 Google Drive MCP Server 则可以实现云端文件的读取。
MCP Server 的关键特点在于其 被动性 。 它如同一个工具箱,静静地等待指令,只在接收到明确的调用请求后才会执行相应的操作,并不主动参与决策或推理过程。
!
一、通信机制
特性 | stdio | HTTP with SSE |
---|---|---|
协议基础 | 操作系统管道 | HTTP/1.1长连接 |
消息格式 | JSON-RPC 2.0,以换行符分隔 JSON-RPC | 2.0,通过SSE事件流传输 |
连接方向 | 双向(客户端↔服务端) | 客户端通过POST发送请求,服务端通过SSE单向推送响应 |
错误处理 | 依赖管道机制 | 支持HTTP状态码和SSE自动重连机制 |
适用场景 | 本地工具链、CLI应用 | 分布式系统、实时监控、远程服务调用 |
1.stdio(标准输入输出)
适用于客户端与服务端在同一台机器上的场景。
客户端通过启动服务端子进程(如命令行工具),利用操作系统的管道机制(stdin/stdout)进行数据传输。
是个同步阻塞模型,通信基于顺序处理,需等待前一条消息完成传输后才能处理下一条,适合简单的本地批处理任务。
2.HTTP with SSE(Server-Sent Events)
客户端与服务端可部署在不同节点,通过HTTP协议实现跨网络通信。 是个异步事件驱动。
- 服务端通过SSE长连接主动推送数据,
- 客户端通过HTTP POST端点发送请求, 支持实时或准实时交互,适合分布式系统或需要高并发的场景
二、技术实现
2.1 STDIO
- 消息必须为UTF-8编码的JSON-RPC格式,以换行符
\n
分隔。 - 服务端通过
stderr
输出日志,客户端可选择处理或忽略。 - 严格禁止在
stdout
中写入非协议消息,避免解析错误。
服务端代码demo
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.2 HTTP WITH SSE
- 服务端需提供两个端点:
- SSE端点:客户端通过此建立长连接,接收事件流(如
/sse
)。 - HTTP POST端点:客户端发送请求至此(如
/messages
)。
- SSE端点:客户端通过此建立长连接,接收事件流(如
- 消息推送流程:客户端首次连接时,服务端返回SSE端点的URI;后续所有请求通过POST发送,响应通过SSE事件流返回。
# 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 请求,这通常是短连接。