anthropic.com/engineering/code-execution-with-mcp · 2025-11-04 · Engineering Blog

Code execution with MCP:把工具变成代码

Anthropic 一手原文——agent 不再通过上下文直接调 MCP 工具,而是写代码调。工具变成文件树上的类型化模块,定义按 import JIT 进上下文,数据在变量里流转。五个收益里有两个(隐私 tokenize、状态 + 技能)是二手综述从没提过的——这是 Code Mode 的原始权威出处,Cloudflare 据此文命名 "Code Mode"。

Adam Jones & Conor Kelly · Anthropic 150K → 2K tokens(-98.7%)

零、两个独立的烧 token 问题

一手原文把「工具调用为什么贵」拆成两个互相独立的模式——这是理解 Code Mode 为什么能一次治两个病的前提。Akshay 综述把两者混在一起讲,原文分得很清。

模式 1:工具定义预载 system prompt(常驻上下文) gdrive.getDocument(...) salesforce.updateRecord(...) slack.sendMessage(...) ... 几百上千个 schema 连几千工具 → 还没读请求先烧几十万 tokens schema 全量塞进上下文 每一步都占着 5-server 配置 ≈ 55K tokens 模式 2:中间结果过模型 模型上下文 getDocument() → 转录全文进 [转录全文] 读一遍 ← 转录全文再写一遍 updateRecord(notes=...) 数据来回穿过模型 2 小时会议 ≈ 多烧 5 万 tokens 大文档直接超上下文 两个问题独立——治了 schema 预载,中间结果照样烧 Code Mode 两个一起治
模式 1 是「清单太长」,模式 2 是「数据在模型里来回」。它们独立叠加——这就是为什么光做 schema 精简(如动态加载工具子集)不够,只要还在直接 tool-calling,大数据中间结果照样烧穿上下文。

一、解法的钥匙:工具变文件树

第二个原语(类型化 import)怎么落地?原文给的实现——把所有连上的 MCP server 的工具,生成为一棵文件树,每个工具是一个带类型签名的 TypeScript 文件,内部包一层 callMCPTool。agent 通过浏览文件系统(ls + read)发现工具,只在需要时把那一个工具的类型拉进上下文。

文件系统上的工具树 servers/ ├── google-drive/ │ ├── getDocument.ts │ ├── listFiles.ts │ └── index.ts ├── salesforce/ │ ├── updateRecord.ts │ └── index.ts └── slack/ └── sendMessage.ts agent: ls ./servers/ 发现 server read 具体文件看接口(JIT 拉签名) 每个工具 = 一个 TS 文件 // getDocument.ts import { callMCPTool } from client interface Input { documentId: string } interface Resp { content: string } export async function getDocument( input: Input): Promise<Resp> { return callMCPTool( 'google_drive__get_document', input) } 包一层:MCP 协议调用 → 普通类型化函数 类型签名只在 import 这一行进上下文
这是「工具如何变成可 import 的代码」的落地——文件树既是组织方式(按 server 分目录),也是发现机制(agent 用 ls/read 探索),还是惰性加载的载体(不 import 就不进上下文)。MCP 的类型契约(Tools 原语)被包成了普通函数。

二、五个收益(两个是二手综述没提的)

① Progressive disclosure 渐进式披露 文件系统浏览 + search_tools detail level 参数(名/描述/全 schema) 按需选披露粒度 ② Context-efficient results 结果先 filter 再返回 10000 行 → 只看 5 行 聚合 / join / 抽字段 都在执行环境里做完 ③ Control flow 循环 / 条件 / 错误处理 代码而非 tool-call 链 省 time-to-first-token (条件交给代码,不等模型) ④ Privacy-preserving ★一手独有 PII 自动 tokenize email → [EMAIL_1] 真实数据 source→dest 不过模型 可定义确定性数据流安全规则 ⑤ State + skills ★一手独有 持久化 + 攒技能 中间结果写文件 → 跨操作恢复 工作代码存 ./skills/ + SKILL.md → agent 给自己攒高层能力工具箱 ④⑤ 是 Akshay 二手综述完全没提的两个维度——隐私 tokenize 把 Code Mode 推进合规场景,skills 让 agent 可自我进化
前三个收益(progressive disclosure / context-efficient results / control flow)是「省 token + 更强表达」的主线;后两个(privacy / state+skills)把 Code Mode 的价值从「效率」扩展到「安全」和「成长性」——这是二手综述的视野盲区。

三、隐私 tokenize:真实数据绕开模型

agent harness 在数据到达模型前自动把 PII 替换成占位符,真实数据从源系统直流目标系统,从不进入模型上下文。这既能防误 log,也能定义确定性的数据流边界。

模型上下文边界 Google Sheets alice@x.com +1-555-0100 Alice Chen MCP client tokenize 模型只看到: [EMAIL_1] [PHONE_1] [NAME_1] MCP client untokenize Salesforce alice@x.com +1-555-0100 Alice Chen 真实数据走这条绿色弧线——从不进入虚线框内的模型上下文 进边界前脱敏 出边界后还原
虚线框是模型能「看见」的范围。绿色弧线是真实 PII 的路径——它从 Sheets 直流 Salesforce,被 MCP client 在边界两侧 tokenize/untokenize,模型从头到尾只碰到占位符。这让 Code Mode 能进合规场景,也是定义「数据能从哪流到哪」的确定性安全规则的支点。

四、skills:agent 给自己攒工具箱

agent 把为某个任务写好的工作代码存成文件 + SKILL.md,之后任何执行都能 import 复用。久而久之,agent 为自己积攒一个高层能力工具箱——这正是它高效工作所需的脚手架。

t₁ agent 写代码 saveSheetAsCsv() 为某任务写好、跑通 t₂ 存到 ./skills/ save-sheet-as-csv.ts + SKILL.md → 结构化 Skill t₃ 之后任意执行 import { saveSheetAsCsv } 直接用,不用重写 第一次手写 → 冻结成 skill → 之后一行 import agent 越用越能干——把 Code Mode 和 Claude Skills 体系打通
state persistence(中间结果写文件、跨操作恢复)是基础;skills 是它的进化形态——agent 把代码本身持久化。加上 SKILL.md 就接入 Claude 的 Skill 体系,agent 的工作不再是一次性的,而是会沉淀、可复用、能进化。
不是免费的:权衡

一手原文诚实指出,代码执行把复杂度从「上下文窗口」转移到「运行时基础设施」——需要安全沙箱、资源限制、监控。这些是直接 tool call 能避免的运维开销和安全考量。token 节省的收益要和实现成本权衡:工具数量大的场景值,工具少的简单场景可能 overkill。

五、一句话

Tool definitions belong in code, not in context. 工具定义属于代码,不属于上下文。schema 从「清单项」降级成「函数签名」,只在 import 那一刻、只为那一个函数出现;数据在变量里从 A 流到 B,不回头看清单、不穿过模型。

「MCP vs CLI」是假命题——死的是「预载所有工具」这个做法,不是协议本身(2026-07 MCP 月下载已超 4 亿)。MCP 与 CLI 都活了下来,只是从「运行时本身」降格为「被运行时组合的两种原语」。