编者摘要:Cloudflare Code Mode 提出一种重构 MCP 调用范式的新思路,颠覆当前主流 Agent 直接调用 MCP 工具的模式。传统方案依靠模型输出特殊标记与 JSON 来调用工具,受限于合成训练样本,模型在工具数量多、链路复杂时稳定性差,且多步骤调用会反复来回传递结果,大量消耗 Token。
Code Mode 的核心思路是:由 SDK 自动读取 MCP 的接口 Schema,转换成完整带注释的 TypeScript 类型定义,把 MCP RPC 能力包装成编程语言 API。大模型不再直接输出工具调用 JSON,而是编写 TypeScript 代码编排多步业务逻辑,代码在 Cloudflare V8 Isolate 沙箱内执行。
沙箱没有通用外网权限,仅通过平台 bindings 访问 MCP 后端,鉴权由上层调度器统一接管,AI 代码无法接触密钥,大幅降低安全风险。依托 Worker Loader API,Isolate 毫秒级启停,每次代码执行新建一次性隔离实例,无需容器,开销远低于容器沙箱。
本质上这套方案利用大模型在海量真实代码上学到的能力,替代薄弱的原生 function calling。MCP 保留其核心价值:统一的工具发现、连接、文档标准;只是把调用入口从模型工具调用切换为代码执行。该方案适合长链路、多工具串联的复杂智能体任务,目前开放本地调试,生产版处于封闭 Beta。
10个关键问题 Q&A
- Q:Code Mode 是什么?
A:Cloudflare 提出的 MCP 新范式,不直接调用 MCP 工具,而是把 MCP 转为 TS API,让 LLM 写代码调用 API。 - Q:传统 function calling 的短板在哪?
A:工具调用格式样本是人工合成,真实场景少见;工具一多容易出错;多轮调用反复往返,浪费 Token。 - Q:为什么 LLM 写代码比直接调用工具更强?
A:训练数据包含海量开源真实代码,模型对 TS 语法、函数调用逻辑掌握更好。 - Q:MCP 在 Code Mode 里还有意义吗?
A:有。MCP 提供统一工具发现、接口文档、连接规范,让 Agent 和 MCP 服务无需预先互相适配。 - Q:MCP 怎么转 TypeScript?
A:SDK 读取 MCP 服务 Schema,自动生成带注释 interface 与函数声明。 - Q:代码运行在什么环境?是 Docker 容器吗?
A:不是容器,Cloudflare V8 Isolate,毫秒级启动,用完销毁。 - Q:沙箱如何访问 MCP,能不能直接访问互联网?
A:沙箱默认阻断外网;通过 Worker bindings 访问 MCP,由上层代理转发请求。 - Q:密钥安全如何保障?
A:鉴权凭证保存在上层调度器,绑定是预授权客户端,AI 生成代码拿不到 API Key。 - Q:怎么接入 Code Mode?
A:用 Cloudflare Agents SDK,codemode 包装 system 和 tools,几乎不用改动原有业务逻辑。 - Q:当前可用环境?
A:本地 Wrangler+workerd 完整可用;Dynamic Worker Loader 生产环境封闭 Beta。
原文:Code Mode: the better way to use MCP| Cloudflare Blog,2025-09-26
结论先行:我们一直都在用错 MCP。 当前大多数智能体,都是直接把工具暴露给大模型。 Cloudflare 提出新思路:把 MCP 工具转换成 TypeScript API,让 LLM 编写代码调用这套 API。 效果非常显著:当工具以 TypeScript API 的形式提供,智能体可以驾驭数量更多、逻辑更复杂的工具。原因很简单:LLM 训练数据里有海量真实世界的 TypeScript 代码,但工具调用格式只有少量人工合成样本。 这套方案在串联多轮工具调用时优势最大。传统方式中,每一次工具返回结果都要送回大模型,再复制参数给下一次调用,浪费 Token、算力与时间。而 LLM 写代码时,可以一次性编排多步逻辑,只在最后读取最终返回结果。 一句话总结:大模型更擅长写代码调用 MCP,而非直接调用 MCP。
一、什么是 MCP(Model Context Protocol)
MCP 是一套标准化协议,用来给 AI 智能体接入外部工具,让智能体执行真实操作,而不只是对话。 换个角度理解,MCP 统一定义三件事:
-
对外暴露执行能力的 API -
附带大模型可读懂的接口文档 -
鉴权授权在协议外单独处理
2025 年 MCP 快速出圈,极大拓展 AI Agent 的能力边界。 MCP 服务端对外暴露的能力单元叫做工具(tools),本质是远程过程调用 RPC 函数:传入参数,返回结果。 现代大模型普遍支持函数调用(function calling):模型经过微调,会输出特定格式文本来发起工具调用;外层程序识别该格式、执行工具,再把结果回传给 LLM。
二、传统工具调用的底层原理
大模型输出是 Token 流,Token 可以代表词语、音节、标点等文本单元。 而工具调用依赖特殊标记 Token,这类 Token 没有对应的可读文本。模型经过训练,识别两个特殊标记:
<|tool_call|>后续内容是工具调用请求 <|end_tool_call|>工具调用请求结束
两个标记之间,模型输出 JSON,描述调用的工具名称与参数。
示例:查询美国奥斯汀天气
我将调用天气MCP服务,查询德克萨斯州奥斯汀的天气。
我将调用天气MCP服务,查询德克萨斯州奥斯汀的天气。
<|tool_call|>
{
"name": "get_current_weather",
"arguments": {"location": "Austin, TX, USA"}
}
<|end_tool_call|>
运行时框架识别到特殊标记后,暂停大模型生成,解析 JSON,调用对应的 MCP 服务,拿到结果,再用另一组标记把工具结果送回 LLM:
<|tool_result|>
{
"location": "Austin, TX, USA",
"temperature": 93,
"unit": "fahrenheit",
"conditions": "sunny"
}
<|end_tool_result|>
大模型读取工具返回结果,继续生成回答。不同模型的工具调用格式略有差异,但底层逻辑一致。
三、传统 MCP 工具调用存在什么问题
工具调用的特殊标记,现实世界几乎不存在。模型只能依靠人工合成数据集专门学习工具调用,稳定性不佳:
-
工具数量过多 / 接口过于复杂时,模型容易选错工具、传错参数 -
因此 MCP 开发者被迫简化接口,降低能力,适配大模型工具调用能力
但矛盾点在于:大模型写代码的能力极强,直接使用面向开发者的完整复杂 API 写代码,反而不容易出错。 为什么 MCP 工具接口必须刻意 “降智简化”?
原因:训练数据里海量真实代码,但几乎没有真实场景下的工具调用。工具调用样本只是厂商人工构造的合成数据;而代码是数百万开源项目的真实代码。 类比:就像让莎士比亚突击学一个月普通话,然后直接写普通话剧本,很难发挥真实水平。
四、MCP 依然有巨大价值:统一的接入标准
MCP 设计初衷是工具调用,但不一定要用传统工具调用模式。 MCP 服务暴露的工具本质就是带文档的 RPC 接口,完全可以把这些工具转换成编程语言 API。
疑问:既然原本就有原生 API,为什么还要绕 MCP 转一层? 核心价值:MCP 提供统一的 API 发现与接入规范。
-
Agent 开发者不需要预先了解某个 MCP 服务;MCP 服务开发者也不用提前适配特定 Agent,二者可以即插即用。传统 API 很难做到这一点,传统接口的连接方式、鉴权、文档规范各不相同。
这套统一标准在 Code Mode 场景下同样重要:
-
Agent 在沙箱内运行,只能访问被授权的工具,MCP 让智能体框架统一管控连接与鉴权,和 AI 生成的代码解耦 -
接口文档内置在协议中,不需要让 AI 上网搜索文档
五、Code Mode 如何工作
Cloudflare Agents SDK 已经扩展,支持这套新模式。 基于 ai-sdk的原有应用,只需要用 codemode包装 system prompt 和工具定义:
import { codemode } from "agents/codemode/ai";
const {system, tools} = codemode({
system: "You are a helpful assistant",
tools: {
// 工具定义
}
});
const stream = streamText({
model: openai("gpt-5"),
system,
tools,
messages: [{ role: "user", content: "Write a function that adds two numbers" }]
});
改造后,应用会让大模型生成 TypeScript 代码,代码内部调用包含 MCP 在内的工具。后续还会适配更多 AI 开发库。
1. MCP 自动转 TypeScript 类型定义
当以 Code Mode 连接 MCP 服务时,Agents SDK 会拉取 MCP 的 Schema,自动生成带注释的 TypeScript 接口定义。 示例:连接 gitmcp.io/cloudflare/agents,自动产出类型声明:
interface FetchAgentsDocumentationInput {
[k: string]: unknown;
}
interface FetchAgentsDocumentationOutput {
[key: string]: any;
}
interface SearchAgentsDocumentationInput {
/**
* 用于检索相关文档的查询词
*/
query: string;
}
interface SearchAgentsDocumentationOutput {
[key: string]: any;
}
interface SearchAgentsCodeInput {
/**
* 检索代码文件的查询词
*/
query: string;
/**
* 待获取页码,从1开始,每页返回30条结果
*/
page?: number;
}
interface SearchAgentsCodeOutput {
[key: string]: any;
}
interface FetchGenericUrlContentInput {
/**
* 需要拉取的文档/页面绝对URL
*/
url: string;
}
interface FetchGenericUrlContentOutput {
[key: string]: any;
}
declare const codemode: {
/**
* 从GitHub仓库cloudflare/agents读取完整文档文件。适合通用问题;询问该仓库相关问题优先调用。
*/
fetch_agents_documentation: (input: FetchAgentsDocumentationInput) => Promise<FetchAgentsDocumentationOutput>;
/**
* 在已拉取文档中进行语义检索,适合精细查询
*/
search_agents_documentation: (input: SearchAgentsDocumentationInput) => Promise<SearchAgentsDocumentationOutput>;
/**
* 使用GitHub搜索API,在cloudflare/agents仓库搜索代码(精确匹配),返回匹配文件供后续查询
*/
search_agents_code: (input: SearchAgentsCodeInput) => Promise<SearchAgentsCodeOutput>;
/**
* 通用工具,拉取任意绝对URL内容,遵守robots.txt规则,用于读取前文文档中引用的链接
*/
fetch_generic_url_content: (input: FetchGenericUrlContentInput) => Promise<FetchGenericUrlContentOutput>;
};
生成的 TypeScript API 会加载进 Agent 上下文。当前方案一次性加载全部接口;未来会支持动态浏览、按需检索接口,类似代码助手。
2. 在沙箱中执行代码
Agent 不再接收一堆 MCP 工具列表,只获得单个工具:执行一段 TypeScript 代码。 代码运行在安全沙箱内:
-
沙箱完全隔离外网,对外唯一访问入口,就是这些映射 MCP 的 TypeScript API -
API 底层通过 RPC 回调到 Agent 主循环,SDK 再分发请求到对应的 MCP 服务 -
沙箱脚本通过 console.log()返回结果;脚本执行结束,日志全部回传给 Agent
3. 动态 Worker 加载:不使用容器
运行任意代码的安全沙箱,Cloudflare 没有用容器,而是 V8 Isolate(隔离实例)。
-
Isolate 远比容器轻量,启动仅需几毫秒,内存占用仅数 MB -
每次 Agent 生成一段代码,就新建一个独立 Isolate,用完直接销毁,无需预热、复用池 -
开销极低,几乎等价直接 eval,同时具备安全隔离能力
为此 Cloudflare Workers 平台新增 Worker Loader API,支持按需动态加载 Worker 代码。
// 获取指定ID的Worker,不存在则执行回调加载代码
let worker = env.LOADER.get(id, async () => {
// Worker不存在时,回调获取代码
return {
compatibilityDate: "2025-06-01",
mainModule: "foo.js",
modules: {
"foo.js": "export default {\n fetch(req, env, ctx) { return new Response('Hello'); }\n}"
},
env: {
SOME_NUMBER: 123,
// 回环RPC绑定,访问父Worker导出的接口
SOME_RPC_BINDING: ctx.exports.MyBindingImpl({props})
},
// 网络请求代理,可完全阻断外网
globalOutbound: ctx.exports.OutboundProxy({props}),
};
});
// 获取入口并发起调用
let defaultEntrypoint = worker.getEntrypoint();
await defaultEntrypoint.fetch("http://example.com");
可以使用 Wrangler + workerd 在本地调试该 API;生产环境需要申请封闭 Beta。
六、Workers 作为沙箱的优势
- 轻量、低成本、一次性沙箱
Isolate 启动极快,为每一段代码新建销毁,无需实例池。Worker Loader API 定价尚未最终确定,但相比容器方案成本会显著更低。 - 默认隔离,通过绑定(bindings)受控访问资源
Code Mode 沙箱禁用全局 fetch()和网络连接。 传统方案一般默认开放网络,依靠鉴权密钥访问资源;Workers 的env对象提供绑定(bindings),直接访问私有资源,不需要通用网络请求。 Code Mode 中,沙箱通过绑定访问 MCP 服务。
优势:边界清晰,不是靠网络过滤 / 代理做访问控制;过滤规则容易出现边界模糊,而绑定是明确允许的 JS 接口,模型无需猜测哪些请求会被拦截。
- 杜绝 API Key 泄露
绑定本身就是预授权好的客户端,鉴权令牌保存在上层 Agent 调度器中,由调度器代为转发 MCP 请求。 AI 生成的代码无法读取密钥,解决 AI 代码泄露密钥的安全痛点。
七、试用方式
- 生产环境 Beta
填写表单申请封闭内测 Dynamic Worker Loader API - 本地体验
Wrangler + workerd 本地环境已经完整支持,查阅文档与 agents 仓库 codemode 示例

