到第 18 篇为止,我们给 Agent 造的每一件工具都是"私有的":@tool 装饰器定义在项目里,bind_tools 绑定进图里,换个应用就得重写一遍。可工具明明是通用的——查数据库、读文件、调 GitHub API,谁的 Agent 都需要,却被锁死在一个个进程里。**Model Context Protocol(MCP,模型上下文协议)**就是解开这把锁的标准:Anthropic 于 2024 年 11 月将其开源,发布半年内 OpenAI、Google、微软先后采纳,如今它已是 AI 工具生态的事实标准。
本篇是第四模块"MCP 与工具生态"的开篇,专注协议本身:三个角色怎么分工,Tools/Resources/Prompts 三类原语有何区别,stdio 与 Streamable HTTP 两种传输怎么选,一次工具调用在线上长什么样,最后厘清 MCP 与 Function Calling 的关系。全文按"动机 → 架构 → 原语 → 传输 → 消息流 → 对比 → 生态"组织;协议吃透了,下一篇我们再亲手写 Server。
1、为什么需要 MCP
没有标准协议时,工具集成的复杂度是乘法:N 个应用接入 M 个工具,每个组合都要写一遍胶水代码——认证方式、参数格式、错误处理各不相同,总共 N×M 份维护负担。MCP 把乘法变成加法:工具作者按协议实现一次 Server,应用作者实现一次 Client,任意组合即插即用。官方给它的类比是"AI 应用的 USB-C":接口标准化之后,外设生态才会爆发。
行业采纳的速度是这场协议竞争最干脆的注脚。2024 年 11 月 Anthropic 开源 MCP,首发规范版本为 2024-11-05;2025 年 3 月 OpenAI 宣布采纳,Agents SDK 与 ChatGPT 桌面版率先接入;4 月 Google DeepMind 宣布 Gemini 支持;5 月微软在 Build 大会上宣布 Copilot 生态全面接入。发布半年,三大对手全部入局,此后 MCP 不再是某一家的私有协议,而是全行业的公共接口。生态数据同样直观:据第三方统计,npm 上官方 SDK 的下载量从发布月的约 10 万次涨到 2025 年 4 月的 800 万次以上。
对我们写 Agent 的人而言,这件事的直接含义是:工具层从"每个项目自己写"变成"像装 npm 包一样接标准件"。协议细节见 MCP 官方文档,缘起可读 Anthropic 的发布公告。
2、协议架构三角色
MCP 架构里有三个角色,名词容易搞混,先钉死:
| 角色 | 是什么 | 例子 |
|---|---|---|
| Host | 宿主应用,用户真正打开的那个 AI 程序 | Claude Desktop、IDE、你的 Agent |
| Client | Host 内嵌的连接器,一个 Client 连一个 Server | Host 里的天气连接器 |
| Server | 独立进程或远程服务,对外提供能力 | 文件 Server、GitHub Server |
注意 Client 不是"终端用户"——它是 Host 里的一个协议实现,负责与单个 Server 建立连接、协商能力、收发消息。一个 Host 内嵌多个 Client,每个 Client 与一个 Server 一一相连,Host 把所有 Client 发现的工具合并成一份列表交给模型。一张图看全:
Host(宿主应用:Claude Desktop / IDE / 你的 Agent 程序)
├── 模型调用、任务编排、UI
├── Client A ─── stdio(本地子进程)───▶ Server 甲:文件 / Git / 本地库
└── Client B ─── Streamable HTTP ─────▶ Server 乙:云端天气 / SaaS API
│
└── 两路发现的工具合并为一份列表,交给模型选用
为什么一个 Client 只连一个 Server,而不是让一个大 Client 连所有 Server?答案是隔离:每个 Server 是一条独立的信任边界,权限审批(文件 Server 只读哪个目录)、崩溃恢复(子进程挂了只影响这一路)、能力协商都按连接各自进行。你在 Claude Desktop 的连接配置里逐个添加 Server,加的就是一条条这样的链路。
3、三类服务原语
Server 能对外提供三类东西,规范称为三类原语(primitive),核心差异在于控制权在谁手里:
| 原语 | 谁发起 | 给谁看 | 典型场景 |
|---|---|---|---|
| Tools | 模型自主决定 | 结果回给模型继续推理 | 查天气、执行 SQL、发消息 |
| Resources | 应用代码控制 | 内容作为上下文提供给模型 | 文件内容、表结构、日志片段 |
| Prompts | 用户显式触发 | 展开成一段对话 | 斜杠命令式的评审、翻译模板 |
Tools 是我们最熟悉的东西:带 name、description、inputSchema 的函数描述,模型看到描述后自行决定何时调用——与第 5 篇 @tool 的产物结构一致,只是搬到了进程之外。Resources 是被动的数据:以 URI 标识(如 file:///logs/app.log),由应用代码决定何时用 resources/read 读取,模型无权主动拉取,适合"把这份文档放进上下文"这类确定性动作。Prompts 则面向用户:预置一段带参数的提示词模板,用户敲 /review pr-123 触发,Host 把模板展开成对话交给模型。
三者对应的方法族分别是 tools/*、resources/*、prompts/*(如 tools/list、resources/list、prompts/get)。日常说"接一个 MCP Server",九成场景指的就是 Tools。
4、传输层两种形态
消息怎么从 Client 送到 Server?2026 年 10 月的规范里只有两种标准传输:
| 维度 | stdio | Streamable HTTP |
|---|---|---|
| 形态 | Host 拉起本地子进程 | 远程 HTTP 服务 |
| 通道 | stdin/stdout 按行分隔的 JSON-RPC | 单一 /mcp 端点,每条消息一次 POST |
| 适用 | 本地工具:文件、Git、本地库 | 云端服务:SaaS API、多租户 |
| 认证 | 继承本机用户权限 | OAuth 2.1 + TLS |
stdio 适合"工具就装在本机"的场景:Client 把 Server 当子进程启动,JSON-RPC 消息一行一条写进 stdin、从 stdout 读回,日志走 stderr。零网络开销、零部署成本,本地文件 Server、Git Server 都走这条路。Streamable HTTP 面向远程:Client 向单一端点 POST 每条消息,服务端回复一个 JSON 对象,或者为该次请求开一条 SSE 流逐步吐出结果。完整定义见规范传输章节。
这里有一段值得知道的演进史:最早的 2024-11-05 规范里,远程传输叫 HTTP+SSE,需要两个端点——POST 一个发消息、GET 一个挂长连接收推送,实现繁琐且对网关不友好。2025 年 3 月的 2025-03-26 修订用 Streamable HTTP 取而代之(单端点、按需开流),旧传输随即进入废弃流程。今天新建远程 Server,只有 Streamable HTTP 一个选项;看到老教程里的双端点 SSE 配置,可以直接判断它过时了。
5、消息流解剖
MCP 的线协议是 JSON-RPC 2.0:请求带 jsonrpc、id、method、params 四个字段,响应用同一个 id 回 result 或 error;方法名就是 tools/list、tools/call 这样的点分字符串。下面按"握手 → 发现 → 执行"三段走一遍完整时序——这也是当前绝大多数已部署 Server 仍在使用的语言,读懂它再看新修订的改动就有的放矢。
5.1、完整调用时序
第一段,连接建立后的 initialize 握手,双方交换版本与能力:
{"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": {"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {"name": "my-agent", "version": "0.1.0"}}}
{"jsonrpc": "2.0", "id": 1, "result": {
"protocolVersion": "2025-06-18",
"capabilities": {"tools": {"listChanged": true}},
"serverInfo": {"name": "weather", "version": "1.2.0"}}}
{"jsonrpc": "2.0", "method": "notifications/initialized"}
解读三个要点:客户端在 params 里报上协议版本与自身能力,服务端在 result 里回敲定版本与自己的能力(此处声明支持 tools 且列表变更时会通知);版本不一致时以服务端回复为准;最后的 notifications/initialized 是一条没有 id 的通知,表示握手完成、进入正常工作。能力协商的本质是双方各自声明可选特性,只使用交集——客户端不支持采样,服务端就永远别向它发采样请求。
第二段,工具发现:
{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}
{"jsonrpc": "2.0", "id": 2, "result": {"tools": [{
"name": "get_weather",
"description": "查询指定城市的当前天气",
"inputSchema": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]}}]}}
tools/list 的返回就是一张工具描述表,inputSchema 是标准 JSON Schema——Host 拿到后原样喂给模型的 Function Calling 机制,第 5 篇里 bind_tools 干的就是这件事。第三段,模型决定调用后,Host 转发执行请求:
{"jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": {"name": "get_weather", "arguments": {"city": "Beijing"}}}
{"jsonrpc": "2.0", "id": 3, "result": {
"content": [{"type": "text", "text": "Beijing 晴,12 摄氏度"}],
"isError": false}}
结果放在 content 数组里,可以是文本、图片或内嵌资源;isError: true 表示工具执行层面的业务失败,区别于协议层错误(走响应的 error 字段)。Host 把文本内容包成 ToolMessage 塞回对话,一轮 MCP 调用闭环。
5.2、无状态化修订
上面这套"先握手、后干活"的模型,在 2026 年 7 月 28 日被大改:2026-07-28 修订把协议核心改成了无状态。initialize 握手与 Mcp-Session-Id 会话头整体移除,协议版本、客户端身份、能力这些过去握手时交换一次的信息,改为随每条请求的 _meta 字段携带;Server 能力改用新的 server/discover 方法按需拉取。Streamable HTTP 还新增了路由头,网关不解析请求体就能完成分发:
POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: weather
{"jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": {"name": "get_weather", "arguments": {"city": "Beijing"}},
"_meta": {"io.modelcontextprotocol/clientInfo": {"name": "my-agent"}}}
解读:Mcp-Method 与 Mcp-Name 告诉中间层"调什么方法、找哪个 Server",负载均衡与限流不再需要解开 JSON;请求体仍是事实来源,头部只是镜像,两边不一致会被拒绝(报文有省略)。改动动机很工程化:有会话就要粘性路由、要共享会话存储,Server 无法水平扩展;无状态之后任意实例可处理任意请求,MCP Server 退化成一台普通 HTTP 服务。配套地,Roots、Sampling、Logging 三项特性被标记废弃(仅标注,至少一年内继续可用),Server 中途向用户要输入的场景改由"多轮请求"机制承接。
注意:新旧两代协议并存会是 2026 年的常态。SDK 会自动探测对端版本并回落到握手模式,但你自己抓包排查问题时,先确认这条链路说的是哪一代语言。
6、MCP 与函数调用
"MCP 是不是替代了 Function Calling"是最高频的误解。两者不在同一层:Function Calling 是模型能力——模型读得懂工具 schema,会输出结构化的调用意图;MCP 是分发协议——规定工具从哪来、如何被发现、调用与结果如何在线上传输。分层看:
应用层 你的 Agent(LangGraph 编排、状态管理)
│ 需要工具
分发层 MCP:发现工具(tools/list)、调用与回传(tools/call)
│ schema 注入 prompt
机制层 Function Calling:模型理解 schema,输出调用意图
│
模型层 GPT / Claude / Gemini
串起来读:MCP Server 的工具描述经 tools/list 到达 Host,Host 用 Function Calling 机制把 schema 交给模型,模型输出的调用意图再由 Host 翻译成 tools/call 发回 Server。所以答案是互补而非竞争:没有 Function Calling,MCP 的工具没有模型能消费;没有 MCP,每个应用的工具都要手写一遍。第 5 篇我们用 @tool 手工定义再 bind_tools,走的是最短路径;MCP 做的事,是把"定义工具"这一步标准化、外置化、可复用化。
7、生态现状
协议的价值最终兑现为生态规模。官方 MCP Registry 于 2025 年底上线,2026 年年中的注册量已接近一万;聚合第三方目录的统计则给出两万以上的量级——即便打个对折,也足以支撑"常见需求大概率有现成 Server"的判断。品类高度集中在几类:
- 文件与代码:文件系统、Git、GitHub,官方 servers 仓库有参考实现
- 数据库:Postgres、MySQL、SQLite,把查询包装成工具
- 浏览器:Playwright、Puppeteer,让 Agent 驱动真实浏览器
- SaaS:Slack、Notion、Linear 等,OAuth 认证加 Streamable HTTP 接入
SDK 一侧,官方维护 TypeScript、Python、Go、C# 等实现,均在 2026-07-28 修订发布同期更新。Python SDK 的 v2 已于 2026 年 8 月 GA(当前 2.1.x),新协议与旧修订回落都支持;它内置的 FastMCP 高层封装,正是我们下一篇的主角。
8、总结
回收全文:MCP 用一个开放协议,把工具集成从 N×M 的乘法变成 N+M 的加法;架构上 Host 内嵌多个 Client、每个 Client 一对一连一个 Server;Server 提供 Tools(模型控制)、Resources(应用控制)、Prompts(用户控制)三类原语;传输分 stdio(本地子进程)与 Streamable HTTP(远程单端点),旧 HTTP+SSE 已废弃;线上是 JSON-RPC 2.0,2026-07-28 修订后核心无状态化,握手退场、能力随请求携带。MCP 与 Function Calling 一个管分发、一个管调用,是上下两层的互补关系。
练习:打开 Claude Desktop 的连接设置,添加官方 filesystem Server 并配一个只读目录;在调试模式里观察 initialize 与 tools/list 的真实报文,再问模型一个需要读文件的问题,对照本文第 5 节的时序逐条印证。
对于正在写 Agent 的同学,建议把 MCP 当作工具层的默认采购渠道:动手造轮子之前,先到 Registry 查一查有没有现成 Server,多数通用需求早已被覆盖。下一篇第 20 篇:用官方 Python SDK v2 的 FastMCP 亲手写一个 Server,@mcp.tool 一行装饰器起步,同时发布 stdio 与 Streamable HTTP 两种形态。


