cc-codex-mcp
Runs OpenAI Codex as a local stdio MCP server so Claude Code agents and subagents can request an independent opinion (typically a read-only review of their changes) and continue the same Codex thread later. Provides codex_ask to start a Codex thread in a project directory and return the answer plus a thread ID, and codex_followup to resume that thread. Each call can set model, reasoning effort, fast mode (service tier), sandbox mode (read-only or workspace-write), and timeout; results include the answer, duration, warnings, and activity such as commands run, MCP tool calls, and subagent events.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@cc-codex-mcpask Codex for a read-only review of my latest changes"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
cc-codex-mcp
A local stdio MCP server that lets Claude Code agents and subagents ask OpenAI Codex for an independent opinion (typically a read-only review of their changes) and follow up on the same Codex thread later.
codex_ask: start a Codex thread in a project directory and get the answer plus athread_id.codex_followup: continue that thread ("I fixed 1 and 3, re-check").Per call:
model,effort,fast,sandbox,timeout_sec.Runs in an isolated
CODEX_HOME(~/.codex-reviews), so these threads never show up in the Codex desktop app.Safe for many parallel callers: one process and temp dir per call, no shared state, plus a cross-process lock per thread.
Windows first (tested on Windows 10 with the Codex desktop app and codex-cli 0.163). macOS/Linux should work but are untested.
Requirements
Node.js >= 20.3
The Codex CLI. On Windows it ships with the Codex desktop app; a separately installed
codexworks too (see How Codex is found).A ChatGPT account that can use Codex.
Related MCP server: codex-subagent-mcp
Install
git clone https://github.com/NtTestAlert/cc-codex-mcp.git
cd cc-codex-mcp
npm install
npm run build1. One-time login for the isolated home
The isolated home has its own login. auth.json is never copied or linked from ~/.codex, because token
refreshes rewrite that file.
Windows (PowerShell):
powershell -ExecutionPolicy Bypass -File scripts\login.ps1
# or by hand:
$env:CODEX_HOME="$HOME\.codex-reviews"; & "$env:LOCALAPPDATA\Codex\versions\current\resources\codex.exe" loginAdd -DeviceAuth (or --device-auth) if no browser can open. On macOS/Linux:
CODEX_HOME="$HOME/.codex-reviews" codex login.
Until you log in, every tool call returns an error containing this command.
2. Register with Claude Code (CLI and desktop app)
Claude Code's CLI and the Claude desktop app (Code tab) share the same user-scope MCP config (~/.claude.json), so
one registration covers both. Use an absolute path to a real node.exe: version-manager shims (Volta, nvm-windows)
can pick a different Node per project, and Volta's shim also mangles </> in arguments.
claude mcp add-json --scope user cc-codex-mcp '{"type":"stdio","command":"C:/path/to/node.exe","args":["C:/path/to/cc-codex-mcp/dist/index.js"],"timeout":3700000}'
claude mcp get cc-codex-mcpclaude mcp get should show Status: ✔ Connected. New Claude Code sessions (CLI or desktop) pick it up; sessions
that were already open need a restart. Tools appear as mcp__cc-codex-mcp__codex_ask and
mcp__cc-codex-mcp__codex_followup.
Other MCP clients (Claude Desktop chat, Cursor, etc.) use the usual stdio entry: command = absolute node,
args = [".../dist/index.js"].
Tool-call timeout
Claude Code has two limits on MCP tool calls (checked in Claude Code 2.1.277 / desktop 2.1.299):
a hard wall-clock limit: the per-server
"timeout"(ms) if set, otherwiseMCP_TOOL_TIMEOUT, otherwise about 28 h;an idle limit,
CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT(default 30 min for stdio), which progress notifications reset.
The per-server "timeout": 3700000 above covers the maximum timeout_sec (3600). It works in both the CLI and the
desktop app, regardless of environment-variable precedence (under the desktop app, a variable already in the host's
environment wins over settings.json env). The server sends a progress notification every ~15 s while Codex runs,
which keeps the idle limit from firing. You don't need to set MCP_TOOL_TIMEOUT; setting it would lower the 28 h
default for every server.
3. Tell your agents when to use it
See CLAUDE.snippet.md: drop it into a project's CLAUDE.md. Implementer subagents then get a
read-only review when they finish, fix real issues, re-check on the same thread, stop after 3 rounds, and never use
fast mode unless told to.
Check the setup
node dist/index.js --doctorThis prints the resolved Codex executable, the isolated home and login state, and the MCP sync report: each server,
its transport, and whether default_tools_approval_mode is set. It also creates the isolated home if needed and runs one real config
sync, so it may update the isolated config.toml (never ~/.codex).
Tools
codex_ask
input | default | |
| required | sent on stdin, so no quoting issues |
| required | project directory ( |
|
| or |
| config default |
|
| config default |
|
|
|
|
|
|
|
| 900 | 10…3600; on timeout the whole process tree is killed ( |
Runs codex exec --json --color never -C <cwd> -s <sandbox> [...] -o <temp file> -.
codex_followup
Inputs: thread_id (a UUID, validated, and it must exist in the isolated home), prompt, plus optional model,
effort, fast, timeout_sec. Runs codex exec resume --json --skip-git-repo-check -c sandbox_mode="<original>" [...] -o <temp file> <thread_id> -, with the process working directory set to the thread's original cwd. If that directory no longer exists, it runs
from your home directory and says so in warnings.
Result (both tools)
{
"thread_id": "0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b",
"answer": "…",
"duration_sec": 7.5,
"warnings": [],
"activity": { "commands": 2, "mcp_tool_calls": ["openaiDeveloperDocs.search_openai_docs (completed)"], "subagent_events": 0 },
"error": "…only when something failed…",
"answer_file": "…only when the answer was truncated…"
}answeris the-ofile (falling back to the lastagent_message), ANSI-stripped and capped at 50,000 characters. When it's longer, the full text stays inanswer_file.warningscollects MCP server startup failures, failed or rejected MCP tool calls, declined commands, unsupported service tier / fast-mode messages, config problems, and config-sync errors.On
turn.failed,errorevents in a turn that didn't complete, a non-zero exit, a timeout or cancellation,errorholds the message plus the last 40 stderr lines. Any partial answer and thethread_idare still returned.activityis only present when Codex ran commands, called MCP tools, or spawned subagents.
Environment variables
variable | default | |
|
| isolated |
|
| main Codex home (source of truth for config and sandbox state) |
| auto | explicit Codex executable ( |
| unset |
|
| unset | comma-separated MCP server names not to sync |
| unset |
|
How Codex is found
CODEX_BRIDGE_CODEX_PATH.codexonPATH. An npmcodex.cmdshim is unwrapped to the nativecodex.exeinside the npm package, or tobin/codex.jsrun with the current Node. A shell is never used.The desktop app:
%LOCALAPPDATA%\Codex\versions\current\resources\codex.exe(currentis a junction to the newest version), else the highestversions\<x.y.z.w>folder. On macOS,/Applications/Codex.app/Contents/Resources/codex.
What is shared with the Codex desktop app
The desktop app's ~/.codex is the source of truth. The bridge only reads it and only writes the isolated home.
Config sync (config.toml): at startup, then when ~/.codex/config.toml changes (fs.watch, debounced 1 s),
plus a cheap mtime/size check before each run in case the watcher missed an event. The sync copies:
the
[mcp_servers.*]tables (per server name the source wins; servers only in the isolated config are kept; servers removed from the source are removed again);top-level
modelandmodel_reasoning_effort;the
[windows]table. Withoutwindows.sandbox, Codex on Windows blocks every shell command in read-only mode, evengit diff.
All other isolated-config keys are kept. Writes are atomic and only happen when the synced subset actually changed.
The file is parsed with a real TOML parser (smol-toml), so comments in the isolated config are not preserved.
Desktop-only servers are skipped by default (node_repl needs the desktop app's named pipe and hard-codes
CODEX_HOME=~/.codex).
Elevated Windows sandbox state. The elevated sandbox runs commands as two machine-wide local accounts
(CodexSandboxOffline / CodexSandboxOnline). Each CODEX_HOME keeps its own DPAPI-encrypted copy of their
passwords (.sandbox-secrets/sandbox_users.json) and a .sandbox/setup_marker.json. If two homes each provision,
every provisioning rotates the passwords and makes the other home re-run the elevated setup, endlessly. So the
desktop app's home owns this state, and the bridge copies those two files into the isolated home at startup and
whenever the desktop app rewrites them (fs.watch). Nothing happens per call. The isolated home never provisions
while the desktop app has a provisioned sandbox, and ~/.codex is never written.
Normal Codex behaviour is unaffected: a quick, non-elevated codex-windows-sandbox-setup.exe "setup refresh" still
runs before sandboxed commands, as it does in the desktop app.
Not shared: auth.json (separate login), MCP OAuth tokens (see below), sessions/threads, history, memories.
Tool approvals for synced MCP servers
node dist/index.js --doctor lists every synced server and whether it sets default_tools_approval_mode = "approve".
The bridge never changes that setting. In testing, read-only MCP tools ran fine under exec without it. If a server's
tool calls get rejected for approval, warnings says so; add default_tools_approval_mode = "approve" to that server
in ~/.codex/config.toml and the sync carries it over.
MCP OAuth tokens
With Codex 0.163 on Windows, OAuth tokens for remote MCP servers are stored per CODEX_HOME:
CODEX_HOME\secrets\mcp_oauth.age, with its key in Windows Credential Manager under an account derived from the
CODEX_HOME path. The isolated home does not see the desktop app's tokens. To log a server in for the isolated home:
$env:CODEX_HOME="$HOME\.codex-reviews"; & "$env:LOCALAPPDATA\Codex\versions\current\resources\codex.exe" mcp login <server>Remote plugins enabled on your ChatGPT account are installed into every home, including the isolated one, so their
OAuth MCP servers need this login too. Until a server is logged in, each run carries a harmless AuthRequired
warning for it. Servers that authenticate with headers or bearer_token_env_var in config.toml need nothing extra.
Verified against the installed CLI (codex-cli 0.163.0-alpha.10.2)
exec:--json,-o,-C,-s read-only|workspace-write|danger-full-access,-m,-c key=value(TOML value),--skip-git-repo-check, and-/ no prompt = read stdin all exist. The first JSON event is{"type":"thread.started","thread_id":…}. Thread ids are UUIDv7.exec resume: accepts-c,-m,--json,-o,--skip-git-repo-checkand-for stdin. It has no-Cand no-s, and it runs in the process cwd, not the thread's original cwd. So the bridge spawns it in the original cwd (read from the rollout file) and keeps the sandbox with-c sandbox_mode="…".Fast mode:
-c service_tier="fast"is accepted and recorded asservice_tier: "priority". An unsupported tier produces anerroritem ("…not advertised as supported for model…"), which lands inwarnings.Reasoning effort key:
model_reasoning_effort. Supported levels come from Codex's own model list (<CODEX_HOME>/models_cache.json); at the time of writing the models offeredlow, medium, high, xhigh, maxand most alsoultra, and none offeredminimal. Before starting Codex, the bridge checkseffortagainst the effective model: themodelinput, else the thread's model for follow-ups, else the configured default. An unsupported level is rejected with the supported list. Unknown models are passed through unchecked. Verified live:low,xhigh,maxandultraare each recorded as the turn'sreasoning_effort.Subagents (
multi_agent, stable) work underexec: the child thread hasthread_source: "subagent"and the parent'sparent_thread_id.
Known limitations
Occasionally a run sits for several minutes waiting on the model API (seen: 225 s and ~438 s for a one-word reply, both with and without fast mode; the next identical runs took ~7 s). The default 900 s timeout covers it.
Settings this Codex version doesn't recognise produce a warning on every run until they're removed from
~/.codex/config.toml.On Windows, if
codex.exeitself crashes while a grandchild still holds its pipes, that grandchild can outlive it (Node can't put children in a Job Object). Timeouts, cancellation and shutdown kill the whole tree.The thread lock is a lockfile with a 30 s heartbeat. A crashed holder is reclaimed after its PID is gone, or after 2 minutes without a heartbeat.
macOS/Linux paths are implemented but untested.
Development
npm test # build + node:test (unit tests use temp dirs and a fake codex)
node dist/index.js --doctorLayout: src/index.ts (MCP tools), runner.ts (spawn, JSONL parsing, timeout and tree kill), codexPath.ts,
lock.ts, configSync.ts, sandboxMirror.ts, home.ts, sessions.ts, util.ts.
Available Tools
2 toolscodex_askAsk CodexA
Get an independent opinion from a different model (OpenAI Codex), e.g. a read-only review of changes you made. Returns a thread_id; keep it if you may want to ask follow-ups.
Codex runs as an agent in cwd and can read files and run read-only commands there itself, so name the files, diff range or question precisely instead of pasting large content. A run can take several minutes. Default sandbox is read-only; only use workspace-write when you explicitly want Codex to edit files. Returns JSON: { thread_id, answer, duration_sec, warnings[], activity?, answer_file?, error? }.
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | Yes | Absolute path of the project directory Codex should work in. | |
| fast | No | Fast mode (faster responses). Uses roughly 2.5x the ChatGPT subscription usage limits, so leave it off unless the user explicitly asked for fast mode. | |
| model | No | Codex model id. Omit to use the configured default. | |
| effort | No | Reasoning effort. Omit to use the configured default. Checked against the levels the model supports (an unsupported level returns an error listing the supported ones). | |
| prompt | Yes | What to ask Codex. Be specific (files, commits, what to look for). | |
| sandbox | No | read-only (default): Codex cannot modify files. workspace-write: Codex may edit files in cwd. | |
| timeout_sec | No | Kill Codex after this many seconds (default 900, max 3600). | |
| skip_git_check | No | Allow running in a directory that is not a git repository (default false). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: Codex runs as an agent in cwd and can read files and execute read-only commands itself, runs can take several minutes, and the default sandbox blocks file modification. The stated default read-only sandbox is consistent with readOnlyHint=false (writes are possible under workspace-write) and openWorldHint=true (external model/agent), so there is no contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then behavior, then return shape; every sentence carries information and the timeout/warnings/error details are useful given there is no output schema. Minor redundancy in mentioning the thread_id twice, which is why it is not a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly supplies the return shape ({ thread_id, answer, duration_sec, warnings[], activity?, answer_file?, error? }), plus latency expectations and sandbox defaults. Nothing an agent needs to call this correctly and interpret the result is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema carries parameter documentation and the baseline is 3. The description still adds real value: guidance on how to phrase 'prompt' (files, diff range, question) and the cwd-as-working-directory semantics, rather than repeating field-level descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (get an independent opinion from OpenAI Codex) and gives a concrete use case (read-only review of changes). It also differentiates from the sibling by explaining that the returned thread_id is what enables follow-ups, so an agent can route between codex_ask and codex_followup without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly covers when to use the default (read-only review) and when not to ('only use workspace-write when you explicitly want Codex to edit files'), plus the fast-mode cost caveat. It also tells the agent to name files/diff ranges precisely rather than pasting content, which is actionable invocation guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
codex_followupFollow up with CodexA
Continue an existing Codex thread by thread_id: re-check fixes, ask why it flagged something. Always use the thread_id from your own earlier codex_ask; never guess one.
The thread keeps its original working directory and sandbox mode. Only one follow-up can run on a thread at a time; a concurrent one waits (up to timeout_sec) and then fails with "thread busy". Returns JSON: { thread_id, answer, duration_sec, warnings[], activity?, answer_file?, error? }.
| Name | Required | Description | Default |
|---|---|---|---|
| fast | No | Fast mode (faster responses). Uses roughly 2.5x the ChatGPT subscription usage limits, so leave it off unless the user explicitly asked for fast mode. | |
| model | No | Codex model id. Omit to use the configured default. | |
| effort | No | Reasoning effort. Omit to use the configured default. Checked against the levels the model supports (an unsupported level returns an error listing the supported ones). | |
| prompt | Yes | The follow-up message. | |
| thread_id | Yes | thread_id returned by your earlier codex_ask (a UUID). | |
| timeout_sec | No | Kill Codex after this many seconds (default 900, max 3600). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and openWorldHint=true; the description adds material behavior beyond that: the thread inherits its original working directory and sandbox mode, follow-ups are serialized per thread with a timeout-then-fail model, and it enumerates the response envelope. This is substantive context the annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, each earning its place: purpose first, then the thread_id sourcing rule, then inheritance/concurrency/return-shape facts. No filler or restatement of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description compensates by naming the return fields (thread_id, answer, duration_sec, warnings[], activity?, answer_file?, error?) and covers prerequisites, sandbox inheritance, and failure modes. Nothing an agent needs to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so fast/model/effort/prompt/thread_id/timeout_sec are already documented in the schema. The description reinforces thread_id provenance ('never guess one') and connects timeout_sec to the concurrency wait, which is helpful, but it does not add meaning the schema lacks. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (continue an existing Codex thread by thread_id) and gives concrete example uses (re-check fixes, ask why something was flagged). It distinguishes itself from the sibling codex_ask by explicitly requiring the thread_id that codex_ask produced, so an agent can route between the two without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit usage condition (continue an existing thread) plus a hard prerequisite: 'Always use the thread_id from your own earlier codex_ask; never guess one.' It also states the concurrency rule (only one follow-up per thread, concurrent calls wait then fail with 'thread busy'), which is exactly the kind of when-it-won't-work guidance an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.1.0- First observed
codex_ask - First observed
codex_followup
TDQS
Scored across 2 tools
codex_ask starts a new independent-review thread, while codex_followup continues an existing one via thread_id. The two purposes are cleanly separated with no overlapping scope, so an agent can choose reliably.
Both tools use the same codex_ prefix with snake_case action suffixes (ask, followup). The pattern is predictable and no conventions are mixed.
Two tools is lean but well-matched to a narrow purpose: initiate an opinion thread and extend it. It is slightly below the typical 3-15 range, but each tool clearly earns its place.
The ask/follow-up pair covers the core lifecycle of getting and continuing an independent review. Minor gaps such as listing or cancelling threads exist but are not required for the stated workflow.
Maintenance
Related MCP Connectors
A paid remote MCP for OpenAI Codex agent coordination MCP, built to return verdicts, receipts, usage
A paid remote MCP for OpenAI Codex context compressor, built to return verdicts, receipts, usage log
A paid remote MCP for OpenAI Codex harness MCP, built to return verdicts, receipts, usage logs, and
Multi-model code review: a panel of models + detectors return a pass/fail verdict. Paid via x402.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables Claude Code to delegate bounded, read-only analysis and isolated patch proposals to the locally installed Codex CLI over MCP, with sanitized live status, revision-aware polling, and reviewable results.1MIT
- AlicenseAqualityAmaintenanceEnables Claude Code to delegate coding tasks—investigation, review, long-running background jobs, and optional file edits—to a locally installed OpenAI Codex CLI, with the model and reasoning effort chosen per task and read-only execution by default. Follow-up requests reuse Codex's existing context, and write-enabled delegations can be confined to a managed git worktree so the user's own checkout stays untouched.842 npmMIT
- FlicenseCqualityBmaintenanceEnables Codex to delegate already-scoped coding tasks to Claude Code and manage the resulting execution and fresh read-only review sessions, returning deterministic PASS/FAIL results through a local MCP interface.715-
- AlicenseNot gradedqualityBmaintenanceEnables delegating bounded tasks from Codex to Claude Code, including read-only reviews, isolated branch edits, long-running background work, and approval handling.220 npmMIT