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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

MCP Server (Model Context Protocol Server),即模型上下文协议服务器, 是一种基于标准化协议的服务端程序。 它的核心作用是为大语言模型 (LLM) 提供外部数据和功能支持。 可以将其理解为一个标准化的 工具接口 。 例如Fetch MCP Server 能够抓取网页内容,而 Google Drive MCP Server 则可以实现云端文件的读取。 MCP Server 的关键特点在于其 被动性 。 它如同一个工具箱,静静地等待指令,只在接收到明确的调用请求后才会执行相应的操作,并不主动参与决策或推理过程。 !Pasted image 20250323110401.png

一、通信机制

特性 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 SSEServer-Sent Events

客户端与服务端可部署在不同节点通过HTTP协议实现跨网络通信。 是个异步事件驱动。

  • 服务端通过SSE长连接主动推送数据
  • 客户端通过HTTP POST端点发送请求 支持实时或准实时交互,适合分布式系统或需要高并发的场景

二、技术实现

2.1 STDIO

!Pasted image 20250323110642.png

  • 消息必须为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

!Pasted image 20250323113326.png

  • 服务端需提供两个端点:
    • SSE端点客户端通过此建立长连接接收事件流/sse)。
    • HTTP POST端点客户端发送请求至此/messages)。
  • 消息推送流程客户端首次连接时服务端返回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 请求,这通常是短连接。