跳转到内容

Codex 的 MCP 集成方案

Codex 的 MCP 集成方案

学习目标

  • 理解 Codex 的 MCP 客户端聚合架构
  • 掌握 Codex 作为 MCP 服务器的实现方式
  • 分析 Codex 的传输层支持和会话恢复机制

前置知识

本章涉及 MCP 协议的通用原理,建议先阅读:

下文假设你已理解上述概念,直接聚焦 Codex 的具体实现。


项目实践

MCP 客户端架构

Codex 的 MCP 客户端分布在三个 crate:

  • codex-mcp:聚合层(连接管理、工具聚合)
  • rmcp-client:底层协议实现
  • codex-mcp-server:Codex 作为 MCP 服务器

McpConnectionManager

codex-mcp 中的 McpConnectionManager 是 MCP 客户端的管理中枢:

pub struct McpConnectionManager {
clients: HashMap<String, AsyncManagedClient>, // 按服务器名索引
}

启动流程

  1. new() 并行启动所有启用的 MCP 服务器(通过 JoinSet 收集结果)
  2. 每个服务器启动后发送 McpStartupCompleteEvent
  3. 启动期间返回缓存的 startup_snapshot 工具列表

工具聚合

  • list_all_tools():收集所有服务器的工具,执行模型可见名称归一化
  • 去重逻辑:同名工具通过截断至 64 字节并附加 SHA1 后缀来区分
  • codex-apps 服务器的 connector 元数据被剥离,防止不可信服务器伪装

传输层实现

rmcp-client 支持三种传输:

Stdio 传输

  • LocalStdioServerLauncher:本地子进程启动 MCP 服务器
  • ExecutorStdioServerLauncher:通过 ExecBackend API 在远程启动,stdin/stdout 通过 executor 转发

Streamable HTTP

  • 基于 SSE 的 HTTP 传输
  • 支持 Mcp-Session-Id 会话管理
  • OAuth 2.0 自动刷新:通过 AuthClient 包装请求

会话恢复

  • 遇到 SessionExpired404 时自动重建 transport
  • 使用 session_recovery_lock 防止并发恢复
  • 恢复后重新 initialize 并拉取工具列表

Codex 作为 MCP 服务器

mcp-server crate 将 Codex 自身暴露为 MCP 服务器:

暴露的工具

  • codex:启动新会话,参数包括 promptmodelsandboxapproval_policy
  • codex-reply:基于 thread_id 继续已有会话

通信方式:JSON-RPC over stdio,使用 rmcp 库处理协议帧。

事件流

  • Codex 内部事件(ExecApprovalRequestApplyPatchApprovalRequestTurnComplete
  • 通过自定义通知 codex/event 推送给 MCP 客户端
  • 实现方式:MessageProcessor 处理标准 MCP 方法,工具调用在独立 Tokio task 中运行

问题与规避

MCP 服务器启动失败

Codex 的对策:

  • 每个服务器独立启动,失败不影响其他服务器
  • AsyncManagedClient 内部使用 Shared<BoxFuture> 实现懒加载
  • 启动失败的服务器标记为不可用,后续工具调用跳过

工具名称冲突

Codex 的解决方案:

  • 截断至 64 字节(模型限制)
  • 附加 SHA1 哈希后缀保证唯一性
  • 提供 ToolFilter 白名单/黑名单控制

会话过期

Codex 的自动恢复:

  • HTTP 传输层检测 SessionExpired404
  • 自动重建 transport 并重连
  • 通过 session_recovery_lock 串行化恢复操作
  • 恢复后重新拉取工具列表(可能已变更)

设计取舍

为什么 Codex 同时作为 MCP 客户端和服务器?

这种双向集成实现了 Agent 生态的互操作性:

  • 作为客户端:Codex 可以调用外部工具(如数据库查询、API 调用)
  • 作为服务器:Claude Desktop、IDE 等可以调用 Codex 的能力
  • 这是 MCP 协议的核心理念——任何 Agent 既可以消费工具,也可以提供工具

代价是增加了架构复杂度,需要同时维护两套 MCP 相关代码。

为什么使用 rmcp 库而非自研协议?

Codex 选择使用官方的 rmcp Rust SDK 而非自研 MCP 协议实现。优势是:

  • 与 MCP 标准保持同步
  • 减少维护成本
  • 生态兼容性好

代价是对 rmcp 的依赖意味着必须跟随其版本升级,且某些定制化需求可能受限。


参考来源