每一次标准化,都是把「不可靠的约定」换成「可验证的契约」。但契约解决了连接,没解决分寸。
2022 年底,ChatGPT 刚火起来那阵,几乎所有人都想到同一个用法:能不能让它帮我查天气、下单、翻数据库?
很快就发现,模型真正难的地方不是「知道要干什么」。它早就知道要查天气。难的是另一件事——把想干的事,准确地告诉程序。
它只会吐字。
你让它查北京天气,它可能回一句「好的,我来帮你查一下北京的天气」;也可能回一段 JSON;还可能回半句话加一个表情符号。同样的请求,两次输出格式都可能不一样。程序读不懂这种东西。
于是那段时间,开发者在做同一件事:写正则、写 if-else,从模型的自由文本里把参数抠出来。抠错了就重试。有人后来回忆,那阵子有将近一半的代码,在处理「模型又没按格式说」。
这篇文章要讲的,就是这段历史:工具调用是怎么从「各写各的解析器」,一步步走到今天这个叫 MCP 的公开协议的。
沿着一条主线推进:标准化到底标准化了什么,又有什么东西始终没被标准化?想清楚后半句,比记住前半句更有用。
答案很朴素:全靠提示词工程加文本解析。能跑,但脆得像玻璃。
先把时间拨到 2022 年 10 月。
那时候还没有任何厂商提供官方的函数调用能力。研究者 Yao 等人发了一篇论文,叫 ReAct(Reason + Act)。思路今天看依然漂亮:让模型交替生成「推理」和「行动」。
模型先想一步,输出一个动作,比如 Search[北京天气]。程序把这个动作解析出来,真的去搜,再把结果塞回去。模型看到结果,接着想下一步,或者给出答案。
这是「推理加行动」范式的奠基工作,后来几乎所有 Agent 都长这个样子。
但它有一个前提:模型必须严格按你规定的格式输出。而模型不是为这个格式训练出来的。
有人为了让模型稳定输出 JSON,在提示词里写满了各种强调:「你必须严格输出 JSON」「不要加任何解释」「不要说『好的』」。然后在代码里写正则去匹配。
跑几次就崩了。模型的输出是「这是结果:{"city":"北京"}」,多了一句「这是结果:」,正则匹配不上。于是加一层容错,再崩,再加。
这种做法能上生产吗?能。但它依赖一个很虚的东西——模型今天心情好,愿意按格式说话。换句话说,格式靠自觉,契约并不存在。
LangChain 这类框架后来把这套东西封装成了 Agent / Tool 抽象,看起来专业多了。但扒开看,底层还是提示词约定加文本解析。换汤没换药。
它把「希望模型这么做」,变成了「模型被训练成这么做」。这是从约定走向契约的第一步。
转折点在 2023 年 6 月 13 日。OpenAI 发布博文《Function calling and other API updates》,在 Chat Completions 接口里引入了 function calling,同时放出 gpt-3.5-turbo-0613 和 gpt-4-0613。
机制不复杂,四步:
functions 参数里;function_call,含 name 和 arguments),而不是自由文本;role: "function" 回传,模型基于结果继续推理,或者给出最终回答。schema 就是那份契约:模型知道要往哪个格式里填,程序知道该去哪儿取参数。之前那堆正则,全都可以扔了。
关键转变在于,模型被专门微调过,知道什么时候该输出结构化的调用。格式从「我希望它这么做」,变成了「它被训练成会这么做」。这是从约定走向契约的第一步。
2023 年 11 月 6 日的 DevDay,OpenAI 又推了一把:GPT-4 Turbo 上线,带来 并行函数调用(parallel function calling)。一句话里说「打开车窗并关掉空调」,模型可以在单条消息里返回多个调用,不用来回好几轮。
同一天,参数名也换了:functions 变成 tools,function_call 变成 tool_choice(微软 Azure OpenAI 文档记载,随 2023-12-01-preview 版本弃用旧参数)。这个改名不只是字面功夫——概念从「函数」泛化成了「工具」,为后面接检索、代码执行这些非函数能力留了口子。
同日发布的还有 Assistants API。官方第一次明确把它定位成「构建类智能体体验的第一步」。也就是说,从这一天起,function calling 被正式当成了 Agent 的核心组件。
还剩一个问题。模型大部分时候会按 schema 输出,但偶尔会漏一个字段、多一个逗号。
2024 年 8 月 6 日,OpenAI 发布 Structured Outputs。在工具定义里加上 strict: true,模型输出会被受限解码(constrained decoding)约束,严格符合你给的 schema。
效果有多硬?复杂 JSON schema 的遵循评测里,gpt-4o-2024-08-06 做到 100% 可靠;而一年前的 gpt-4-0613,得分低于 40%。
因为这是「每家自己的标准」。三套契约,互不相通。
Anthropic 也有 tool use,Google 也有 function calling。听起来皆大欢喜,实际上开发者更累了。
因为每一家定义的「契约格式」都不一样。看这张表就明白:
| 厂商 | 怎么描述工具 | 模型怎么返回调用 | 谁执行 |
|---|---|---|---|
| OpenAI | tools 数组 + JSON Schema | tool_calls(name + arguments) | 客户端执行 |
| Anthropic | tools + input_schema | stop_reason=tool_use,返回 tool_use 内容块 | 区分 client tools / server tools |
| Google Gemini | function declarations(OpenAPI 风格) | functionCall | 客户端执行 |
差别不止字段名。Anthropic 用的是内容块机制:模型返回一个或多个 tool_use 块,你把 tool_result 块传回去。而且它明确区分两类工具——client tools 跑在应用侧,server tools(比如 web_search、code_execution)跑在 Anthropic 自己的基础设施上。这套划分,OpenAI 那边没有。
每个工具都想接进每个模型,就要为每一种组合写一份适配代码。M 乘 N,随规模爆炸。中间加一层统一协议,成本降到 M 加 N。
你今天写了一个查 Postgres 的工具,想同时接进三个模型。对不起,得写三份适配代码。三个模型 × 十个工具,就是三十份胶水代码。维护起来是一场灾难。
Anthropic 发布 MCP 时,把这个痛点说得很直白:数据被锁在信息孤岛和遗留系统里,每接一个新数据源,都要做一次定制实现。真正连通的系统,难以规模化。
这就像 USB 出现之前——每个外设一个专属接口,键盘一个口、鼠标一个口、打印机又一个口。直到有人站出来说:我们定一个所有人都认的接口形状吧。
它定的不是「怎么调用」,而是「怎么把你的能力,描述成一个任何客户端都能读懂的接口」。
2024 年 11 月 25 日,Anthropic 开源了 MCP(Model Context Protocol)。发布当天不只是一篇公告,还给了完整规范、SDK、Claude Desktop 的本地 server 支持,以及一批预构建的 server——Google Drive、Slack、GitHub、Git、Postgres、Puppeteer。由 David Soria Parra 和 Justin Spahr-Summers 主导。
目标是六个字:一次编写,到处集成(write once, integrate everywhere)。
MCP 用的是 Host / Client / Server 三层模型:
这里有个克制的设计原则:server 不该能读整段对话,也不能「看进」其他 server。能力通过初始化时协商,可以渐进式添加。
数据层跑在 JSON-RPC 2.0 上。传输层支持 Stdio(本地进程走标准输入输出)和 Streamable HTTP(远程)。Server 暴露三种核心原语:
客户端那边也保留了几个原语。最有意思的是 Sampling:server 可以通过 sampling/createMessage,反过来请求宿主的 LLM 做一次补全。这样一来,一个 server 不必内置任何模型 SDK,就能保持模型无关。
还有 Elicitation(向用户要额外信息或确认)和 Logging(发调试日志)。
一个协议定下来不就完了?不。它在真实使用里被发现问题,然后选择改,甚至做减法。
MCP 从 2024 年底到现在,经历了好几轮大改。值得关注的是,改动方向很明显:越来越像一套正经的工程协议——无状态、可授权、可扩展。
| 版本 | 关键变化 |
|---|---|
| 2024-11-05 | 初始规范。本地 Stdio + HTTP/SSE 两种传输。 |
| 2025-03-26 | 引入 OAuth 2.1 授权框架;用 Streamable HTTP 替换 HTTP+SSE;加 JSON-RPC 批处理;加 tool annotations(标注工具是否只读、是否有破坏性)。 |
| 2025-06-18 | 去掉批处理;加结构化工具输出;把 server 归为 OAuth Resource Server,引入 RFC 8707 Resource Indicators 防恶意 server 骗 token;加 elicitation 和 resource links。 |
| 2025-11-25 | 一周年版。引入 Tasks(长时任务)与官方 Extensions 框架;简化授权流程;治理结构成型(58 名 maintainer、9 名核心)。 |
| 2026-07-28 | 目前最大一次修订。走向无状态核心——移除 initialize 握手和 Mcp-Session-Id,协议版本改由每次请求的 _meta 携带,可以在普通负载均衡器后面跑,不再依赖 sticky session。Extensions 升级为一等公民。 |
2026-07-28 这一版里,有个容易被忽略但意味深长的动作:Roots、Sampling、Logging 三项核心特性被弃用(标注为 deprecated,一年内仍可用)。
尤其是 Sampling。它当年是 MCP 设计里的一个亮点——让 server 不用内置模型 SDK,就能借用宿主的模型。但到了 2026 年,官方建议:改为直接集成 LLM provider 的 API。
当初想得很美的设计,不一定活得下来。协议是会长出赘肉然后被修剪的。
更重要的变化在治理层。2025 年 12 月 9 日,Anthropic 把 MCP 捐给了 Linux Foundation 旗下的 Agentic AI Foundation(AAIF)。
这个基金会由 Anthropic、Block、OpenAI 联合创立,Google、微软、AWS、Cloudflare、Bloomberg 支持。三个创始项目是:Anthropic 的 MCP、Block 的 goose、OpenAI 的 AGENTS.md。
关键安排是:技术方向仍由原 maintainer 团队自治,Linux Foundation 提供中立基础设施,不干预技术路线。这套路子很眼熟——Kubernetes、PyTorch、Node.js 都是这么走的。
标准化解决了「能不能连上」,没解决「连上之后安不安全、划不划算」。
假设现在全世界都用 MCP 了。工具都能连上了。那还有问题吗?
有,而且不小。问题从「接口格式」转移到了「接口之外」。
最刺眼的一个,是 STDIO 命令注入。2026 年 4 月,安全厂商 OX Security 披露:MCP 的 STDIO 传输会无条件执行传入的 command 字段。这个默认行为顺着官方实现,传导进了所有主流语言绑定(Python、TypeScript、Java、Rust)和下游项目,波及 7000 多个公开 server 与包、1.5 亿多次下载。Cloud Security Alliance 给它的定性很狠——「设计即 RCE(远程代码执行)」。
另一类风险是提示注入与上下文投毒。MCP 会把工具描述全量注入模型上下文。如果某个工具的描述里藏了恶意指令,它就能借「工具元数据」污染模型的推理。Palo Alto 的研究还指出,Sampling 机制带来了资源盗用、对话劫持、隐蔽工具调用这几类新攻击面。
权限方面也松。第三方一项覆盖 210 名安全从业者的调研显示,64.8% 的企业 MCP 集成存在过度授权,或使用了 root 级工具权限。而 IETF 的一份草案进一步指出:MCP 的 JSON-RPC 消息没有签名,客户端与 server 无法用密码学验证对端身份,理论上可以被冒充和篡改。
这是工程上最日常的痛。
大多数 MCP 客户端,会把所有工具定义预先塞进上下文。你连了上千个工具?那模型还没读到你的问题,上下文里已经躺着几十万 token 的工具描述了。
而且成本是持续的。每个工具 schema 的每个字节,每一轮对话都要重新进一次上下文。有研究审计了 1862 个公共 server,发现连良性 server 的冗长描述,也会抬高 token 成本、拖慢 agent 表现。
中间结果也重复流转。Anthropic 举过一个例子:处理两小时的会议纪要,可能因为结果反复经过模型,额外多烧掉 5 万 token。
这一条最反直觉。
一个受控实验的结果:10 个工具时任务完美完成,20 个时 20 次里对 19 次,到了 107 个,大小模型全部失败。不是慢慢变差,是一脚踩空。数据来自二手汇总,仅供参考。
模型选工具的准确率,并不随工具数量平滑下降。它在某个点之后,会突然崩掉。这背后的直觉是:工具越多,名字越像、描述越重叠,模型挑错的概率就越高,而错一次,整条链路就废了。
一条路是换掉调用方式,一条路是让协议分层。它们其实在回答两个不同的问题。
这是目前最有意思的一场范式之争。
Anthropic 在 2025 年 11 月的工程博客里提了个方案:不把 MCP 工具直接暴露给模型,而是把它们呈现成「代码 API」,让 agent 写代码去调用。
这样做的好处很实在。模型按需加载工具定义,而不是全量预加载;它可以在执行环境里先过滤、聚合数据,只把真正需要的结果回传。博客里给了一个案例:token 从 150,000 降到 2,000,省了 98.7%。顺带还有隐私收益——中间数据默认留在执行环境,敏感信息「流经但不进入模型上下文」。
Cloudflare 走了同一条路,叫 Code Mode。它把 MCP 工具转成 TypeScript API,理由很朴素:LLM 见过海量真实的 TypeScript 代码,却只见过少量「合成」的工具调用样例。所以它写代码调用,比直接做结构化调用更擅长,多步串联时优势尤其明显。
代价也清楚:要跑模型生成的代码,就得有安全沙箱、资源限制、监控。Cloudflare 的做法是用 V8 isolate,沙箱默认没有公网访问,只能碰那些以 binding 形式注入的已授权接口,API key 由 supervisor 持有,模型写不出会泄露 key 的代码。
这场争论的本质是一句话:要不要把「结构化函数调用」当成模型的头等交互界面?
另一条路是承认:没有哪个协议能包办一切。于是它们分层。
Linux Foundation 把 A2A 的定位说得很明确:与 MCP 互补,而非替代。A2A 发布一年后,支持组织从 50 多家涨到 150 多家,AWS、思科、IBM、微软、Salesforce、SAP、ServiceNow 都在内。
一个典型的组合是这样的:A2A 先负责把任务委派给另一个 agent,接手的那个 agent,再用 MCP 去调它自己的工具。
回到开头那个问题。
从「让模型稳定吐个 JSON 都费劲」,到今天一个 server 任何客户端都能接,工具调用确实被标准化了。这条路走了三年:ReAct 的提示词约定,到 function calling 的私有契约,再到 MCP 的公开协议。
但仔细看,MCP 标准化的是接口的形状——schema 长什么样、怎么握手、怎么授权、怎么发现。
它没有标准化的是分寸——一个 agent 面前摆着上千个工具时该怎么选,一段工具描述里藏了恶意指令该如何防,一个中间结果到底该不该进上下文。
这些,协议解决不了。得靠沙箱、靠工程取舍、靠对整个链路负责的人。
所以下次有人问你「要不要上 MCP」,也许可以先把问题换一下:我要解决的,是「连不上」的问题,还是「用不好」的问题?
这两个问题的答案,往往不一样。