Skip to main content
Glama
4714407
by 4714407
README.md
# Codex app-server MCP 桥接

> 想直接接入并开始使用?请先看 [使用指南](USAGE.md)。

[English documentation](README.en.md)

安全问题请阅读 [安全策略](SECURITY.md) 并私下报告;参与贡献前请阅读 [贡献指南](CONTRIBUTING.md)。版本变更记录见 [CHANGELOG.md](CHANGELOG.md)。

本项目让 Claude Code 通过本地 stdio MCP 调用独立的 Codex app-server 会话,默认适用于提问、代码分析和只读审查;用户显式启用 workspace-write 后,也可在任务工作区内修改代码。它不会连接或继承当前 Codex 桌面聊天上下文;没有 `threadId` 时创建新会话,提供 `threadId` 时恢复该会话。

`Claude Code → MCP stdio → 本桥接程序 → Codex app-server stdio → 独立 Codex thread`

## 兼容性、安装与登录

最低 Node.js 版本为 20。已在 Windows 上核实 Node.js `v24.14.1`、npm `11.11.0`、Codex CLI `0.154.0`,并以该 Codex 版本生成协议定义核对字段。实现使用 Node.js 的跨平台 `spawn(..., { shell: false })`;macOS 和 Linux 尚未实际验证,不对此作出已验证声明。

```powershell
$mcpDir = '<codex-app-server-mcp 所在目录>'
Set-Location $mcpDir
npm.cmd install
codex --version
codex login
node .\server.mjs
```

桥接优先使用 `CODEX_EXECUTABLE`;未设置时从 `PATH` 查找 `codex`(Windows 也查找 `.exe`、`.cmd` 和 `.bat`)。找不到时工具返回明确配置说明。桥接不会读取、复制、打印或硬编码令牌、API Key 或 Codex 全局配置。

Windows PowerShell:

```powershell
$env:CODEX_EXECUTABLE = 'C:\Program Files\OpenAI\Codex\bin\codex.exe'
node D:\path\to\codex-app-server-mcp\server.mjs
```

macOS / Linux:

```bash
export CODEX_EXECUTABLE="$(command -v codex)" # 可省略,让程序从 PATH 查找
node /path/to/codex-app-server-mcp/server.mjs
```

未登录时,请在普通终端执行 `codex login` 后重启桥接。若本机 Codex 协议不兼容,初始化或对应 JSON-RPC 请求会以方法名和服务端错误明确失败,不会静默降级。

## MCP 工具

`codex_start({ prompt, cwd, threadId?, model? })` 按启动时的沙箱配置启动任务。`prompt` 必须非空;`cwd` 必须是存在的绝对目录。它立即返回 `jobId`、`threadId` 和已获得时的 `turnId`。同一桥接进程只允许一个活动任务,第二个调用会收到 `busy`;恢复既有 thread 时 cwd 必须与该 thread 初始 cwd 相同。

`codex_status({ jobId, cursor?, waitMs? })` 返回任务状态 `starting`、`running`、`waiting_for_input`、`completed`、`failed` 或 `cancelled`,以及已收到的助手回复、错误、进度和关联 ID。传入上次结果的 `outputCursor` 作为 `cursor` 时,`assistantReply` 只包含增量;`waitMs` 支持最多 30 秒的长轮询。启动结果和状态均包含 `sandboxMode`,工具描述也显示当前模式。最多保留 100 个任务,每项回复最多 256 KiB,截断会标为 `outputTruncated: true`。

`codex_cancel({ jobId })` 使用 app-server `turn/interrupt` 请求中断。返回 `requested` 仅表示已发出请求;只有收到匹配 `turn/completed` 的 `interrupted` 才确认 `cancelled`。重复取消和已结束任务有稳定结果。

```text
codex_start({"prompt":"只回复 CODEX_OK,不读取或修改任何文件。","cwd":"D:\\project"})
codex_status({"jobId":"..."})
codex_cancel({"jobId":"..."})
```

`codex_models({ cursor?, limit? })` 从当前 Codex app-server 实时读取可用模型。返回模型 ID、显示名称、描述、默认推理强度、支持的推理强度、可用性提示以及 `nextCursor`;Claude 可先调用此工具展示列表,再将用户选中的 `model` 传给下一次 `codex_start`。

`codex_steer({ jobId, prompt })` 可向运行中的普通 turn 补充指令;`codex_review({ threadId, target, delivery? })` 启动原生审查;`codex_compact({ threadId })` 异步压缩长会话。Codex 需要澄清时,使用 `codex_pending_input({ jobId })` 取得问题与 `inputId`,再由 `codex_answer_input({ inputId, answers })` 明确回答;该流程不能批准命令或文件变更。`codex_doctor()` 显示连接、可执行文件、沙箱、目录白名单和可选任务索引配置。

设置 `CODEX_STATE_PATH` 后,桥接将以原子写入的本地 JSON 索引保留不含 prompt/回复/凭据的任务元数据;重启时已运行任务标为 `unknown`,不会自动重试,可使用保存的 `threadId` 手动恢复。

## 权限、超时和关闭

未设置 `CODEX_SANDBOX_MODE` 时使用 `read-only`。用户可显式设置为 `workspace-write`,其他值(包括空字符串和拼写错误)会导致启动失败。可写模式必须同时设置 `CODEX_ALLOWED_ROOTS`(分号分隔的目录列表或 JSON 字符串数组),任务 `cwd` 必须位于白名单内;未设置白名单时可写任务会拒绝启动。新建与恢复 thread 都明确设定当前沙箱和 `approvalPolicy: "never"`;每个 turn 再指定相应策略:只读为 `{ type: "readOnly", networkAccess: false }`;可写为 `{ type: "workspaceWrite", writableRoots: [cwd], networkAccess: false }`。`never` 代表不发起交互审批,不代表自动批准。服务端提出的命令、文件改动和权限审批一律拒绝;用户输入会进入等待状态,须通过 `codex_pending_input` 和 `codex_answer_input` 明确回答,未知服务端请求收到 JSON-RPC `-32601`,不会悬挂。工作区内写入在 workspace-write 下由沙箱直接允许,无需自动批准请求;超出沙箱的请求仍被拒绝。工具不接受改变沙箱或审批策略的参数,也不会使用危险绕过选项。

初始化超时为 20 秒,普通 RPC 超时为 30 秒。Codex 子进程退出、初始化失败或 JSON-RPC 失败会让活动任务失败,绝不误报成功。stdin 关闭、SIGINT 或 SIGTERM 时只关闭本桥接启动的 app-server,并清理计时器和待处理请求。

## 注册 Claude Code

已按当前 Claude Code 文档核对:stdio 选项和 `--scope` 必须放在服务名前,`--` 后才是启动命令。请自行执行:

```powershell
$mcpDir = '<codex-app-server-mcp 所在目录>'
$nodeExe = (Get-Command node.exe).Source
claude mcp add --transport stdio --scope user codex-agent -- "$nodeExe" (Join-Path $mcpDir 'server.mjs')
claude mcp get codex-agent
```

卸载命令:

```powershell
claude mcp remove codex-agent --scope user
```

## 测试与分发

```powershell
npm.cmd test
npm.cmd run test:real
npm.cmd pack --dry-run
npm.cmd pack
```

`npm test` 运行 JSONL 分块、启动响应前事件、忙状态、取消确认、子进程退出,以及使用官方 MCP 客户端 SDK 从外部进程启动服务的初始化、`tools/list`、不存在 cwd、未知 job 检查。`test:real` 额外验证真实 Codex 简短答复与 `threadId` 上下文恢复;它需要网络、有效登录和可用额度。测试只使用项目内 `test-tmp`,不会访问业务项目。模拟不会替代真实端到端成功。

npm 的 `files` 白名单仅包含运行必需的 `server.mjs`、`lib/`、README 和 LICENSE,排除测试、测试临时目录、日志、凭据、本地配置和会话数据。`npm pack` 仅在本地生成 tarball,不会发布到 npm。

## 两种 Codex 连接模式

MCP 服务应由 Claude Code、Cursor 等 MCP 客户端按其 `command`、`args` 和 `env` 配置自动启动;无需手动运行桥接进程或使用平台专属启动脚本。首次仍需在项目目录执行一次 `npm.cmd install`(或 `npm install`)。

两种模式向 Claude Code 暴露相同的 `codex_start`、`codex_status`、`codex_cancel`、`codex_models`、`codex_steer`、`codex_review`、`codex_compact`、`codex_pending_input`、`codex_answer_input` 和 `codex_doctor` 工具。每次启动只选择一种模式:设置 `CODEX_APP_SERVER_URL` 即为远程模式;未设置时为本地模式。

### 本地模式

本地模式由桥接程序以 `spawn(codex, ['app-server', '--listen', 'stdio://'])` 启动并管理子进程。`cwd` 是桥接机器上的存在目录,必须是绝对路径。桥接关闭时只停止它自己启动的 app-server。

Windows PowerShell:

```powershell
Remove-Item Env:CODEX_APP_SERVER_URL -ErrorAction Ignore
$env:CODEX_EXECUTABLE = 'C:\Program Files\OpenAI\Codex\bin\codex.exe' # 或让程序从 PATH 查找
node D:\path\to\codex-app-server-mcp\server.mjs
```

macOS / Linux:

```bash
unset CODEX_APP_SERVER_URL
export CODEX_EXECUTABLE="$(command -v codex)" # 可省略
node /path/to/codex-app-server-mcp/server.mjs
```

### 远程模式

远程模式不会启动、重启或终止任何 Codex 进程;它只连接既有 app-server。`cwd` 是远程 Codex 执行环境中的绝对路径,桥接不会在本机检查它是否存在,远程 app-server 会验证它。

配置 `CODEX_APP_SERVER_URL`。跨机器连接必须使用 `wss://`;`ws://` 仅接受 `localhost`、`127.0.0.1` 或 `::1`,用于同机服务或 SSH 隧道。URL 不得内嵌用户名、密码或 Token。

Bearer Token 可任选其一提供:`CODEX_REMOTE_BEARER_TOKEN`,或 `CODEX_REMOTE_TOKEN_FILE` 指向只含 Token 的秘密文件。Token 只用于 WebSocket 握手的 `Authorization: Bearer …` 请求头,不会写入日志、任务状态或 README 示例。优先使用秘密文件。

Windows PowerShell(TLS 反向代理后的远程服务):

```powershell
$env:CODEX_APP_SERVER_URL = 'wss://codex.example.internal/app-server'
$env:CODEX_REMOTE_TOKEN_FILE = 'C:\secure\codex-app-server.token'
Remove-Item Env:CODEX_EXECUTABLE -ErrorAction Ignore
node D:\path\to\codex-app-server-mcp\server.mjs
```

macOS / Linux(TLS 反向代理后的远程服务):

```bash
export CODEX_APP_SERVER_URL='wss://codex.example.internal/app-server'
export CODEX_REMOTE_TOKEN_FILE="$HOME/.config/codex-app-server.token"
node /path/to/codex-app-server-mcp/server.mjs
```

使用 SSH 隧道时,远程主机上的 app-server 应仅监听 loopback;在本机建立隧道后使用本地 `ws://`:

```bash
# 远程主机:使用其安全的 Token 文件启动 app-server
codex app-server --listen ws://127.0.0.1:4500 --ws-auth capability-token --ws-token-file /secure/codex-app-server.token
# 本机:保持隧道运行
ssh -N -L 4500:127.0.0.1:4500 user@codex-host
export CODEX_APP_SERVER_URL='ws://127.0.0.1:4500'
export CODEX_REMOTE_TOKEN_FILE="$HOME/.config/codex-app-server.token"
node /path/to/codex-app-server-mcp/server.mjs
```

远程 WebSocket 在任务运行时断开,任务会显示 `status: "unknown"` 与断线原因。桥接不会自动重连后重发该任务,避免重复执行;可以在确认远程状态后手动发起新任务。关闭桥接只关闭其 WebSocket 客户端连接,不会向远程 app-server 发送终止信号。

本地模式的真实 Codex 测试仍依赖本机登录和可访问的用户 Home。远程模式已使用本地受控 WebSocket 服务验证握手 Bearer 头、远程 cwd 透传和断线为 `unknown`;尚未针对外部真实远程 Codex 端点运行集成测试。

## 沙箱开关:默认只读,用户显式启用写入

在 Claude 项目的 .mcp.json 中,保留现有 codex-agent 的 command、args 和 env,在它的 env 对象中增加:

```json
"CODEX_SANDBOX_MODE": "workspace-write"
```

保存后重启该项目的 Claude / MCP 连接。恢复只读时改为 read-only;删除该键将回退到进程环境,环境也未设置时才使用只读默认值。

这是一项启动配置,不是 Claude 可以通过 prompt 或 codex_start 参数自行切换的权限。每个桥接实例启动后固定使用该模式,新建、恢复会话及每次任务均重新发送对应权限。支持本地和远程连接;远程的 cwd 与可写目录属于远程执行环境。

写入范围是任务 cwd 工作区及 Codex 标准沙箱允许的临时目录,受服务端和平台的额外限制约束。不会开启网络或全磁盘访问。当前 cwd 仍由调用方提供,因此请明确任务目录。配置为 workspace-write 并不保证外部依赖下载或工作区外的全局缓存写入成功。

若为调试而手动启动,可仅使用环境变量:

```powershell
$env:CODEX_SANDBOX_MODE = 'workspace-write'
$env:CODEX_ALLOWED_ROOTS = 'D:\projects\my-app'
node .\server.mjs
```

验证:npm.cmd test 包含默认值、非法配置、新建/恢复会话的双层权限、远程策略、审批拒绝和 MCP 工具描述检查。
真实沙箱文件测试使用独立临时目录(不修改业务仓库):

```powershell
$env:CODEX_RUN_SANDBOX_REAL = '1'
npm.cmd run test:sandbox-real
```

真实测试依次检查默认只读不能创建文件、显式开启写入能创建文件,以及恢复可写会话到只读后不能再次创建文件。需有效 Codex 登录和可用网络;未执行真实测试不能视为沙箱执行验证通过。

## 指定模型

在项目 .mcp.json 的 codex-agent.env 中设置 CODEX_MODEL 为账号可用的模型 ID,保存后重启 Claude / MCP。示例(将占位符替换为实际模型 ID):

```json
"CODEX_MODEL": "YOUR_MODEL_ID",
"CODEX_SANDBOX_MODE": "workspace-write"
```

未设置 CODEX_MODEL 时不传 model:新会话使用 Codex 默认配置,恢复会话遵循 Codex 对已有会话的默认行为。显式设置后,新建、恢复会话和每个 turn 均传入该模型。空值会报错;不自动替换账号不支持的模型,不修改 Codex 全局配置。该设置适用于本地和远程模式,也可通过启动环境传入。任务状态的 requestedModel 表示请求的模型 ID(未设置时为 null),不冒充服务端确认的实际模型。

### 通过话术切换模型

codex_start 现在接受可选 model 参数。对 Claude 说“通过 codex-agent,使用模型 <实际模型 ID> 审查当前项目”,Claude 应把模型 ID 传入 model,而不是仅写进 prompt。
优先级为:本次 model 参数 > CODEX_MODEL 启动配置 > Codex 默认。支持在下一次调用中沿用 threadId 并更换 model,兼容性和账号权限由服务端验证;不自动替换不支持的模型。运行中的任务不能中途切换,需等待结束或取消后再调用。未指定 model 且未配置 CODEX_MODEL 时,恢复已有会话遵循服务端已有模型设置。

注意:可通过话术选择模型,但不能通过话术改变沙箱权限;写入权限仍必须由用户配置 CODEX_SANDBOX_MODE。

TDQS

A3.7/5.0

Scored across 10 tools

Disambiguation5/5

Each tool maps to a distinct Codex operation: start, status, cancel, steer, review, compact, pending input, answer input, model listing, and diagnostics. Even similar actions like codex_steer and codex_answer_input are cleanly separated by their stated purpose.

Naming Consistency4/5

The codex_ prefix and snake_case style are consistent throughout, making the family easy to recognize. Minor deviations exist: codex_models and codex_status are noun-like rather than verb_noun, while most others follow an action-oriented pattern.

Tool Count5/5

Ten tools is a well-scoped set for managing Codex tasks and app-server operations. Each tool covers a meaningful lifecycle or capability without unnecessary redundancy.

Completeness4/5

The surface covers the main task lifecycle: start, monitor, cancel, steer, answer pending input, compact context, and review. Minor gaps exist around broader thread history or explicit thread deletion, but these are not essential for the core workflow.

Maintenance

ActivityMaintained
ResponsivenessNo issues