目录
原文链接 https://www.anthropic.com/engineering/code-execution-with-mcp
直接调用工具会为每个工具定义和执行结果消耗上下文空间。智能体通过编写代码来调用工具,能实现更出色的可扩展性。本文将详细介绍其在 MCP 中的实现方式。
模型上下文协议(Model Context Protocol,简称 MCP)是一套用于将 AI 智能体与外部系统相连接的开放标准。传统方式下,要将智能体与各类工具和数据对接,每一种组合都需要单独定制集成方案,这会造成系统碎片化和重复开发,难以构建真正具备可扩展性的互联系统。而 MCP 提供了通用协议 —— 开发者只需在智能体中完成一次 MCP 集成,就能解锁整个生态系统中的各类工具对接能力。
自 2024 年 11 月 MCP 正式推出以来,其落地应用速度十分迅猛:社区已搭建了数千台 MCP 服务器,主流编程语言均已配套对应的 SDK,MCP 也已成为行业内智能体对接工具与数据的事实标准。
如今,开发者通常会为智能体配置可访问的、来自数十台 MCP 服务器的数百乃至数千个工具。但随着对接工具数量的增加,提前加载所有工具定义、并通过上下文窗口传递中间结果的模式,会拖慢智能体运行速度并增加成本。
本文将探讨代码执行如何帮助智能体更高效地与 MCP 服务器交互,实现工具数量扩容的同时降低令牌消耗
1 工具引发的令牌过度消耗降低了智能体效率
随着 MCP 使用规模的扩大,两种常见模式会显著增加智能体的使用成本与延迟:
- 工具定义挤占上下文窗口
- 工具中间结果消耗额外令牌
1.1 工具定义挤占上下文窗口
大多数 MCP 客户端会将所有工具定义提前直接加载到上下文当中,并通过直接工具调用语法将其暴露给模型。这类工具定义的格式示例如下:
|
1 2 3 4 5 6 |
gdrive.getDocument 描述:从谷歌云端硬盘中获取文档 参数: documentId(必填,字符串类型):待获取文档的ID fields(可选,字符串类型):需要返回的特定字段 返回值:包含标题、正文内容、元数据、权限等信息的文档对象 |
|
1 2 3 4 5 6 7 |
salesforce.updateRecord 描述:在Salesforce系统中更新记录 参数: objectType(必填,字符串类型):Salesforce对象类型(如销售线索、联系人、客户等) recordId(必填,字符串类型):待更新记录的ID data(必填,对象类型):待更新字段及其对应新值 返回值:包含更新确认信息的已更新记录对象 |
1.2 工具中间结果消耗额外令牌
大多数 MCP 客户端支持模型直接调用 MCP 工具。例如,你可能会向智能体下达指令:“从谷歌云端硬盘下载我的会议纪要,并将其附加到 Salesforce 销售线索中”。
模型会发起如下工具调用:
|
1 2 3 4 5 6 7 8 9 10 |
工具调用:gdrive.getDocument(documentId: "abc123") → 返回结果“讨论了第四季度目标……\n[完整会议纪要文本]” (该结果会被加载到模型上下文) 工具调用:salesforce.updateRecord( objectType: "SalesMeeting", recordId: "00Q5f000001abcXYZ", data: { "Notes": "讨论了第四季度目标……\n[完整会议纪要文本内容]" } ) (模型需要再次将完整会议纪要写入上下文) |
每一个中间结果都必须经过模型处理。在上述示例中,完整的会议纪要内容被传输了两次。对于一场 2 小时的销售会议,这可能意味着要额外处理 5 万个令牌。若文档体量更大,甚至可能超出上下文窗口的承载上限,导致整个工作流程中断。
当处理大型文档或复杂数据结构时,模型在工具调用之间复制数据的过程中,出现错误的概率也会随之升高。

2 借助 MCP 的代码执行提升上下文使用效率
随着代码执行环境在智能体领域的普及,一种优化方案应运而生:将 MCP 服务器以代码 API 的形式呈现,而非支持直接工具调用,智能体便可通过编写代码与 MCP 服务器交互。这种方式能同时解决上述两大问题:智能体可按需加载所需工具,且能在执行环境中先处理数据,再将结果回传给模型。
具体实现方式多样,其中一种是为已对接 MCP 服务器的所有可用工具生成文件目录结构。以下是基于 TypeScript 的实现示例:
|
1 2 3 4 5 6 7 8 9 10 |
servers ├── google-drive │ ├── getDocument.ts │ ├── ...(其他工具) │ └── index.ts ├── salesforce │ ├── updateRecord.ts │ ├── ...(其他工具) │ └── index.ts └── ...(其他服务器) |
每个工具对应一个文件,示例如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// ./servers/google-drive/getDocument.ts import { callMCPTool } from "../../../client.js"; interface GetDocumentInput { documentId: string; } interface GetDocumentResponse { content: string; } /* 从谷歌云端硬盘读取文档 */ export async function getDocument(input: GetDocumentInput): Promise<GetDocumentResponse> { return callMCPTool<GetDocumentResponse>('google_drive__get_document', input); } |
前文提到的 “从谷歌文档读取会议纪要并同步至 Salesforce” 的需求,可转化为如下代码:
|
1 2 3 4 5 6 7 8 9 10 |
// 从谷歌文档读取会议纪要并添加至Salesforce潜在客户信息 import * as gdrive from './servers/google-drive'; import * as salesforce from './servers/salesforce'; const transcript = (await gdrive.getDocument({ documentId: 'abc123' })).content; await salesforce.updateRecord({ objectType: 'SalesMeeting', recordId: '00Q5f000001abcXYZ', data: { Notes: transcript } }); |
智能体可通过浏览文件系统发现工具:先列出./servers/目录以获取可用服务器(如google-drive和salesforce),再读取所需的具体工具文件(如getDocument.ts和updateRecord.ts),从而了解各工具的接口信息。这使得智能体仅需加载当前任务所需的工具定义,令牌消耗量可从 15 万降至 2000,时间与成本节省率高达 98.7%。
Cloudflare 也发布了类似研究成果,并将这种 MCP 代码执行方式称为 “代码模式”。其核心思路一致:大语言模型擅长编写代码,开发者应利用这一优势,构建能更高效与 MCP 服务器交互的智能体。
3 借助 MCP 实现代码执行的优势
基于 MCP 的代码执行,可让智能体通过按需加载工具、在数据传入模型前进行过滤、单步执行复杂逻辑等方式,提升上下文使用效率。此外,该方式还具备安全防护与状态管理方面的优势。
3.1 渐进式信息披露
模型具备出色的文件系统导航能力。将工具以代码形式部署在文件系统中,模型可按需读取工具定义,无需提前加载全部内容。
此外,还可在服务器中添加search_tools工具以查找相关工具定义。例如,在处理上述 Salesforce 服务器相关任务时,智能体可搜索 “salesforce” 关键词,仅加载当前任务所需的工具。在search_tools工具中设置 “细节层级” 参数,支持智能体按需选择工具定义的详细程度(如仅工具名、工具名 + 描述、含模式的完整定义),也能帮助智能体节省上下文空间、高效定位工具。
3.2 上下文友好的工具结果处理
处理大型数据集时,智能体可在代码中先对结果进行过滤和转换,再将其返回。以获取含 1 万行数据的电子表格为例:
|
1 2 3 4 5 6 7 8 9 10 11 |
// 无代码执行模式——所有行数据均需传入上下文,由模型手动过滤 工具调用:gdrive.getSheet(sheetId: 'abc123') → 1万行数据全部传入上下文 // 代码执行模式——在执行环境中完成过滤 const allRows = await gdrive.getSheet({ sheetId: 'abc123' }); const pendingOrders = allRows.filter(row => row["Status"] === 'pending' ); console.log(`共查询到${pendingOrders.length}条待处理订单`); console.log(pendingOrders.slice(0, 5)); // 仅输出前5条供审核 |
智能体只需处理 5 行数据,而非 1 万行。类似逻辑同样适用于数据聚合、跨数据源关联、特定字段提取等场景,且不会造成上下文窗口膨胀。
3.3 更强大且上下文高效的控制流
循环、条件判断、错误处理等逻辑,可通过开发者熟悉的代码模式实现,无需通过链式的独立工具调用来完成。例如,若需在 Slack 中接收部署完成通知,智能体可编写如下代码:
|
1 2 3 4 5 6 7 |
let found = false; while (!found) { const messages = await slack.getChannelHistory({ channel: 'C123456' }); found = messages.some(m => m.text.includes('deployment complete')); if (!found) await new Promise(r => setTimeout(r, 5000)); } console.log('已收到部署完成通知'); |
相较于在智能体循环中交替执行 MCP 工具调用和休眠指令,这种方式效率更高。
此外,编写可执行的条件判断逻辑,还能缩短 “首个令牌生成耗时” 的延迟:无需等待模型逐行解析条件语句,可直接交由代码执行环境处理。
3.4 隐私保护型操作
智能体基于 MCP 执行代码时,中间结果默认留存于执行环境内。如此一来,智能体仅能获取显式日志或返回的信息,意味着无需与模型共享的敏感数据,可在工作流中流转而不进入模型上下文。
对于高敏感业务场景,智能体的管控组件可自动对敏感数据进行标记脱敏。例如,需将电子表格中的客户联系方式导入 Salesforce 时,智能体编写的代码如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const sheet = await gdrive.getSheet({ sheetId: 'abc123' }); for (const row of sheet.rows) { await salesforce.updateRecord({ objectType: 'Lead', recordId: row.salesforceId, data: { Email: row.email, Phone: row.phone, Name: row.name } }); } console.log(`已更新${sheet.rows.length}条销售线索`); |
MCP 客户端会在数据传入模型前拦截并对个人身份信息(PII)进行脱敏处理:
|
1 2 3 4 5 6 |
// 若智能体打印sheet.rows,其看到的内容为: [ { salesforceId: '00Q...', email: '[EMAIL_1]', phone: '[PHONE_1]', name: '[NAME_1]' }, { salesforceId: '00Q...', email: '[EMAIL_2]', phone: '[PHONE_2]', name: '[NAME_2]' }, ... ] |
当这些数据在其他 MCP 工具调用中传输时,MCP 客户端会通过内部映射表完成脱敏还原。真实的邮箱、电话、姓名可从谷歌表格同步至 Salesforce,但全程不会经过模型处理。这能避免智能体意外记录或处理敏感数据,同时还可通过该机制制定确定性安全规则,管控数据的流转范围。
3.5 状态持久化与技能沉淀
具备文件系统访问权限的代码执行能力,可支持智能体在多次操作间维持状态。智能体可将中间结果写入文件,实现任务断点续跑与进度追踪:
|
1 2 3 4 5 6 7 8 |
const leads = await salesforce.query({ query: 'SELECT Id, Email FROM Lead LIMIT 1000' }); const csvData = leads.map(l => `${l.Id},${l.Email}`).join('\n'); await fs.writeFile('./workspace/leads.csv', csvData); // 后续执行可从断点继续 const saved = await fs.readFile('./workspace/leads.csv', 'utf-8'); |
智能体还可将自身代码保存为可复用函数。一旦智能体开发出能完成特定任务的可用代码,便可将其保存以备后续调用:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
// 路径:./skills/save-sheet-as-csv.ts import * as gdrive from './servers/google-drive'; export async function saveSheetAsCsv(sheetId: string) { const data = await gdrive.getSheet({ sheetId }); const csv = data.map(row => row.join(',')).join('\n'); await fs.writeFile(`./workspace/sheet-${sheetId}.csv`, csv); return `./workspace/sheet-${sheetId}.csv`; } // 后续任意智能体执行流程中均可调用: import { saveSheetAsCsv } from './skills/save-sheet-as-csv'; const csvPath = await saveSheetAsCsv('abc123'); |
这与 “技能(Skills)” 的理念深度契合 —— 技能是指为模型打造的、用于提升特定任务表现的可复用指令、脚本及资源文件夹。在这些已保存的函数中添加 SKILL.md 说明文件,就能形成结构化技能,供模型查阅和调用。长此以往,智能体可逐步构建专属的高阶能力工具箱,形成适配自身高效工作的架构体系。
需注意的是,代码执行也会带来额外复杂性。运行智能体生成的代码,需要搭建具备完善沙箱隔离、资源限额管控及运行监控的安全执行环境。这些基础设施需求会产生一定的运维成本与安全考量,而直接工具调用模式则可规避这些问题。因此,在采用代码执行方案时,需权衡其带来的收益(降低令牌成本、减少延迟、优化工具组合)与实施成本。
4 总结
MCP 为智能体对接各类工具与系统提供了基础协议支撑。但随着对接服务器数量的增多,工具定义与执行结果会造成令牌过度消耗,降低智能体运行效率。
尽管这些问题(上下文管理、工具组合、状态持久化)看似新颖,但软件工程领域已存在成熟解决方案。代码执行正是将这些经过验证的模式应用于智能体,使其能通过熟悉的编程结构,更高效地与 MCP 服务器交互。若你已落地该方案,欢迎向 MCP 社区分享实践经验。





