本页目录5
- MCP 直接工具调用存在两大问题:海量工具定义占用上下文、中间结果需多次经过模型上下文
- 解决思路是把 MCP 服务器呈现为代码 API(如 servers/google-drive/getDocument.ts),代理编写代码调用而非逐次工具调用
- 官方示例中,一次会议记录写入 Salesforce 的操作从约 15 万 token 降到约 2000 token,降幅约 98.7%
- 渐进式披露(按需读取工具定义)、执行环境内过滤聚合数据、循环与条件控制流,都是可直接落地的技巧
- 代码执行还能实现敏感数据令牌化保护隐私,以及把常用代码片段存成可复用的「技能」文件
- 代价是需要额外的沙箱、资源限制与监控基础设施来安全运行代理生成的代码
本文是对 Anthropic 官方文章「Code execution with MCP: Building more efficient agents」的中文要点摘要,完整内容以原文为准:https://www.anthropic.com/engineering/code-execution-with-mcp
背景:MCP 直接调用工具会「烧」很多上下文
MCP(Model Context Protocol)让代理可以连接文件系统、Google Drive、Salesforce、Slack 等各种外部工具。但当代理直接以「工具调用」的方式使用 MCP 时,会遇到两个规模化问题:
- 工具定义占位大:代理接入的 MCP 服务器越多,需要预先加载进上下文的工具定义就越多。文章指出,当连接的工具达到数千个规模时,仅工具定义就可能吃掉数十万 token,拉高延迟和成本。
- 中间结果被重复传递:多步工具调用中,上一步的完整输出往往要原样再传回模型,才能作为下一步调用的参数。文章给出的例子是:下载一份 2 小时的会议转录文本,再把它写入 Salesforce,转录全文需要在模型上下文里出现两次,仅这一步就可能多消耗约 5 万 token。
核心方案:把 MCP 服务器变成「代码 API」
官方给出的解法是:不要让模型直接发起一次次工具调用,而是把每个 MCP 服务器呈现为一棵 TypeScript 文件树,例如:
servers/
├── google-drive/
│ ├── getDocument.ts
│ └── index.ts
├── salesforce/
│ ├── updateRecord.ts
│ └── index.ts
代理不再逐步调用工具,而是直接编写一段代码,在执行环境里完成整条链路:
const transcript = (await gdrive.getDocument(
{ documentId: 'abc123' }
)).content;
await salesforce.updateRecord({
objectType: 'SalesMeeting',
recordId: '00Q5f000001abcXYZ',
data: { Notes: transcript }
});
转录文本只在执行环境内部流转一次,不需要往返模型上下文。官方给出的对比数字是:同样的会议记录写入任务,从约 15 万 token 降到约 2000 token,降幅约 98.7%。
可落地的几个技巧
渐进式披露(progressive disclosure):不预先把所有工具定义塞进上下文,而是让代理按需「查阅」,比如通过 search_tools 之类的能力配合 detail level 参数,只在真正要用某个工具时才加载它的完整定义。
在执行环境里过滤/聚合数据:拿到一张万行级别的表格后,不要把全部行都交给模型,而是在代码里先筛选、汇总,只把关键的几行结果打印出来:
const allRows = await gdrive.getSheet({ sheetId: 'abc123' });
const pendingOrders = allRows.filter(row =>
row["Status"] === 'pending'
);
console.log(pendingOrders.slice(0, 5));
一万行数据最终只需要向模型展示 5 行。
更强的控制流:用代码里的循环、条件判断、错误处理代替一连串工具调用的手动编排,比如轮询某个 Slack 频道直到出现「deployment complete」消息为止。
隐私保护:中间结果默认只留在执行环境中,不经过模型;文章还提到可以对敏感数据(邮箱、电话、姓名等 PII)做自动令牌化,用「EMAIL_1」这类占位符替换真实值,模型只看到占位符,真实数据通过 MCP 客户端的查找表在工具之间直接流转,绕开模型上下文。
状态持久化与「技能」复用:代理可以把中间结果写入文件,跨多次执行继续处理;还可以把写好的常用代码片段保存为可复用的「技能」文件,例如把某个「读取表格并存成 CSV」的函数固化下来,以后直接调用而不用每次重新生成代码。
权衡与风险
官方也明确指出,这套方案把复杂度转移到了执行侧:让代理生成并运行代码,需要一个具备沙箱隔离(sandboxing)、资源限制(resource limits)和监控(monitoring)能力的安全执行环境。也就是说,节省下来的 token 成本,要用额外的基础设施建设和运维投入来换。
结论
MCP 本身解决的是「协议层」的连接问题,让代理能统一接入多种工具;但当工具数量和调用链路变长后,工具定义与中间结果会持续挤占上下文。文章的建议是:把软件工程里已经成熟的模式(封装成 API、按需加载、过滤聚合、控制流、持久化)搬到代理与 MCP 的交互方式上,用「写代码调用」替代「逐次工具调用」,是应对规模化场景下上下文效率问题的一个可行方向。官方也欢迎实践者把自己的经验反馈给 MCP 社区。