MCP 深度实战:当大模型终于学会「调用万物」——从 2026-07-28 史诗级修订、JSON-RPC 协议栈到 FastMCP / TypeScript 双栈工程与 OAuth 安全防护的完整指南
2026 年 7 月,全球 AI 智能体最核心的互联协议 MCP(Model Context Protocol,模型上下文协议)迎来了自 2024 年 11 月诞生以来规模最大的一次系统性修订——"2026-07-28 版本候选规范"已正式进入发布倒计时。它将 MCP 从"让 AI 会调工具"的连接协议,升级为可规模化部署、全链路可治理、调用全程可追溯的生产级智能体基础设施。
本文不是一篇"MCP 是什么"的科普,而是一份工程级深度指南:从 M×N 集成痛苦讲到协议栈每一层的字节,从 FastMCP 十行写出一个 Server 讲到 TypeScript 双栈、从 stdio 本地穿透讲到 Streamable HTTP + OAuth 2.0 的远程安全部署,最后落到 2026 史诗修订的能力发现、链路追踪与任务协作。配可直接运行的代码,建议收藏后照着敲。
目录
- 背景:那个折磨了整个行业两年的 M×N 问题
- 核心概念:Host、Client、Server 的三角关系与四大原语
- 架构分析:JSON-RPC 2.0 协议栈、生命周期与三大传输层
- 代码实战一:用 FastMCP 十行写出一个生产级 Server
- 代码实战二:TypeScript SDK 双栈与低层协议透视
- 代码实战三:Streamable HTTP 远程 Server 与 OAuth 2.0 鉴权
- 性能优化:延迟、连接与并发的工程真相
- 安全:工具投毒、越权与 OAuth 防护体系
- 总结与展望:MCP vs Function Calling vs A2A,以及 2026 史诗修订
一、背景:那个折磨了整个行业两年的 M×N 问题
如果你在 2023—2024 年做过任何"让大模型干活"的尝试,一定被同一个问题折磨过:每接一个工具,就要为每一个应用重写一遍胶水代码。
一个典型的 AI 编程助手,要连 GitHub、连文件系统、连数据库、连搜索、连内部 API。而每一个宿主应用(Claude Desktop、VS Code 插件、自研 Agent)如果要支持这些能力,都得各自实现一遍。这就形成了经典的 M × N 集成爆炸:
M 个应用 × N 个工具 = M×N 套重复集成代码
更糟的是,那个时代的"工具调用"主流方案是各家的 Function Calling(函数调用)。它的本质只是"模型输出一段约定好的 JSON",没有传输层、没有标准协议、强绑定模型厂商。OpenAI 的格式、Anthropic 的格式、Google 的格式各不相同,同一套工具要为不同模型各写一套适配。
2024 年 11 月底,Anthropic 开源了 MCP,提出一个朴素的野心:能不能像 USB-C 一样,给 AI 应用一个统一的"插口"? 任何工具只要实现一次 MCP Server,所有兼容 MCP 的宿主都能即插即用。
改造前(M×N):
App A ──手写──> Tool 1
App A ──手写──> Tool 2
App B ──手写──> Tool 1 ... 每对都要写一遍
改造后(M+N):
App A ──┐
App B ──┼──> MCP 协议 ──> MCP Server(Tool 1, Tool 2, ...)
App C ──┘
每个工具只实现一次 Server,所有宿主共用
到 2026 年,MCP 已经成为事实上的"AI 工具调用标准"。2026 年 5 月发布的 2026-07-28 候选规范更是一次质变:它不再满足于"连接",而是要把 MCP 变成可治理、可追溯、可协作的智能体基础设施。后面我们会专门拆解这次修订。
工程判断:如果你今天要做一个需要"调用外部能力"的 AI 应用,MCP 已经不是"要不要学"的问题,而是"你的竞品已经用上了"的问题。
二、核心概念:Host、Client、Server 的三角关系与四大原语
MCP 的架构里有三个角色,第一次上手最容易混淆的是 Host 和 Client 的区别。
2.1 三个角色
| 角色 | 是什么 | 例子 |
|---|---|---|
| Host(宿主) | 运行 LLM 的"大应用",用户直接交互的入口,负责把模型生成的 tool_call 真正派发执行 | Claude Desktop、VS Code + Copilot、你自研的 Agent 主程序 |
| Client(客户端) | 运行在 Host 进程内部的连接器,一个 Client 对应一个 Server 连接(1:1)。它把 Host 的意图翻译成 MCP 协议,再翻译回 Host | Host 里每个 MCP 连接背后都藏着一个 Client 实例 |
| Server(服务端) | 真正提供能力的进程,暴露 Tools / Resources / Prompts | 一个连 GitHub 的 Server、一个读本地文件的 Server |
关键理解:Host 里可以有多个 Client,每个 Client 只连一个 Server。你配置了 3 个 MCP Server,Host 内部就起了 3 个 Client,各连各的。
┌─────────────────────────── Host (你的 AI 应用) ───────────────────────────┐
│ │
│ LLM ──生成 tool_call──> 路由层 │
│ ├─ Client A ──stdio/http──> Server A (文件系统) │
│ ├─ Client B ──stdio/http──> Server B (GitHub) │
│ └─ Client C ──stdio/http──> Server C (数据库) │
└─────────────────────────────────────────────────────────────────────────┘
2.2 四大原语(Primitives)
MCP 不是只有"工具调用"。它定义了四类能力,这才是它比裸 Function Calling 强大的地方:
① Tools(工具) —— 模型可以主动调用来执行动作、产生副作用。
- 典型:查天气、调 API、写文件、跑 SQL。
- 特点:由模型决策是否调用(LLM 自己决定),有输入 schema、有输出。
- 本质 ≈ Function Calling 的"函数"。
② Resources(资源) —— 可以被读取的上下文数据,不由模型决策,通常由应用/用户决定要不要喂给模型。
- 典型:一个文件内容、一条数据库记录、一份文档。
- 特点:类似 REST 的
GET,只读、无副作用,用 URI 寻址(file:///logs/app.log、db://users/42)。 - 关键差异:Resources 不进"模型自主决策"的快车道,而是作为上下文附加上去,避免模型被海量资源淹没而乱调。
③ Prompts(提示词模板) —— 服务端预定义的、可复用的提示词工作流,由用户显式触发。
- 典型:"代码审查模板""SQL 生成模板"。
- 特点:人类点一下就插入一段结构化 prompt,模型不自主触发。
④ Sampling(采样 / 反向调用) —— 这是很多人忽略的"反向通道":Server 可以反过来请求 Host 里的 LLM 干活。
- 场景:一个文档处理 Server 想让模型先总结一段文本,再决定下一步。它不能自己跑 LLM,于是通过 Sampling 请求 Host:"hey Host,帮我让你们的模型总结这段"。
- 这是 MCP "Server 也能用 AI" 的关键设计,也是安全风险点(后面安全章节会讲)。
此外还有 Roots(告诉 Server "你可以访问哪些根目录/作用域",做权限边界)和 Elicitation(运行时向用户追问缺失参数,类似交互式表单)。这俩在 2026 修订里被进一步强化。
2.3 生命周期:一次连接的完整剧本
任何 MCP 连接都遵循严格的状态机,理解它对你排错至关重要:
1) 建立传输(stdio 启动子进程 / HTTP 建连)
2) initialize ──> Client 发协议版本 + 各自 capabilities
3) <── initialized Server 确认,双方能力对齐
4) 正常通信:tools/list、tools/call、resources/read、prompts/get ...
5) shutdown ──> 优雅关闭
6) exit
版本协商是这里最容易踩的坑:Client 会声明自己支持的最高协议版本,Server 回自己支持的最高且 ≤ 客户端的版本。当前正式稳定线有 2024-11-05、2025-03-26、2025-06-18,而即将发布的候选版是 2026-07-28。低版本 Client 连高版本 Server 时,Server 会"向下兼容"到 Client 的版本——这正是向后兼容的精髓。
三、架构分析:JSON-RPC 2.0 协议栈、生命周期与三大传输层
MCP 的"协议栈"其实非常薄且优雅,这也是它能被各语言快速实现的原因。
3.1 协议层:就是 JSON-RPC 2.0
MCP 的所有消息都是 JSON-RPC 2.0。request 带 id,response 回相同的 id,notification 无 id(单向通知,如日志、进度)。
一次最朴素的 initialize 长这样(这是你用任何 SDK 时底层真正发出的东西):
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2026-07-28",
"capabilities": {
"tools": { "listChanged": true },
"resources": { "subscribe": true, "listChanged": true }
},
"clientInfo": { "name": "demo-client", "version": "1.0.0" }
}
}
Server 回:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": { "tools": { "listChanged": true } },
"serverInfo": { "name": "demo-server", "version": "2.3.1" }
}
}
注意:Server 回的 protocolVersion 是 2025-06-18 而非客户端请求的 2026-07-28——因为它只支持到 2025-06-18,于是双方就在这个协商后的版本上通信。这就是"能力对齐"的落地。
3.2 传输层:三种方式怎么选
| 传输 | 适用 | 形态 | 现状 |
|---|---|---|---|
| stdio | 本地、同机 | Client 启动 Server 子进程,通过 stdin/stdout 收发 JSON-RPC | 最常用、最安全(无网络暴露) |
| SSE(旧) | 远程(历史方案) | 一条 SSE 长连接 Server→Client 推事件 + 一条独立 HTTP POST 发请求 | 已废弃,被 Streamable HTTP 取代 |
| Streamable HTTP | 远程(现代) | 双向都走 HTTP,请求/响应可流式,按需建连,无需常驻 SSE | 2025-03-26 起官方推荐,2026 远程部署首选 |
为什么 Streamable HTTP 取代了 SSE? SSE 方案的硬伤是:它要求 Server 维持一条长连接来向 Client 推事件,这对无状态的云托管(如 Serverless、容器自动伸缩)极不友好——连接一断状态就没了。Streamable HTTP 改为:Client 用普通 POST 发请求并带上 Accept: application/json, text/event-stream,Server 可以选择用 SSE 流式回、也可以直接回 JSON;Server→Client 的主动通知则通过 Client 后续发起的 GET 流获得。这样 Server 可以完全无状态,轻松上云。
Streamable HTTP 一次调用的真实 HTTP 交互:
Client ──POST /mcp (Accept: application/json, text/event-stream)──> Server
body: {"jsonrpc":"2.0","id":1,"method":"tools/call",...}
Server ──HTTP 200 + Content-Type: text/event-stream──> Client
data: {"jsonrpc":"2.0","id":1,"result":{...}} (可多段 SSE)
Server 主动通知(如进度):
Client ──GET /mcp (Accept: text/event-stream)──> Server
Server 推: data: {"jsonrpc":"2.0","method":"notifications/progress",...}
四、代码实战一:用 FastMCP 十行写出一个生产级 Server
Python 阵营最强生产力来自官方的 FastMCP(包名 mcp,from mcp.server.fastmcp import FastMCP)。装饰器一行注册一个能力,零样板。
先装依赖:
pip install "mcp[cli]"
# 或
uv add "mcp[cli]"
4.1 一个会"加法 + 读文件 + 给模板"的最小 Server
# server.py
from mcp.server.fastmcp import FastMCP
# 创建 Server 实例(名字会出现在客户端列表里)
mcp = FastMCP("DemoServer")
# ① Tool:模型主动调用,执行动作
@mcp.tool()
def add(a: int, b: int) -> int:
"""计算两个整数的和。"""
return a + b
# ② Resource:按 URI 读取的上下文,无副作用
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""按名字返回一句问候(演示动态 URI 资源)。"""
return f"你好,{name}!欢迎使用 MCP。"
# ③ Prompt:用户显式触发的提示词模板
@mcp.prompt()
def review_code(code: str) -> str:
"""生成一段代码审查提示词。"""
return f"请审查下面这段代码的健壮性、安全性与可维护性:\n\n{code}"
if __name__ == "__main__":
# 默认 stdio 传输;改 transport="streamable-http" 即可变远程
mcp.run()
就这 20 行,add 是工具、greeting://xxx 是资源、review_code 是提示词模板。类型注解就是 schema——FastMCP 自动把 a: int, b: int 变成 JSON Schema 的 type: integer,模型调用时参数校验全自动。
运行与本地调试:
# 直接用官方 CLI 起一个可交互的 Inspector(浏览器可视化调试神器)
mcp dev server.py
# 或者作为普通 stdio Server 启动(给宿主配置用)
python server.py
4.2 真实一点的 Server:带副作用与异常的"数据库查询"
生产环境你不会只写加法。下面这个例子演示:参数校验、结构化返回、错误处理三件大事。
# db_server.py
import sqlite3
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("SqliteServer")
DB_PATH = "app.db"
@mcp.tool()
def query(sql: str) -> str:
"""对本地 SQLite 执行只读 SELECT 查询,返回 CSV 格式结果。
Args:
sql: 一条 SELECT 语句(仅允许查询,禁止写操作)
"""
# ⚠️ 生产必备:白名单校验,防止模型被诱导执行 DROP/UPDATE
stripped = sql.strip().lower()
if not stripped.startswith("select"):
raise ValueError("出于安全考虑,本工具仅允许 SELECT 语句")
if any(k in stripped for k in (";", "drop", "delete", "update", "insert", "attach")):
raise ValueError("检测到非法关键字,已拒绝执行")
try:
conn = sqlite3.connect(DB_PATH)
cur = conn.cursor()
cur.execute(sql)
rows = cur.fetchall()
cols = [d[0] for d in cur.description] if cur.description else []
except sqlite3.Error as e:
return f"查询失败:{e}"
finally:
conn.close()
# 转 CSV,方便模型直接消费
header = ",".join(cols)
body = "\n".join(",".join(str(c) for c in r) for r in rows)
return f"{header}\n{body}"
要点:
- Tool 的 docstring 极其重要——它会被发给模型当"功能说明",写清楚参数含义和约束,模型才调得对。
- 永远做输入白名单:模型是概率性的,被 prompt injection 诱导去执行危险 SQL 是真实风险(见安全章节)。
- 返回字符串即可,FastMCP 会自动包成
content: [{type:"text", text: ...}]。
4.3 让宿主"看见"你的 Server
在 Claude Desktop / VS Code 等宿主里,只需在配置文件加一段(路径因客户端而异,这里以通用 mcp.json 风格为例):
{
"mcpServers": {
"sqlite": {
"command": "python",
"args": ["/绝对路径/db_server.py"]
}
}
}
保存重启宿主,它就会自动 initialize 你的 Server、tools/list 拿到 query,然后模型就能在对话里说"帮我查一下用户表前 10 行"并真正执行。
五、代码实战二:TypeScript SDK 双栈与低层协议透视
很多生产 Agent 用 Node 生态。官方 TypeScript SDK(@modelcontextprotocol/sdk)提供高层 McpServer 与低层 Client/Server 原语两套 API。
5.1 高层 McpServer:和 FastMCP 一样顺手
npm install @modelcontextprotocol/sdk zod
// ts-server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({ name: "TsDemo", version: "1.0.0" });
// 注册 Tool:inputSchema 用 zod 描述,自动变 JSON Schema
server.registerTool(
"add",
{
description: "计算两个整数的和",
inputSchema: { a: z.number(), b: z.number() },
},
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }],
})
);
// 注册 Resource
server.registerResource(
"greeting",
"greeting://{name}",
{ title: "问候资源", mimeType: "text/plain" },
async (uri, { name }) => ({
contents: [{ uri: uri.href, text: `你好,${name}!` }],
})
);
// 用 stdio 传输启动
const transport = new StdioServerTransport();
await server.connect(transport);
5.2 客户端:在宿主里连接并调用
// client.ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "node",
args: ["ts-server.ts"],
});
const client = new Client({ name: "demo-client", version: "1.0.0" });
await client.connect(transport);
// 列出工具
const tools = await client.listTools();
console.log(tools.tools.map((t) => t.name));
// 调用工具
const res = await client.callTool({ name: "add", arguments: { a: 2, b: 3 } });
console.log(res); // { content: [{ type: "text", text: "5" }] }
5.3 低层透视:自己手搓一个 JSON-RPC 握手
理解高层 API 背后发生了什么,排错时你会感谢自己。下面用原生 stdio 演示一次最小握手(仅示意核心字段):
// 伪代码:展示协议底层,无需真正运行
const initRequest = {
jsonrpc: "2.0",
id: 1,
method: "initialize",
params: {
protocolVersion: "2025-06-18",
capabilities: { tools: {} },
clientInfo: { name: "raw-client", version: "0.1.0" },
},
};
// 通过 stdio 的 stdout.write(JSON.stringify(initRequest) + "\n")
// 等待服务端回 { id:1, result: {...} }
// 再发:{ jsonrpc:"2.0", method:"notifications/initialized" }(无 id 的通知)
// 之后才能 tools/list / tools/call
记住这条铁律:没收到 initialized 通知之前,任何 tools/call 都会被 Server 拒绝。新手 90% 的"调用没反应"都栽在这里。
六、代码实战三:Streamable HTTP 远程 Server 与 OAuth 2.0 鉴权
当 Server 要部署到云端、被多个用户远程访问时,stdio 就不行了——你需要 Streamable HTTP 传输 + OAuth 2.0 鉴权。这正是 2026 年 MCP 走向"生产级"的核心拼图。
6.1 起一个 Streamable HTTP Server(Starlette + 官方 SDK)
# http_server.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("RemoteDemo")
@mcp.tool()
def echo(text: str) -> str:
"""原样返回输入,演示远程无状态调用。"""
return text
if __name__ == "__main__":
# Streamable HTTP 传输,默认挂载在 /mcp
mcp.run(transport="streamable-http")
部署后,客户端用 StreamableHTTPClientTransport 连接,URL 指向 https://你的域名/mcp 即可。关键点:Streamable HTTP 设计上是无状态的——每个请求自带 session 上下文,Server 不保活长连接,因此可以轻松跑在容器、Serverless 上,靠负载均衡横向扩展。
6.2 OAuth 2.0:远程 Server 的"门锁"
本地 stdio 为什么安全?因为 Server 是宿主自己启动的子进程,没有网络暴露面。但远程 Server 一旦挂公网,任何人都能调你的工具——所以 MCP 规范直接采用 OAuth 2.0(Authorization Code + PKCE)作为远程 Server 的标准鉴权方案。
流程与大家熟悉的"用 GitHub 登录第三方网站"完全一致:
1) Client 访问远程 MCP Server 的 /mcp
2) Server 回 401 + WWW-Authenticate,指明授权服务器地址
3) Client 跳转到授权服务器,用户登录并"同意授权此应用访问我的数据"
4) 授权服务器回一个授权码(code)
5) Client 用 code + PKCE 换取 Access Token(含 scope,限定能调哪些工具)
6) Client 携带 Bearer Token 调 /mcp,Server 校验 scope 后放行
# 客户端调用时
POST /mcp HTTP/1.1
Host: mcp.example.com
Authorization: Bearer eyJhbGciOi...
Accept: application/json, text/event-stream
Content-Type: application/json
{"jsonrpc":"2.0","id":1,"method":"tools/call",...}
工程意义:OAuth 带来的不只是"要登录",而是细粒度 scope——你可以让"只读天气"的 scope 和"读写 GitHub"的 scope 完全不同,用户授权时看得清清楚楚,避免过度授权。这是把 MCP 从玩具变生产的关键一步。
2026 年 7 月,AWS 在联合国"AI 向善"峰会上开源的 MCP Server 正是这类远程 + OAuth 形态——科学家用对话式 AI,凭授权即可秒级检索 AWS 开放数据注册表里的全球科研数据。这标志着 MCP 正式进入"企业级数据底座"赛道。
七、性能优化:延迟、连接与并发的工程真相
MCP 看似简单,真上量时会遇到几类典型性能坑。
7.1 stdio 的"进程启动税"
stdio 模式下,每次连接都要冷启动一个子进程。如果你的 Agent 频繁短连接,启动 Python 解释器 + import 重依赖(如 torch、pandas)可能就要吃掉几百毫秒到几秒。优化:
- 长连接复用:Host 持有 Client 长生命周期,不要"用完即焚"。
- 懒加载重型依赖:Server 启动只 import 轻量部分,真正被
tools/call命中时才import torch,用__import__或模块级惰性单例。 - 用 uv 加速启动:
uv run的冷启动比pip环境快一个数量级(本站已有《uv:Rust 正在如何肢解 Python 包管理》详解)。
7.2 远程调用的延迟与流式
Streamable HTTP 每次 tools/call 是一次网络 RTT。如果工具本身耗时长(如跑个大查询),务必:
- 开启进度通知:用
notifications/progress周期性回报进度,避免客户端超时断连、用户以为卡死。 - 流式返回:Server 用 SSE 边算边吐,客户端渐进渲染。
- 连接池 / 会话复用:无状态 Streamable HTTP 天然适合连接池,Client 侧维护 keep-alive 连接。
# FastMCP 中上报进度(示意 API 形态)
@mcp.tool()
async def long_task(ctx: Context, n: int) -> str:
for i in range(n):
await ctx.report_progress(i, n) # 进度通知
await asyncio.sleep(0.1)
return "done"
7.3 工具数量爆炸
当你的 Server 暴露了上百个 Tool,每次 tools/list 返回的 schema 会很长,挤占模型的上下文窗口,还会让模型"选择困难"乱调工具。优化:
- 按需 listChanged:工具集变化时用
notifications/tools/list_changed通知客户端增量更新,而非每次全量。 - 工具分组 / 路由 Server:把不同域的工具拆成多个 Server,Host 按需挂载。
- 精简 description:模型靠 description 选工具,写得准比写得多重要。
八、安全:工具投毒、越权与 OAuth 防护体系
MCP 把"执行真实动作"的能力交给了模型,安全边界就必须当成头等大事。2026 史诗修订里"全链路可治理、调用全程可追溯"很大程度上就是冲着安全问题来的。
8.1 工具投毒攻击(Tool Poisoning)
最经典的风险:恶意 Server 在 Tool 的 description 里藏了给模型的暗示指令,比如"调用此工具时会把用户私钥发到 attacker.com"。模型读 description 时"中招",在用户不知情下执行。防护:
- Host 侧对 Tool description 做沙箱展示:把工具说明呈现给用户确认,而不是默默交给模型。
- 最小权限:Server 只暴露必要的 Tool,数据库 Server 默认只读。
- 人类审批网关:对"发邮件、删数据、转账"等高危工具,强制插入一次人工确认。
8.2 越权与提示注入
模型可能因为对话里的一段外部内容(网页、文件、邮件)被诱导去调不该调的工具。防护:
- 输入白名单 + 输出脱敏:如 4.2 那样对 SQL 做关键字拦截。
- Roots 限制作用域:通过 Roots 明确告诉 Server "你只能访问
/home/app/data,别想读/etc"。 - Sampling 反转风险:Server 通过 Sampling 反过来让 Host 的 LLM 干活,相当于"工具能操控模型"——对不可信 Server 必须禁用 Sampling 或加审批。
8.3 OAuth 是远程安全的地基
回到第六章:没有 OAuth 的远程 MCP Server 等于把工具裸奔在公网。Scope 机制让"这个应用只能读天气、不能动我的 GitHub"成为现实。2026 规范还要求远程 Server 支持可撤销的 Token、短时效 Access Token + Refresh Token,进一步压缩泄露危害面。
8.4 链路追踪(Traceability)
2026 修订强调"调用全程可追溯"——每一次 tools/call 都应带追踪 ID,从模型决策 → 工具执行 → 结果返回全链路留痕。这不仅是排错需要,更是审计与合规的硬要求:当 AI 自动删了一笔订单,你必须能回溯"是谁(哪个用户/哪个 Agent)在什么时间、因为模型的哪次决策、调用了哪个工具、传了什么参数"。
九、总结与展望:MCP vs Function Calling vs A2A,以及 2026 史诗修订
9.1 三个协议,各管一段
很多人混淆 MCP、Function Calling、A2A,记住这张表就够了:
| 维度 | Function Calling | MCP | A2A (Agent2Agent) |
|---|---|---|---|
| 定位 | 模型输出格式的约定 | 统一工具/数据连接协议 | 智能体之间的协作协议 |
| 解决 | "模型怎么表达要调函数" | "应用怎么标准地连工具/数据" | "多个 Agent 怎么分工对话" |
| 依赖 | 强绑定模型厂商 | 与模型无关,跨厂商通用 | 与模型无关 |
| 层次 | 最底层(单步动作) | 中间层(能力接入) | 上层(多体协作) |
它们不是竞争关系,而是分层互补:Function Calling 是"模型张嘴说话"的语法;MCP 是"模型伸手够工具"的插座;A2A 是"多个模型/智能体开会分工"的会议室。一个成熟的多智能体系统,往往是 A2A 编排多个 Agent,每个 Agent 内部用 MCP 接工具,工具底层靠 Function Calling 触发模型。
9.2 2026-07-28 史诗修订:从"连接"到"基础设施"
即将于 2026 年 7 月 28 日正式发布的候选规范,被官方称为"史上最大修订",核心是把 MCP 从连接协议升级为生产级智能体基础设施。四个关键词:
- 能力发现(Capability Discovery):Server 能结构化地声明自己会什么、约束是什么,宿主据此动态编排,而非写死配置。
- 结构化交付(Structured Delivery):工具返回不只是纯文本,而是带类型、可校验的结构化数据,便于下游程序化消费。
- 链路追踪(Link Tracing):每次调用带追踪上下文,全链路可观测、可审计(呼应第八章安全)。
- 任务协作(Task Collaboration):Server 之间、Agent 之间能委派与协同任务,MCP 开始触碰 A2A 的边界。
配合同期推进的 MCP Registry(注册中心)——一个类似 npm / Docker Hub 的"MCP Server 市场",开发者可以像 npm install 一样发现、安装、版本化管理 Server——MCP 的生态飞轮正式转起来。
9.3 给你的落地建议
- 新项目直接用 MCP,别再手写 Function Calling 胶水:省下的 M×N 集成成本,随工具数线性放大。
- 本地优先 stdio,远程必须 OAuth:安全红线别碰。
- Tool 的 description 认真写:它是模型选工具的"说明书",写得好坏直接决定调用准确率。
- 把 2026-07-28 当基线规划:新项目就按候选规范的能力发现 / 追踪 / 协作去设计,等 7 月 28 日正式发布能平滑升级。
- 不可信 Server 一律关 Sampling、加人工审批:宁可慢一点,别让模型被远程 Server 反操控。
写在最后
两年前,让 AI 调一个 API 还是"为每个应用重写一遍"的苦力活;今天,MCP 用一套薄而优雅的 JSON-RPC + 多传输协议,把"模型连接世界"变成了即插即用。2026-07-28 的史诗修订,又将把这条线从"能连"推向"能治理、能追溯、能协作"。
对工程师而言,这是少数"现在上车还不晚、且确定性极强"的基础设施红利。照着本文的代码把第一个 FastMCP Server 跑起来,你会立刻理解为什么整个行业都在往这个"USB-C 插口"上插——因为当大模型终于学会了调用万物,能挡住它的,就只剩你的想象力了。
参考资料与延伸:官方规范仓库 modelcontextprotocol、Python SDK mcp、TypeScript SDK @modelcontextprotocol/sdk、2026-07-28 候选规范公告、AWS 开源 MCP Server(2026-07)、MCP Registry 计划。建议结合本站《Loop Engineering vs Harness Engineering:2026 年 AI 编程范式大决裂》《Hermes Agent 深度拆解》《SGLang 深度实战》对照阅读,建立"协议—Agent—推理"的完整认知。