MCP 系列 1:MCP 协议、架构与通信机制


LangGraph 系列 5 和 6 已经介绍了本地 Tool、Function Calling 与工具调用循环。Python 函数、Runnable 和 BaseTool 都可以交给 Agent 使用,但这些工具通常和应用代码放在同一个项目中。另一个应用想复用工具时,需要重新复制代码、安装依赖并处理参数格式。

从本文开始进入独立的 MCP 系列,讨论如何把工具、资源和提示词变成可以被不同语言、进程和 Agent 客户端复用的标准能力。

MCP 解决的是能力标准化和跨应用复用问题。服务端按照统一协议公开工具、资源和提示词,支持 MCP 的客户端就能发现并调用这些能力,而不需要理解服务端使用 Python、Java 还是其他语言实现。

1. MCP 是什么

MCP 的全称是 Model Context Protocol,即模型上下文协议。它定义了 AI 应用与外部能力之间的通信方式。

MCP 不是模型,也不是 Agent 框架。它不负责决定什么时候调用工具,也不负责生成最终回答。它负责描述和传输能力,让客户端能够完成下面这些操作:

  • 发现服务端提供了哪些 Tool。
  • 读取服务端公开的 Resource。
  • 获取服务端维护的 Prompt。
  • 按统一 Schema 传入参数并得到结果。
  • 在初始化阶段协商双方支持的能力。

协议只规定通信规则,不限制实现语言。因此,Python Agent 可以调用 Java MCP Server,桌面应用也可以调用同一个网络 MCP Server。

2. MCP 与本地 Tool、Function Calling、HTTP API 的区别

这几个概念经常同时出现,但职责不同。

本地 Tool 是应用进程中的可调用函数。Function Calling 是模型生成结构化工具请求的能力。普通 HTTP API 是服务之间约定的网络接口。MCP 则在 JSON-RPC 基础上统一了能力发现、调用、通知、生命周期和传输方式。

一次完整调用可能同时使用它们:

用户问题
→ 模型通过 Function Calling 选择工具
→ Agent 调用 MCP Client
→ MCP Client 调用远端 MCP Tool
→ Tool 结果返回 Agent
→ 模型生成最终回答

所以 MCP 不取代 Function Calling。模型仍然需要产生工具调用请求,只是工具可能来自独立 MCP Server。

3. Host、Client 和 Server

MCP 使用 Host、Client、Server 三层架构。

下图中的蓝色虚线框表示同一个 Host 进程。Host 在内部创建多个 Client 实例,每个 Client 只维护与一个 Server 的独立会话。

Host 进程、多个 MCP Client 与独立 Server 的架构

Client 与 Server 之间传输的是双向 JSON-RPC 消息,不是单向函数调用。Host 负责跨 Server 编排,Server 之间没有直接通信通道。

3.1 Host

Host 是用户直接使用的 AI 应用,例如 IDE、桌面助手或 Agent 应用。它负责:

  • 创建和管理 MCP Client。
  • 控制哪些 Server 可以连接。
  • 管理授权、用户同意和安全策略。
  • 把 MCP 返回的能力交给模型或 Agent。
  • 决定哪些上下文可以发送给服务端。

3.2 Client

Client 由 Host 创建,负责与某一个 Server 建立连接、协商能力和收发协议消息。

一个 Client 在一个会话中对应一个 Server。Host 如果连接三个 Server,通常会维护三个彼此隔离的 Client 连接。这样,一个 Server 不能直接查看另一个 Server 的通信内容。

3.3 Server

Server 提供具体能力。它可以是客户端临时启动的本地子进程,也可以是独立运行的网络服务。

Server 只应该获得完成当前调用所需的信息。它不会因为接入 MCP 就自动看见完整聊天记录,也不能直接访问其他 MCP Server。跨服务编排仍由 Host 或 Agent 负责。

4. MCP 基于 JSON-RPC

MCP 使用 JSON-RPC 2.0 编码消息。常见消息分为请求、响应、通知和错误。

一个请求包含方法、参数和请求 ID:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {}
}

响应使用相同 ID 与请求配对:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": []
  }
}

通知没有 id,发送方不等待对应响应。错误响应则包含错误代码和说明。

业务代码通常不需要手写这些 JSON。MCP SDK 会完成编码、请求 ID 管理和结果转换,但理解底层结构有助于排查初始化失败、方法不存在和参数不匹配。

5. MCP 连接的生命周期

一次 MCP 会话不是连接成功后立即调用 Tool,而是经过明确的初始化过程。

MCP 初始化、运行与关闭生命周期

主要阶段如下:

  1. Client 发送 initialize,声明协议版本和自身能力。
  2. Server 返回支持的协议版本、Server 信息和能力。
  3. Client 发送 notifications/initialized 初始化完成通知。
  4. 双方进入正常通信,可以列出或调用能力。
  5. 使用底层传输关闭连接;有状态 HTTP Session 还可以通过 DELETE 请求显式终止。

能力协商很重要。Server 只有声明支持 Tools,Client 才能按照协议使用工具相关方法;Resources、Prompts、Sampling 等能力也遵循相同原则。

MCP 没有定义专用的关闭协议消息。stdio 通过关闭输入流并结束 Server 子进程完成关闭,HTTP 则关闭相关连接。每个请求还应该设置超时;超时后停止等待,并在适用时发送取消通知,避免连接长期占用资源。

6. Server 提供的三种核心能力

6.1 Tools

Tool 表示可以执行的操作,例如计算、查询数据库或读取业务系统。Tool 包含名称、说明和参数 Schema,通常由模型或 Agent 决定是否调用。

Tool 可能产生副作用。删除文件、发送消息或修改数据库之前,Host 应该进行权限控制或用户确认。

6.2 Resources

Resource 表示可以读取的数据,例如配置说明、文件内容或固定知识。它通过 URI 标识,例如:

guide://mcp

Resource 更接近“读取什么”,Tool 更接近“执行什么”。具体由客户端决定怎样把 Resource 放入模型上下文。

6.3 Prompts

Prompt 是服务端公开的可复用提示词模板。客户端可以列出 Prompt,并传入参数获得消息内容。

Prompt 不会自动执行模型,也不是系统提示词的唯一来源。它只是 MCP Server 提供的一种可发现能力。

7. Client 侧能力

协议还定义了 Roots、Sampling 和 Elicitation 等 Client 能力。

  • Roots:客户端向 Server 声明允许访问的文件系统根目录。
  • Sampling:Server 请求 Host 使用模型生成内容,最终控制权仍在 Host。
  • Elicitation:Server 请求用户补充信息或确认操作。

本文只明确这些能力的位置,不编写实现。它们也不是每个 MCP Client 和 Server 都必须支持的功能,是否可用取决于初始化阶段的能力协商。

8. stdio 传输

stdio 使用标准输入和标准输出传输 JSON-RPC 消息。

它的真实进程关系是:Client 启动一个独立 MCP Server 子进程,然后通过子进程的 stdin 和 stdout 通信。两者不是同一个进程。

Host 进程
└── MCP Client
    └── 启动 MCP Server 子进程
        ├── stdin  接收 JSON-RPC
        ├── stdout 返回 JSON-RPC
        └── stderr 输出日志

stdio 适合本机桌面应用、命令行工具和单用户场景。Client 负责 Server 子进程的启动和关闭,不需要提前监听端口。

使用 stdio 时有一条非常重要的规则:Server 不能向 stdout 输出普通日志,因为任何非 MCP 消息都会破坏协议流。日志应该写到 stderr。

每条 JSON-RPC 消息使用换行符分隔,消息本身不能包含未转义的换行。Client 写入 Server stdin 的内容也必须是有效 MCP 消息。

9. Streamable HTTP 传输

Streamable HTTP 适合独立运行和网络访问。Server 必须提供单一 MCP 端点,例如:

http://127.0.0.1:18100/mcp

Client 发送的每一条 JSON-RPC 消息都使用一次新的 HTTP POST 请求。POST 请求需要同时声明能够接收 application/json 和 text/event-stream;Server 可以直接返回一个 JSON 对象,也可以通过 SSE 返回多个消息。

Client 还可以尝试使用 GET 建立服务端到客户端的 SSE 流。如果 Server 不提供这种独立 SSE 流,应返回 405 Method Not Allowed,不能把 GET 描述成所有实现都必须提供的流式能力。

这意味着 Streamable HTTP 可以使用 SSE,但它不等于旧 HTTP+SSE 传输,也不是 WebSocket。

如果 Server 创建了有状态会话,可以在初始化响应中返回 MCP-Session-Id。后续请求需要携带该 Header。HTTP 请求还应携带协商后的 MCP-Protocol-Version。

下图只比较协议定义的两种标准传输。它们承载相同的 JSON-RPC 和生命周期,差别在于进程关系、消息边界、连接方式和会话管理。

stdio 与 Streamable HTTP 标准传输对比

10. 旧 HTTP+SSE 为什么仍然存在

旧 HTTP+SSE 是 MCP 2024-11-05 版本中的传输方式。它通常使用一个 SSE 端点接收服务端消息,再通过另一个 POST 端点发送客户端消息。

Streamable HTTP 已经取代它,网络新项目应该优先使用单一 /mcp 端点。旧 SSE 仍有意义,因为已有客户端和服务端需要兼容。后面的 FastMCP 实战会真实运行一次旧 SSE,但不会把它作为主路径。

11. 本地 MCP Server 也需要安全边界

本机服务并不等于天然安全。Streamable HTTP 规范明确要求关注以下问题:

  • 本地服务优先绑定 127.0.0.1,不要无意暴露到全部网卡。
  • 校验 Origin,降低 DNS Rebinding 风险。
  • 网络服务应该增加认证和授权。
  • Host 只向 Server 提供最少必要上下文。
  • 调用有副作用的 Tool 前进行确认和审计。
  • 不把第三方 MCP 返回的文本直接当作可信指令执行。

本系列的本地服务只用于学习测试。公网部署、OAuth 和细粒度权限会单独处理。

12. 常见误区

12.1 MCP Server 就是 Agent

不是。Server 提供能力,Agent 负责选择能力、组织调用并生成回答。

12.2 使用 MCP 后不需要模型 Function Calling

不是。Agent 把 MCP Tool 转换成模型可理解的工具 Schema,模型仍需要生成工具调用请求。

12.3 SSE 就是 WebSocket

不是。SSE 是基于 HTTP 的单向事件流。Streamable HTTP 可以结合 POST、GET 和 SSE 完成双向协议通信,但底层不是 WebSocket。

12.4 stdio Server 和 Client 在同一个进程

不是。Client 启动独立 Server 子进程,再通过标准流通信。

12.5 MCP Server 可以读取全部对话

不是。Host 决定向某个 Server 发送什么内容,Server 不应该自动获得完整对话或其他 Server 的上下文。

13. 总结

MCP 的价值不只是“远程调用一个函数”,而是为 AI 应用定义统一的能力发现、参数描述、生命周期和传输规则。

概念 主要职责 需要注意的边界
Host 管理 Client、模型、权限和用户交互 决定向 Server 发送哪些上下文
Client 维护与单个 Server 的会话 一个 Client 连接一个 Server
Server 提供 Tool、Resource、Prompt 不自动获得全部对话
Tool 执行操作 可能有副作用,需要权限控制
Resource 公开可读取数据 是否放入模型上下文由客户端决定
Prompt 提供可复用提示词 不会自动调用模型
stdio 本地子进程通信 stdout 只能输出 MCP 消息
Streamable HTTP 网络 MCP 主路径 需要 Origin、认证和会话安全
旧 HTTP+SSE 兼容旧客户端和服务端 不作为新项目首选

文章作者: hnbian
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hnbian !
评论
  目录