Codex Bridge MCP
by luojiateng
README.md
# Codex Bridge MCP
> 让 Claude 或 Codex 负责决策,用一套 MCP 持续、可控地调度 Codex、Claude Code 与支持 ACP 的 Vibe Coding CLI。
Codex Bridge MCP 是连接 **任务编排者**(Claude Code、Codex 或其他 MCP 客户端)与 **编码执行引擎** 的本地会话层。它默认原生连接 Codex App Server,也可以驱动 Claude Agent SDK,以及通过 Agent Client Protocol(ACP)接入的 Kimi 等 Vibe Coding CLI。它不是另一个模型,也不是把一条提示词转发给某个 CLI 的脚本;它用统一的 MCP 工具为一项开发任务保留稳定的执行线程、运行状态、审批记录和审阅闭环。
当需求需要多轮补充、代码修改需要审批、任务可能中断、结果还需要审查时,编排者不必为 Codex、Claude Code、Kimi 等工具分别维护一套调用和恢复逻辑,也不必把执行引擎的一句“完成”当作验收结果。
## 它为谁而做
适合已经使用一种或多种 AI 编码工具,并希望把它们接入真实工程任务的开发者和团队:
- Claude 或 Codex 作为任务编排者,负责理解需求、拆解问题、作出判断和审查结果;
- Codex、Claude Code、Kimi 或其他支持 ACP 的 Vibe Coding 工具作为执行引擎,负责进入仓库、修改文件、执行命令和完成验证;
- 你需要用同一组 MCP 工具选择执行引擎,并让任务状态、审批、恢复和 diff 审阅不随工具切换而断掉。
Claude 是默认、最清晰的协作入口;如果你已经使用 Codex 或其他支持 MCP 的客户端作为上层编排者,也可以通过同一组工具调度一个独立的编码执行引擎。
## 解决的问题
一次性调用一个编码工具很容易;难的是让一项复杂任务可靠地走到验收。
| 真实开发中的问题 | Codex Bridge MCP 的做法 |
| --- | --- |
| 需求补充几轮后,执行上下文散失或串入别的会话 | 一个编排会话永久绑定一个 Task 和执行线程,后续要求只进入自己的执行链 |
| Codex、Claude Code、Kimi 等工具的调用协议各不相同 | Engine Adapter 把线程、turn、审批、用量和完成事件归一化;编排者始终调用同一组 MCP 工具 |
| 同一项目反复启动执行环境 | 一个 `projectRoot` 为每个执行引擎复用一个活跃 Runtime Host |
| 高风险命令不该被自动放行 | 执行引擎的审批请求由任务编排者明确批准或拒绝,Bridge 不会自动批准 |
| Claude、Bridge 或电脑重启后任务失联 | 保存任务、线程、事件和队列状态;优先重连,必要时恢复已知线程 |
| 任务完成却无法判断是否真的符合要求 | 编排者获取真实 diff,继续 review 或下发下一轮要求 |
| 日志、事件与 patch 淹没模型上下文 | 默认返回摘要和分页信息,需要时才显式展开原始内容 |
## 一项任务如何流转
```text
你提出目标与约束
│
▼
Claude / Codex / 其他 MCP 客户端 澄清需求、拆解任务、决定审批、审查结果
│ stdio MCP(兼容入口)
▼
Bridge Adapter 自动连接或拉起共享 Core,不持有任务状态
│ 本地 Streamable HTTP MCP
▼
Bridge Core 唯一持有任务、线程、Runtime、审批与恢复状态
│
▼
Engine Adapter 归一化不同执行引擎的协议与能力
├─ Codex App Server(原生 WebSocket JSON-RPC,可见 TUI)
└─ Bridge Engine Host(WebSocket JSON-RPC 边车)
├─ Claude Agent SDK
└─ ACP stdio → Kimi / 其他支持 ACP 的 Vibe Coding CLI
```
编排者不需要理解每个执行引擎的私有协议。它只在 `task_open` 时选择 `engine`,后续仍然使用 `task_send`、`approval_decide`、`task_status`、`task_diff` 等相同工具。
一次任务通常只有下面几步:
1. 编排者用 `task_open` 打开项目任务,传入稳定的 `orchestrator.kind + orchestrator.sessionId`,并用可选的 `engine` 选择 `codex`、`claude` 或已注册的 ACP 引擎(默认 `codex`)。同一编排会话始终复用该 ID,Bridge 会把它永久绑定到一个 Task 和执行线程;另一个 Claude/Codex/Cursor 会话不能静默接入。相同项目里的独立工作或执行引擎切换使用新的编排会话 ID 和 `mode: "new"`。
2. 编排者用 `task_send` 发送补充要求。完整 Task 标题、requirements 和验收条件只在线程创建或恢复时注入;普通 turn 只携带本轮增量 instruction 和检查策略。Bridge 会保持等待直到审批、完成、失败或中断。Codex 引擎还会确认同一线程的可见 TUI;无可见 TUI 的 Claude/ACP 引擎由 Engine Host 无窗口执行。客户端支持 MCP progress 时,等待期间 Bridge 会发送轻量进度心跳;即使 MCP 调用被取消,最终注意力事件也会先持久化,重连后由 `task_open`、`task_send` 或 `task_status` 重放。
3. 执行引擎需要授权时,`task_send` 会直接返回审批注意力事件;编排者通过 `approval_decide` 作出决定,并继续等待同一 turn 的下一个注意力事件。
4. 执行引擎完成一轮后,编排者用 `task_diff` 审查真实改动;不满足验收条件就继续发送下一轮要求。`task_status` 和 `task_events` 只用于诊断与审计,不承担正常通知职责。
5. 长任务接近上下文限制时,如果当前引擎支持上下文压缩,编排者可以调用 `task_compact`;目前该能力仅由 Codex 引擎提供。
## 核心价值
### 持续执行,而不是一次转发
`orchestrator.kind + orchestrator.sessionId`、`taskId` 与 `codexThreadId` 形成一一绑定,并持久化在 SQLite。这里的 `sessionId` 优先使用 Claude、Codex 或 Cursor 自己提供的稳定对话身份;如果客户端没有暴露该值,就在一次对话第一次 `task_open` 时生成一个,并在该对话内始终复用。临时 stdio/HTTP MCP transport session 会在重连时变化,Bridge 明确不拿它做任务身份。当该 Task 仍是项目当前活跃会话时,同一编排会话再次 `task_open` 即使标题或需求文本变化,也只会返回原 Task 和 Thread。若另一个会话已用 `mode:new` 显式换代,旧会话的绑定仍保留,但必须用返回的原 `taskId` 调用 `task_recover` 才会显式切回。不同编排会话若碰到已经绑定的活跃 Task 会在 Runtime/TUI 副作用前拒绝;只有新的编排会话显式传入 `mode: "new"` 才创建隔离线程。旧客户端无法提供稳定编排身份时,仍可用 `expectedTaskId` 精确复用。
### 一个 MCP,多个编排者和执行引擎
编排者与执行引擎是两个独立维度。例如:
```text
Claude Code ─┐ ┌→ Codex App Server
Codex ─┼→ Codex Bridge MCP ─────┼→ Claude Agent SDK
其他 MCP 客户端 ┘ └→ Kimi / 其他 ACP CLI
```
上游 Claude、Codex 或其他 MCP 客户端是任务编排者:它调用 `task_open`、`task_send`、`task_status` 和 `task_diff`;Bridge 根据 `engine` 启动或复用一个**独立的**执行 Runtime 完成实际工作。即使选择与编排者同类的引擎,也不是让同一个会话递归调用自己,因此仍然保留清晰的任务边界、审批链、恢复状态和 diff 审阅链。
### 审批可控,责任清晰
Bridge 只保存和转发审批请求,不替任务编排者或用户作决定。命令执行、文件修改等需要授权的操作,都要经过明确的 `approve` 或 `deny`。审批、完成、失败和中断都会保存为带单调 revision 的 turn 注意力状态;编排者完成对应动作后才写入 ACK。未确认事件会在调用取消或客户端重连后重放,避免只写入后台日志却没有交付给编排者。
### 中断可恢复,而不是静默重跑
Bridge 会记录 Runtime、线程、turn 和队列状态。Core 重启后通过所选引擎的线程状态接口,将本地活跃 turn 与执行引擎实际状态对账;无法确认已完成的工作会被标记为中断,避免把可能已经生效的修改自动再执行一次。旧 Runtime 连接上的待审批会标记为 `orphaned`,不会被自动批准、自动拒绝或错误地发送到替代连接。
### 一个 Core,而不是每个客户端一套运行时
Claude、Codex 或其他 MCP 客户端都连接到同一个本地 Bridge Core。MCP 客户端连接只是临时的协议会话;SQLite、Runtime WebSocket、任务队列和审批请求由 Core 长期持有。关闭或重连一个 MCP 客户端不会触发全库恢复,也不会为同一 Runtime 再创建一条执行引擎连接。
### 结果可审阅,而不是相信“已完成”
执行引擎的完成事件只是提示编排者进入审查。Bridge 提供工作区 diff、变更文件和可选 patch,让验收基于真实代码,而不是自然语言声明。
### 上下文更干净
状态、事件和 diff 默认返回可用于继续决策的短摘要:
- 审批请求默认只给出可决策信息;需要原文时再请求完整 payload;
- 事件默认按页返回,并提供游标继续读取;
- diff 默认给出短统计与分页文件列表;只有行级审阅时才请求完整 patch。
这让编排者与执行引擎把上下文留给任务本身,而不是重复的日志和历史数据。
## 统一调度 Vibe Coding 执行引擎(实验性)
Bridge 的任务/审批/恢复状态机是引擎无关的。除默认的 Codex App Server 外,同一套 MCP 工具可以驱动其他执行引擎——`task_open` 传入可选的 `engine` 字段即可(默认 `codex`):
| 引擎 | `engine` 值 | 接入方式 | 能力差异 |
| --- | --- | --- | --- |
| Codex | `codex`(默认) | 原生 `codex app-server` | 完整:可见 TUI、compact |
| Claude Code | `claude` | Bridge Engine Host 边车 + Claude Agent SDK | 无可见 TUI、无 compact;审批经 `canUseTool` 完整走 `approval_decide` |
| Kimi / 其他支持 ACP 的 Vibe Coding CLI | 配置的 id | Bridge Engine Host 边车 + ACP(stdio) | 无可见 TUI、无 compact;`session/load` 支持与否决定跨重启恢复能力 |
例如,选择已注册的 Kimi 引擎时,`task_open` 的关键参数如下;后续工具调用不需要再区分引擎协议:
```json
{
"projectRoot": "C:\\absolute\\path\\to\\project",
"title": "实现并验证登录功能",
"requirements": ["保持现有 API 兼容"],
"mode": "new",
"engine": "kimi"
}
```
ACP 引擎通过环境变量注册(分号分隔多个,命令按空白切分):
```powershell
$env:CODEX_BRIDGE_ACP_ENGINES = "kimi=kimi acp;gemini=gemini --experimental-acp"
```
说明:
- 只有实现 ACP 的 CLI/Agent 才能通过该入口接入;配置一个普通、非 ACP 命令不会自动获得 Bridge 能力;
- 配置格式为 `id=command arg1 arg2;id2=command2 arg1`,当前按空白切分参数,不解析 shell 引号;`codex` 与 `claude` 是保留的内置 id;
- 非 Codex 引擎由 Runtime Host Manager 启动一个 `node engineHostMain.js` 边车进程(与 `codex app-server` 走完全相同的端口分配、健康检查、DEAD 重建与恢复流程),因此需要先 `npm run build`;
- 一个 `projectRoot` 每个引擎各有一个 Runtime Host;项目的活跃会话仍然全局唯一,跨引擎切换需 `mode: "new"`;
- 无可见 TUI 的引擎自动无窗口执行,不受 `CODEX_BRIDGE_CODEX_TUI_MODE` 影响;
- Claude 引擎复用本机已登录的 Claude 凭据(Agent SDK 自带运行时,不依赖已安装的 `claude` CLI);Kimi 引擎要求已完成 `kimi login`;
- Task 和 Runtime 会持久化其 `engine`,`task_status` 与 `task_list` 也会返回该字段。为兼容既有 MCP schema,响应中的 `codexThreadId` 当前仍作为通用的执行线程/会话 ID 使用。
## 产品边界
Codex Bridge MCP 的职责是可靠地连接任务编排者与编码执行引擎,不替代任何一方:
- **不是新的模型**:不会替任务编排者规划,也不会替所选执行引擎编写实现;
- **不是云端代理**:Bridge 本身运行在本机,不增加额外的云端中转;
- **不会自动批准操作**:审批权始终属于任务编排者和用户;
- **不会把任意 CLI 自动变成执行引擎**:除内置 Codex 和 Claude 外,CLI 必须提供 Bridge 当前支持的 ACP 接口;
- **不会用 TUI 传递任务**:正常任务通过执行引擎协议进入线程。可见 TUI 仅由 Codex 引擎提供,用于观察或人工交互。
当前 Runtime Host 与可见 Codex TUI 的启动流程主要面向 Windows + PowerShell 验证。
## 快速开始
### 前置条件
- Windows 与 PowerShell;
- Node.js `>= 20.11.0`;
- 支持 stdio MCP 的客户端,例如 Claude Code 或 Codex;也可以直接连接 Streamable HTTP MCP。
- 至少准备一个执行引擎:支持 `codex app-server` 且已认证的 Codex CLI、本机已认证的 Claude 凭据,或一个已安装并登录且支持 ACP 的 Vibe Coding CLI。
### 安装与构建
```powershell
git clone https://github.com/luojiateng/codex-bridge-mcp.git
cd codex-bridge-mcp
npm install
npm run build
```
构建完成后,`dist/index.js` 是稳定的 stdio MCP 入口。它会自动连接或拉起一个只监听 `127.0.0.1` 的共享 Bridge Core,不需要另开终端管理 Core。运行脚本生成配置片段:
```powershell
.\scripts\install-mcp.ps1
```
Codex 的配置形态如下:
```toml
[mcp_servers.codex_bridge]
command = "node"
args = ["C:\\absolute\\path\\codex-bridge-mcp\\dist\\index.js"]
cwd = "C:\\absolute\\path\\codex-bridge-mcp"
startup_timeout_sec = 20
tool_timeout_sec = 600
```
Claude Code 使用同一个 `node dist/index.js` stdio 命令即可。多个 MCP 客户端只会创建各自的轻量 Adapter;所有 Adapter 都连接同一个 Core,因此客户端退出不会关闭正在执行的 turn,也不会重新执行全库恢复。
每次 `npm run build` 都会生成新的 Bridge build ID。stdio Adapter 发现端口上仍是旧 build 的 Core 时会明确报告 PID 和版本不兼容,不会静默复用旧代码或自动终止正在运行的任务;确认没有活跃任务后再重启该 Core。进度心跳默认每 15 秒发送一次,可用 `CODEX_BRIDGE_ATTENTION_HEARTBEAT_MS` 调整。
对 Codex 引擎,可见 TUI 默认采用 `CODEX_BRIDGE_CODEX_TUI_AUTO_RELAUNCH=active-turn`:正在执行或等待审批时,窗口意外退出会按 `0s / 2s / 5s` 在原会话上最多重拉 3 次;空闲时不主动弹窗,由下一次 `task_send` 惰性恢复。连续失败会打开 60 秒熔断,带原稳定编排身份的 `task_open(mode=reuse)`(旧客户端则加 `expectedTaskId`)可执行一次明确的人工重试并重置计数。也可以设为 `active-session`(活跃项目会话即主动恢复)或 `off`(完全关闭自动恢复,窗口退出后必须显式恢复已知 Task)。`task_status.codexTui` 会返回当前 PID、状态、重试次数、下次重试时间和最近错误。
需要调试或让支持 Streamable HTTP 的客户端直接连接时,可以显式启动 Core:
```powershell
npm start
```
默认地址是 `http://127.0.0.1:43110/mcp`,本地令牌保存在 `data/mcp-token`。这是可选的直连方式;普通 stdio 安装不需要手工读取或配置令牌。
## Core 生命周期与升级
Bridge Core 默认采用**按需启动**,不是 Windows 开机自启服务:第一次由 MCP 客户端建立连接时,stdio Adapter 会在本机没有可用 Core 的情况下拉起共享 Bridge Core;任务需要执行环境时,再由 Core 的 Runtime Host Manager 为对应项目和引擎启动 `codex app-server` 或 Bridge Engine Host。关闭单个客户端不会停止 Core,也不会中断已经提交的 turn。日常使用不需要每次手工执行 `npm start`;该命令主要用于前台诊断。
每次构建都会生成新的 Bridge build ID。Adapter 发现 43110 上运行的是旧构建时,会先通过本地 Bearer Token 请求安全升级:Core 检查运行中的 turn、队列命令、审批、Project Session 创建/恢复和 Runtime 迁移状态;全部为空时,旧 Core 自动进入 `DRAINING`、关闭连接并退出,Adapter 随即拉起新 Core,再完成本次 MCP 连接。这个过程不会重建 Task 或执行线程,也不需要手工查找和停止 PID。
如果仍有活跃操作,Core 会返回具体 blocker,并保持旧 Core 继续运行,不会为了升级中断任务;只要 Bridge protocol 兼容,本次 `/mcp` 仍会连接旧 Core,让当前任务继续使用。操作结束后再次执行 `/mcp` 即可自动切换到新构建。健康信息仍可用于诊断:
```powershell
$health = Invoke-RestMethod http://127.0.0.1:43110/healthz
$health
```
若安全升级被阻止,错误中会列出 `activeTurns`、`runningCommands`、`queuedCommands`、`activeApprovals`、`transitionalProjectSessions` 或 `transitionalRuntimes` 中的非零项。若需要查看启动阶段的直接错误,再在项目目录运行 `npm start` 进行前台诊断。
> 不要在任务执行中或存在待审批操作时直接停止 Core。Bridge 会持久化可恢复状态,但不会假装未确认的外部操作一定没有发生。
## 常用能力
| 你想做什么 | 编排者使用的能力 |
| --- | --- |
| 开始或继续当前编排会话 | `task_open`(传稳定的 `orchestrator.kind + sessionId`) |
| 为新任务选择执行引擎 | `task_open` 的 `engine`:`codex`、`claude` 或已注册的 ACP engine id |
| 旧客户端精确恢复已知任务 | `task_open`(`mode: "reuse"` + `expectedTaskId`) |
| 明确开启隔离的新线程 | 新编排会话身份 + `task_open(mode: "new")` |
| 在原任务上继续补充要求 | `task_send` |
| MCP 调用取消或重连后继续等待 | `task_await`;未 ACK 的结果也会由 `task_open` / `task_send` 重放 |
| 诊断进度、队列和历史事件 | `task_status`、`task_events` |
| 审批或拒绝执行引擎操作 | `approval_decide` |
| 审查真实代码改动 | `task_diff` |
| 压缩长任务上下文 | `task_compact`(仅当前引擎声明支持时;目前为 Codex) |
| 重连或找回任务 | `task_recover`、`task_list` |
完整工具 schema 请见 [`src/mcp/schemas.ts`](src/mcp/schemas.ts)。产品约束、阶段计划和验收矩阵请见 [`docs/phase-development.md`](docs/phase-development.md)。
## 本地数据与隐私
Bridge 在本机保存任务、线程、语义事件、审批、队列和上下文快照,以实现恢复与审阅。默认数据目录位于 Bridge 安装目录下的 `data/`,其中可能包含任务内容、命令、审批原因和 diff 信息;`data/mcp-token` 是本地 HTTP 访问令牌。
这些本地运行数据、日志和 `.env` 已被项目 `.gitignore` 排除。请像管理本地开发日志一样管理它们,并不要把真实凭据写入任务说明、环境示例或仓库文件。
执行引擎的逐 token / delta 输出不会写入 SQLite 事件表;Bridge 只持久化审批、turn 完成/中断、上下文阈值和错误等可恢复的语义事实,从源头减少编排者读取噪音历史时的 Token 消耗。
## 开发验证
```powershell
npm run typecheck
npm run build
npm run check:forbidden
npm run smoke:protocol
npm run smoke:context
npm run smoke:queue
npm run smoke:recovery
npm run smoke:runtime-interruption
npm run smoke:project-session
npm run smoke:attention
npm run smoke:hosted-engine
npm run smoke:diff
npm run smoke:mcp
```
真实端到端验证按执行引擎分别运行:
```powershell
npm run e2e:real # Codex App Server
npx tsx scripts/e2e-claude-engine.ts # Claude Agent SDK
npx tsx scripts/probe-acp-kimi.ts # Kimi ACP
```
这些命令会启动或复用真实的本地执行 Runtime,并可能消耗对应模型额度,因此只应在已完成认证且允许启动相关引擎的环境中执行。
---
**Codex Bridge MCP 不只是让 Claude 或 Codex 调用一次编码工具,而是让编排者通过一套 MCP 在 Codex、Claude Code 与支持 ACP 的 Vibe Coding CLI 之间选择执行引擎,并可靠地把一项开发任务从目标推进到验收。**
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues