Codex CLI / 04
MCP 深度集成:1,100+ PR 背后的设计决策
为什么这个问题值得关注
MCP (Model Context Protocol) 是 Agent 工具生态的标准协议。每个主流 Coding Agent 都支持 MCP,但支持深度差异很大:
- Claude Code:内置支持,TypeScript SDK 集成
- Pi:通过 pi-mcp-adapter 做 token 压缩适配
- DeepSeek Harness:作为 Cordis 插件接入
Codex CLI 的 MCP 支持走了一条独特的路径:Rust 原生实现,从第一天就在内核层面而非扩展层面集成。 GitHub 记录显示,从 2025 年 5 月(PR #787 引入 mcp-types crate)到 2026 年 8 月,共有 1,100+ 个 MCP 相关 PR 被合并。
这个投入量级说明 MCP 不是 Codex 的”附加功能”,而是核心工程重心之一。理解它的设计选择,能帮你判断 MCP 在 Agent 框架中应该被当作”工具插件”还是”基础设施”来对待。
架构:Rust 层的 MCP
Codex 的 MCP 实现分布在多个 Rust crate 中:
codex-mcp ← MCP 服务集成入口
├── rmcp-client ← MCP 客户端(调用外部 MCP server)
├── mcp-server ← MCP 服务端(暴露 Codex 自身工具)
└── mcp-types ← MCP 协议类型定义
为什么在 Rust 层而非 TypeScript 层
安全审查点。 MCP 工具调用是外部代码执行——来自第三方 MCP server 的响应可能包含恶意内容。把 MCP 客户端放在 Rust 层意味着:安全检查(tool approval、response 验证)和沙箱策略在同一层执行,不需要跨进程通信。
性能。 MCP 的 STDIO 传输需要频繁的 JSON 序列化/反序列化。Rust 的 serde 在这类操作上比 Node.js 的 JSON.parse/stringify 快 3-5 倍。对于高频工具调用的 Agent,这个差距会累积。
类型安全。 MCP 协议有复杂的消息格式(JSON-RPC 2.0 + 自定义扩展)。Rust 的类型系统在编译时就能捕获协议违反,不需要等到运行时。
双通道传输:STDIO + Streamable HTTP
Codex 支持两种 MCP server 连接方式:
STDIO 模式
MCP server 作为子进程启动,通过 stdin/stdout 通信。
[mcp.servers.github]
transport = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-github"]
env = { GITHUB_TOKEN = "${GITHUB_TOKEN}" }
适合:本地工具、需要访问本地文件系统的 server、开发调试。
Streamable HTTP 模式
MCP server 作为远程服务运行,通过 HTTP 通信。
[mcp.servers.remote-db]
transport = "streamable-http"
url = "https://mcp.example.com/db"
headers = { Authorization = "Bearer ${DB_TOKEN}" }
适合:远程服务、多用户共享的工具、需要独立部署和扩缩的场景。
选择逻辑
| 维度 | STDIO | Streamable HTTP |
|---|---|---|
| 延迟 | 低(本地 IPC) | 中(网络往返) |
| 部署 | 随 Codex 启动 | 独立部署 |
| 安全 | 继承 Codex 沙箱 | 需要独立认证 |
| 扩展性 | 单实例 | 可水平扩展 |
| 生命周期 | Codex 退出时终止 | 持续运行 |
Per-tool 审批机制
Codex 对 MCP 工具的审批不是全有全无的——你可以对每个 MCP server 甚至每个 tool 设置不同的审批模式:
[mcp.servers.github]
transport = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-github"]
# 这个 server 的所有工具默认需要审批
approval = "prompt"
# 但 read 类操作自动允许
enabled_tools = ["get_file_contents", "search_repositories"]
# 禁止执行这些工具
disabled_tools = ["delete_repository", "force_push"]
四种审批模式:
| 模式 | 行为 |
|---|---|
auto |
自动执行,不提示 |
prompt |
每次执行前提示用户 |
writes |
只在写操作时提示 |
approve |
需要显式预先批准 |
与 Claude Code 的 MCP 审批对比
Claude Code 的 MCP 工具审批是统一的——所有 MCP 工具调用走同一套权限检查逻辑(和内置工具一样的 allow/deny 规则)。
Codex 的 per-tool 审批更细粒度:你可以说”GitHub 的读操作自动允许,写操作需要审批,delete 操作直接禁止”。但代价是配置更复杂——每个 MCP server 都需要单独考虑审批策略。
与 Pi 的 MCP 方案对比
Pi 的 pi-mcp-adapter 关注的是不同的问题:token 压缩。它把 MCP 工具描述从 10k+ token 压缩到 ~200 token,解决的是上下文窗口经济学问题。
Codex 不做 token 压缩——它假设模型的上下文窗口够大(GPT-4o、o3 都有 128k+ 窗口)。Pi 的压缩方案在窗口有限的场景更有价值。
三者的关注点差异:
| 框架 | MCP 关注重点 |
|---|---|
| Codex | 安全(per-tool 审批)+ 性能(Rust 原生) |
| Claude Code | 一致性(MCP 工具和内置工具统一权限模型) |
| Pi | 经济性(token 压缩)+ 兼容性(多框架 Skill) |
安全硬化:Guardian 隔离
2026 年 8 月,Codex 合并了一系列安全相关 PR,其中最值得关注的是 Guardian review 与 executor MCP server 的隔离(PR #39962)。
这解决的问题是:当 Codex 有一个”审查者”角色(Guardian)负责检查 Agent 的操作是否安全时,Guardian 不应该能访问 Agent 正在使用的 MCP server——否则恶意 MCP server 可能通过审查者的上下文注入攻击。
┌──────────────┐ ┌──────────────┐
│ Executor │ │ Guardian │
│ 执行 Agent │ │ 审查 Agent │
├──────────────┤ ├──────────────┤
│ MCP Server A │ │ 无 MCP 访问 │
│ MCP Server B │ │ 只看执行记录 │
└──────────────┘ └──────────────┘
这是多租户安全模型的雏形:同一系统内不同角色有不同的工具访问边界。DSH 通过策略平面实现类似功能;Codex 通过进程级隔离实现。
同一时期合并的其他安全 PR:
- OAuth issuer binding:防止 MCP OAuth token 被重放到其他 server
- Bearer token over WebSocket:WebSocket 连接的认证加固
- Credential write hardening:凭据写入的额外保护
MCP 生态的量化观察
1,100+ PR 的分布可以反映 Codex 团队在 MCP 上的工程优先级:
- 2025.5 - 2025.10:基础建设期。mcp-types crate、STDIO 传输、基本工具调用
- 2025.10 - 2026.4:功能完善期。Streamable HTTP、per-tool 审批、allowlist/denylist
- 2026.4 - 2026.8:安全硬化期。OAuth、Guardian 隔离、credential protection
这个时间线说明 MCP 在 Codex 中经历了”能用 → 好用 → 安全”的三阶段演进。当前处于安全硬化阶段,暗示基础功能已经稳定。
实操:添加 MCP Server
在项目配置中添加一个 MCP server 的最小步骤:
# .codex/config.toml
[mcp.servers.filesystem]
transport = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "./"]
approval = "writes"
这声明了一个 filesystem MCP server,读操作自动允许,写操作需要审批。
验证是否生效:
codex mcp list # 列出已配置的 MCP servers
codex mcp test filesystem # 测试连接
什么时候 Codex 的 MCP 方案更优
- 你需要对不同 MCP server 设置不同的安全策略
- 你有高频工具调用的场景,需要 Rust 层面的解析性能
- 你需要 STDIO 和 HTTP 双通道支持(本地 + 远程混合部署)
- 你需要多角色安全隔离(Guardian + Executor 分离)
什么时候其他方案更优
- Claude Code:如果你希望 MCP 工具和内置工具有完全一致的权限体验
- Pi:如果你的上下文窗口有限,需要 token 压缩
- DSH:如果你需要可编程的工具路由逻辑(比如”根据任务类型自动选择 MCP server”)
小结
Codex 的 MCP 集成不是”支持 MCP”这么简单——它是一个从 Rust 层面原生实现、经过 1,100+ PR 打磨、正在向多租户安全模型演进的完整子系统。Per-tool 审批、双通道传输、Guardian 隔离——这些设计选择反映了一个判断:MCP 工具是 Agent 的主要攻击面之一,安全投入应该和功能投入匹配。
这个判断在企业环境(多 MCP server、多角色、合规要求)下尤其成立。对于个人开发者的简单场景,这些安全机制可能是过度工程——但这恰好说明了 Codex 的目标用户群:不是”快速跑个 demo”的场景,而是”需要细粒度安全控制”的场景。