🏠 总目录📚 本教程 08 · MCP 接入外部 ← →
📑 本页目录(点开跳转)

08 · MCP:接入外部世界

⏱ 44 分钟 | ⭐ 核心


🎯 一句话

MCP(Model Context Protocol)解决 M×N 问题:M 个 Agent × N 个系统, 不再需要 M×N 个定制集成,而是各自实现一次标准协议。它是 Agent 世界的 USB 接口。


🔌 一、没有 MCP 之前的痛

你的 Agent(Host)MCP = 统一插头GitHubServer数据库Server文件系统Server但每接一个 Server,上下文就先被吃掉一块工具定义(还没干活)真正能用来干活的⚠️ 接 5 个 Server ≈ 60 个工具定义 —— 按需加载,或改用代码执行来调它们
上半张是 MCP 解决的问题:N 个应用 × M 个工具,从 N×M 变成 N+M。⚠️ 下半张是它带来的新问题:工具定义在你还没开口之前就已经占掉了预算。

对照

每个 Agent 接每个系统都要单独写:

认证怎么做?工具怎么暴露?返回格式怎么定?错误怎么处理?

Agent A 定制 → Slack 3 个 Agent × 4 个系统

Agent A 定制 → GitHub = 12 套定制集成

Agent B 定制 → Slack 每次加一个系统,所有 Agent 都要改 💥

·

MCP 的答案:定一个标准协议,工具提供方实现一次 MCP Server, 任何支持 MCP 的 Agent(Client)都能即插即用。

SlackMCP ServerGitHubMCP Server数据库MCP Server标准协议任何 Agent即插即用加一个系统 = 只写一个 Server加一个 Agent = 什么都不用写 ✅
要看的是线的条数:左边每个系统只有一条线出去,右边每个 Agent 只有一条线进来 —— 中间那道标准协议把原本 M×N 条定制连接压成了 M+N 条。⭐ 所以接入方越多,MCP 省掉的连接越多,这是它值得存在的全部理由。

MCP Server 能暴露三类东西

类型 是什么 例子 谁触发
Tools 可调用的操作 create_issue() 模型(用得最多)⭐
Resources 可读取的数据 一份文档、一张表 应用/用户
Prompts 预置的提示模板 「代码审查」模板 用户

日常 90% 的场景用的是 Tools。


🧱 二、三层协议:Function Calling / MCP / A2A 各在哪一层

读完第 7 章(工具怎么设计)和上一节(MCP 解决 M×N), 几乎所有人都会冒出同一个疑问:Function Calling 和 MCP 到底是不是一回事?

不是。它们根本不在一层上,加上 Agent 之间的 A2A,一共三层:

Function Calling MCP A2A
连的是谁和谁 模型 ↔ 工具 工具 ↔ 宿主程序 Agent ↔ Agent
解决什么 模型怎么把「我要调这个」说出口 工具怎么被接进来、被发现 两个自主系统怎么互相托付任务
谁在实现它 模型厂商(训练 + API 格式) 工具提供方 + Agent 宿主 双方的 Agent 平台
没有它会怎样 模型只能吐散文,你得自己正则解析 每接一个系统写一次定制集成(M×N) 只能把对方当成一个工具来调
换掉它意味着 换模型 换适配层 换协作方

🔑 一句话记住三层: Function Calling 是「怎么说」,MCP 是「怎么接」,A2A 是「怎么托付」。 ⭐ 三者是叠加不是替代——一次 MCP 工具调用,底下走的仍然是 Function Calling。

① Function Calling:模型和工具之间的接口约定

它只约定两件事:

操作步骤

  1. 你怎么把工具告诉模型 名字 + 描述 + 参数 schema(第 7 章讲的就是这个的内容)
  2. 模型怎么把调用意图说出来 一个结构化的 tool_use 块,而不是一段散文

⭐ 关键认知:它不负责执行。 模型只是「说出」它想调什么,真正去调的是你的代码—— 第 1 章那个循环里的分支。

这也正是「Function Calling ≠ Agent」的原因:它只提供了一次往返的格式, 而循环、状态、错误处理、什么时候停,全都还在你这儿(第 1 章 + 第 12 章)。

💡 模型为什么知道该输出 tool_use 而不是散文:这是训练出来的,不是提示词技巧。 所以不同模型的工具调用可靠性差别很大——参数漏填、该并行调却串行调、该停不停, 都是模型能力问题而不是协议问题(选型见第 2 章)。

⚠️ 一个容易混的邻居:Structured Outputs / JSON mode 和 Function Calling 长得很像 (都是让模型吐结构化数据),但目的不同:前者是「输出要有格式」,后者是「我要调外面的东西」。 见 16c · 接进真实产品。

② MCP:工具和宿主之间的传输与发现协议

MCP 比 Function Calling 高一层:它压根不关心模型怎么表达调用意图(那是上一层的事), 它关心的是——工具从哪来、怎么被发现、怎么连上。

三个角色(上一节只讲了 Server 和 Client 两端,还差最重要的 Host):

角色 是谁 干什么
Host(宿主) ⭐ 用户面对的那个应用:IDE、聊天客户端、你自己的 Agent 服务 决定接哪些 Server、谁有什么权限、把工具交给模型、拿回返回值。管理宿主侧信任边界
Client(客户端) Host 内部为每个 Server 开的一条连接 处理连接、版本与能力;是否握手/维持会话取决于协议版本
Server(服务端) 工具提供方写的那个进程或服务 声明自己有哪些 Tools / Resources / Prompts,被调时执行

Host 和 Server 各自承担信任边界。 Host 决定接哪些服务、向模型暴露什么、何时要求用户确认;Server 验证调用身份、权限和资源归属,并实施业务规则。不能因为 Host 应该检查过,就允许 Server 跳过授权。

Client 负责协议适配。旧协议维护连接与协商;2026-07-28 使用逐请求能力和版本元数据。受保护 HTTP 服务还要验证 token 的有效期、audience 和 scope,双方用 trace ID 贯通审计。见官方授权规范与08c 的完整实验。

两种 Transport:

stdio HTTP(含流式)
怎么连 Host 把 Server 当子进程拉起来,走标准输入输出 网络请求
天然形态 一对一,随宿主进程生死 一对多,独立部署、独立扩容
认证 靠操作系统的进程边界,通常没有额外认证 必须自己做(见本章第五节 ④)
适合 本地工具、桌面开发、要读本机文件 ⭐ 生产主流:多用户、要审计、要独立发版
⚠️ 坑 子进程继承所授予的权限,须按需要限制;Server 挂了 Host 不一定感知得到 长连接的超时与重连要自己扛,跨网络多一个攻击面

🔑 判断口诀:Server 和用户在同一台机器上 → stdio;不在 → HTTP。 别拿 stdio 去做多用户共享——它根本没有租户的概念。

还有一半价值容易被忽略:发现。Server 能自报家门(我有哪些工具、参数长什么样), 所以 Host 可以在运行时把工具列表拿到再交给模型。 ⭐ 这正是上一节 Tool Search 能成立的前提:工具是运行时可枚举的,才谈得上延迟加载。

③ A2A:Agent 和 Agent 之间的协作协议

一个很自然的反问:既然 MCP 什么都能接进来,把另一个 Agent 也包成一个 MCP Server 不就行了?

能,但会丢掉三样东西:

丢掉什么 为什么
对方是自主的 工具调用的心智模型是「我给参数,你返回结果」。而另一个 Agent 会自己规划、可能反问你、可能中途需要人批准——包成工具,你只能拿到最后那个返回值
过程可见 跑几十分钟的长任务需要中间状态、进度、可取消。工具调用是一问一答
能力发现是跨组织的 你接一个 MCP Server 是因为你决定接它;跨组织协作时,你得先知道对方能做什么、以什么形式交付

所以 A2A 这一层要定义的东西和 MCP 完全不同:对方是谁、能干什么(能力描述)、 一个任务的生命周期(提交 / 进行中 / 需要补充输入 / 完成 / 失败)、 交付物长什么样(结构化的产物,而不是一段文本)、长任务怎么推送进度。

⭐ 它和 MCP 是互补不是替代。 一个典型的企业形态是:

结果对照

A2A 横着连 团队A的Agent ←→团队B的Agent ←→供应商的Agent
MCP 竖着连 每个 Agent→接自己那堆系统(Jira / 数据库 / 内部服务)

⚠️ 给这一层泼一盆冷水:跨组织的 Agent 协作目前还没跑出规模化的成功案例,协议本身也在动。 你应该知道这一层要解决什么问题(那是稳定的),但不必记它今天的字段名(那会过期)—— 这就是 16b · 框架这层皮 那条判据:框架会过期,原理不会。


⚠️ 三、MCP 的甜蜜陷阱:工具定义撑爆上下文

关键信息

接上 5 个 MCP Server = 58 个工具
光工具定义就吃掉 55K token
Agent 还没干活,注意力预算先被"工具菜单"花光了(第 4 章)

三个官方解法,按你的瓶颈选:

瓶颈 解法 实测效果
工具定义太多 Tool Search:工具标记延迟加载,初始只给一个搜索工具(约 500 token),用时再取 token 省 85%;准确率反而升(Opus 4.5:79.5% → 88.1%)⭐
中间结果污染上下文 程序化调用:模型写代码编排工具,中间数据在沙箱流转,只有最终结果进上下文 token 省 37%
参数总用错 工具示例:input_examples 给最小/部分/完整三类调用样例 复杂参数准确率 72% → 90%

💡 注意 Tool Search 那一行:减少上下文的同时准确率上升了。 这再次印证第 4 章的核心命题——上下文不是越多越好,工具菜单也是噪声。


🚀 四、更激进:代码执行 + MCP

把「工具调用」改造成「写代码」:

流程图

传统:每次工具调用都往返一次模型,中间结果全过上下文
模型→调 read_sheet()→【1万行数据进上下文】💀
模型→调 filter()→结果又进上下文
模型→调 write()→·
代码执行:MCP 工具变成代码 API(沙箱里的模块)
模型写一段代码:
rows = await gdrive.sheets.read( · ) # 1万行
filtered = rows.filter(r => r.amount > 100) # 沙箱里过滤
await salesforce.update(filtered) # 只写回结果
上下文里只有【这段代码】+ 最终摘要 ✅

📌 官方案例:150,000 token 降到 2,000(省 98.7%)。

三个红利:

红利 说明
渐进式披露 模型用 ls/read 按需探索工具定义,不用预载(第 4 章)
数据不过模型 ⭐ 大数据集在沙箱里处理,既省 token 又保隐私
控制流免费 循环、重试、条件分支用代码写,不烧模型轮次

代价:需要一个安全的代码沙箱(第 15 章)。


🏭 五、生产接入的六条经验

① 远程 Server 是主流形态

信息关系

本地 stdio Server→只适合桌面开发场景
远程 HTTP Server→Web/移动/云部署都能用 ⭐

(两种 Transport 各自的机制和坑,见本章第二节 ②。)

② ⭐ 按意图分组,别镜像 API

这是第 7 章原则 ① 的 MCP 版,也是最常被违反的一条:

结果对照

❌ 把 REST API 的端点一比一暴露
GET /issues, POST /issues, GET /users, POST /comments ·
模型要「从这个讨论串创建一个 issue」得调 4 次
✅ 按用户意图设计
create_issue_from_thread(thread_url, assignee_hint)
一次搞定,内部自己调那 4 个 API

③ 大接口面用代码编排

📌 Cloudflare 的做法:用两个工具覆盖约 2,500 个 API 端点 ——一个搜文档、一个执行代码。

思路:当端点多到无法一一暴露时,别暴露端点,暴露"查文档 + 执行"的能力。

④ 认证要标准化

登录、授权码与刷新流程复用身份平台;MCP Server 仍须验证 token 签名或内省结果、audience、scope 与过期时间,再查资源权限。Host 的确认弹窗和协议会话 ID 都不能替代服务端授权。

⑤ ⚠️ 「审计过的连接器 ≠ 审计过的数据」

关键信息

MCP Server 本身可信(你审过代码)
≠
它取回来的内容可信(那是外部数据)
从 MCP 读到的网页/邮件/工单,都可能携带提示注入

🔗 这是第 15 章的核心议题。MCP 扩大了攻击面—— 每接一个 Server,就多一个外部内容入口。

⑥ 工具返回也要控制体积

MCP 工具和自己写的工具一样,返回内容会永久占据上下文(第 7 章原则 ④)。 接第三方 Server 时,先看它的返回有多大——有些 Server 的默认返回非常臃肿。


🧭 六、什么时候用什么(决策表)

场景 建议
本地开发,接文件系统/git 内置工具或 CLI 就够,别为用 MCP 而用 MCP
接一两个内部 API,只有你自己用 直接写工具函数更简单
多个 Agent 要共用同一批系统 ⭐ MCP,一次实现处处可用
接第三方 SaaS(Slack/GitHub/Jira…) 用现成的官方 MCP Server,别重复造
工具超过 20 个 上 Tool Search
数据量大 / 编排复杂 代码执行 + MCP
需要给外部团队提供能力 MCP(这正是它的设计目标)

🔑 一个判断原则:MCP 的价值随「Agent 数量 × 系统数量」增长。 只有一个 Agent 接一个系统时,它是纯开销。


🕳️ 七、六个常见坑

坑 症状 修
以为 MCP 取代了 Function Calling ⭐ 概念错位,出问题时找错层:明明是模型参数填错(上层),却去改 Server(下层) 三层是叠加的——MCP 工具调用底下走的仍是 Function Calling
一比一镜像 API ⭐ 一个简单意图要调四五个工具 按意图重新分组
接太多 Server 上下文被工具定义吃掉一大半 Tool Search / 只接真正需要的
第三方返回臃肿 几轮就烧光预算 包一层做裁剪,或用代码执行
把 MCP 数据当可信 提示注入 外部内容一律当不可信(第 15 章)
为用而用 单 Agent 单系统还搭 MCP 直接写工具函数

📚 延伸阅读


✅ 检查点

  1. MCP 解决什么问题?用一个类比说明。
  2. MCP Server 能暴露哪三类东西?哪类用得最多?
  3. 58 个工具会带来什么问题?首选解法是什么?效果如何?
  4. 代码执行 + MCP 为什么能省 98% 的 token?三个红利是什么?
  5. 「按意图分组,别镜像 API」什么意思?Cloudflare 怎么处理 2500 个端点的?
  6. 「审计过的连接器 ≠ 审计过的数据」什么意思?
  7. 什么时候不该用 MCP?
  8. Function Calling、MCP、A2A 分别连接谁和谁?三者是替代关系吗?
  9. MCP 的 Host / Client / Server 各干什么?Host 与 Server 分别检查哪些权限?stdio 和 HTTP 怎么选?
  10. 把另一个 Agent 包成一个 MCP Server 来用,会丢掉哪三样东西?
👀 答案
  1. M×N 集成爆炸——M 个 Agent 接 N 个系统本需 M×N 套定制集成。MCP 让两边各实现一次标准协议。类比 USB。
  2. Tools(可调用操作,模型触发,用得最多)、Resources(可读数据)、Prompts(预置模板)。
  3. 工具定义吃掉几万 token,注意力预算先被工具菜单花光。首选 Tool Search:延迟加载,省 85% token,且准确率反而上升(79.5%→88.1%)。
  4. 中间数据在沙箱里用代码处理不经过上下文。三红利:渐进式披露(按需探索工具定义)、数据不过模型(省 token + 保隐私)、控制流免费(循环重试用代码不烧模型轮次)。
  5. 一个工具对应一个用户意图(内部可以调多个 API),而不是把 REST 端点原样暴露。Cloudflare 用两个工具(搜文档 + 执行代码)覆盖 2500 个端点。
  6. MCP Server 本身可信不代表它取回的内容可信——外部网页/邮件/工单可能携带提示注入。每接一个 Server 就多一个攻击面。
  7. 单 Agent 接单系统时(直接写工具函数更简单)、本地开发接文件系统/git 时(内置工具够用)。MCP 的价值随「Agent 数 × 系统数」增长。
  8. Function Calling=模型 ↔ 工具(一次调用的格式约定,「怎么说」);MCP=工具 ↔ 宿主(传输与发现,「怎么接」);A2A=Agent ↔ Agent(任务托付,「怎么托付」)。三者叠加不是替代——一次 MCP 工具调用底下走的仍然是 Function Calling。
  9. Host 是用户面对的那个应用,决定接哪些 Server、给什么权限、把工具交给模型并执行返回值;Client 是 Host 为每个 Server 开的一条一对一连接;Server 是工具提供方那个进程,声明并执行 Tools/Resources/Prompts。Host 管连接、工具暴露和用户同意;Server 必须验证调用身份、资源权限及业务规则,两边都要留痕。Transport 按部署与宿主能力选择:本地子进程常用 stdio,也可使用本地 HTTP;远程服务通常用 HTTP。stdio 不自动提供多用户身份系统,业务层仍可能需要租户隔离。
  10. ①对方是自主的(会自己规划、会反问、可能要人批准,包成工具只能拿到最后一个返回值)②过程可见(长任务要中间状态/进度/可取消,而工具调用是一问一答)③跨组织的能力发现(你得先知道对方能做什么、以什么形式交付)。

🛑 可以停在这里

⚡ 走神救援

回来时接住这四点

下一节 👉 08b-写一个MCP-Server.md

打卡记录保存在你的浏览器里,首页能看到总进度