MCP Hub
Back to servers

@leo000001/codex-mcp

MCP server that wraps OpenAI Codex app-server — start coding agents, poll their progress, and manage permissions from any MCP client

Updated
Feb 21, 2026

Quick Install

npx -y @leo000001/codex-mcp

codex-mcp

npm version license node

MCP server that wraps OpenAI Codex app-server — start coding agents, poll their progress, and manage permissions from any MCP client.

Features

  • 4 tools, full capabilitycodex, codex_reply, codex_session, codex_check
  • Async non-blocking — sessions run in background, poll for results
  • Complete permission management — three-layer model: approval policy, sandbox isolation, async approval arbitration
  • Zero config — inherits your local ~/.codex/config.toml automatically
  • Session management — list, inspect, cancel, interrupt, fork sessions
  • Event streaming — cursor-based pagination with pin-protected event buffer
  • Static read-only resourcescodex-mcp:///server-info, codex-mcp:///compat-report, codex-mcp:///config, codex-mcp:///gotchas, codex-mcp:///quickstart, codex-mcp:///errors

Prerequisites

Quick Start

npx (no install)

npx @leo000001/codex-mcp

Global install

npm install -g @leo000001/codex-mcp
codex-mcp

Windows shell wrapper (if needed)

pwsh -NoProfile -Command "npx -y @leo000001/codex-mcp"

MCP Client Configuration

Add to your MCP client config (e.g. Claude Desktop, Cursor, etc.):

{
  "mcpServers": {
    "codex": {
      "command": "npx",
      "args": ["-y", "@leo000001/codex-mcp"]
    }
  }
}

Claude Code

claude mcp add codex-mcp -- npx -y @leo000001/codex-mcp

Or add to ~/.claude/settings.json:

{
  "mcpServers": {
    "codex-mcp": {
      "command": "npx",
      "args": ["-y", "@leo000001/codex-mcp"]
    }
  }
}

STDIO Guard Modes

codex-mcp includes a startup preflight guard for stdout contamination risk.

  • CODEX_MCP_STDIO_MODE=auto (default): run with warnings when risk is elevated
  • CODEX_MCP_STDIO_MODE=strict: fail fast on blocking risks (e.g. TTY stdio), keep heuristic risks as warnings
  • CODEX_MCP_STDIO_MODE=off: disable the preflight guard

Examples:

CODEX_MCP_STDIO_MODE=strict npx -y @leo000001/codex-mcp
$env:CODEX_MCP_STDIO_MODE = "strict"; npx -y @leo000001/codex-mcp

Tools

codex — Start a new session

Start a Codex agent session asynchronously. Returns immediately with sessionId.

ParameterTypeRequiredDescription
promptstringYesTask or question for the Codex agent
approvalPolicystringYesApproval policy: untrusted, on-failure, on-request, never — caller must set based on its own permission level
sandboxstringYesSandbox mode: read-only, workspace-write, danger-full-access — caller must set based on its own permission level
effortstringNoReasoning effort: none, minimal, low, medium, high, xhigh. Default: low; increase/decrease based on task complexity
cwdstringNoWorking directory. Default: server cwd
modelstringNoModel override. Default: from ~/.codex/config.toml
profilestringNoconfig.toml profile name (passed as codex app-server -p)
advancedobjectNoLow-frequency options (see below)
advanced object parameters (9 low-frequency parameters)
ParameterTypeDescription
advanced.baseInstructionsstringReplace default instructions (thread-level)
advanced.developerInstructionsstringDeveloper instructions (thread-level)
advanced.personalitystringPersonality: none, friendly, pragmatic (default: from ~/.codex/config.toml)
advanced.summarystringReasoning summary: auto, concise, detailed, none (default: from ~/.codex/config.toml)
advanced.configobjectOverride config.toml values (passed as codex app-server -c key=value)
advanced.ephemeralbooleanDon't persist thread. Default: false
advanced.outputSchemaobjectJSON Schema for structured output
advanced.imagesstring[]Local image paths (adds localImage inputs)
advanced.approvalTimeoutMsnumberAuto-decline timeout (ms) for pending approvals. Default: 60000

Returns: { sessionId, threadId, status: "running" | "idle", pollInterval }

{
  "prompt": "Fix the failing tests in src/",
  "approvalPolicy": "on-request",
  "sandbox": "workspace-write",
  "effort": "high",
  "cwd": "/path/to/project",
  "model": "o4-mini"
}

Resources

If your MCP client supports resources, this server exposes a few read-only resources:

  • codex-mcp:///server-info (JSON): static server metadata (version/platform/runtime)
  • codex-mcp:///compat-report (JSON): capability summary for cross-backend adapter compatibility
  • codex-mcp:///config (Markdown): config mapping guide, including how to use codex.advanced.config
  • codex-mcp:///gotchas (Markdown): practical limits/gotchas
  • codex-mcp:///quickstart (Markdown): minimal workflow examples
  • codex-mcp:///errors (Markdown): error code catalog + recovery hints

codex_reply — Continue a session

Send a follow-up message to an existing session.

ParameterTypeRequiredDescription
sessionIdstringYesSession ID from codex
promptstringYesFollow-up message
modelstringNoOverride model for this turn
approvalPolicystringNoOverride approval policy
effortstringNoOverride reasoning effort (none, minimal, low, medium, high, xhigh)
summarystringNoOverride reasoning summary (auto, concise, detailed, none)
personalitystringNoOverride personality (none, friendly, pragmatic)
sandboxstringNoOverride sandbox (read-only, workspace-write, danger-full-access)
cwdstringNoOverride working directory
outputSchemaobjectNoJSON Schema for structured output

Returns: { sessionId, threadId, status: "running" | "idle", pollInterval }

{
  "sessionId": "sess_abc123",
  "prompt": "Now add error handling for the edge cases"
}

codex_session — Manage sessions

List, inspect, cancel, interrupt, or fork sessions.

ParameterTypeRequiredDescription
actionstringYes"list", "get", "cancel", "interrupt", or "fork"
sessionIdstringFor get/cancel/interrupt/forkTarget session ID
includeSensitivebooleanNoInclude cwd/profile/config/threadId in get. Default: false

Returns:

  • action="list"{ sessions: PublicSessionInfo[] }
  • action="get"PublicSessionInfo (or SensitiveSessionInfo when includeSensitive=true)
  • action="cancel"|"interrupt"{ success: true, message }
  • action="fork"{ sessionId, threadId, status: "idle", pollInterval }
{ "action": "list" }
{ "action": "get", "sessionId": "sess_abc123", "includeSensitive": true }
{ "action": "cancel", "sessionId": "sess_abc123" }
{ "action": "interrupt", "sessionId": "sess_abc123" }
{ "action": "fork", "sessionId": "sess_abc123" }

codex_check — Poll events & respond

Query a running session for events, respond to approval requests, or answer user input.

ParameterTypeRequiredDescription
actionstringYes"poll", "respond_permission", or "respond_user_input"
sessionIdstringYesTarget session ID
cursornumberNoEvent cursor for incremental polling (action="poll"). For respond_*, codex-mcp applies monotonic cursor progression: max(cursor, sessionLastCursor).
maxEventsnumberNoKeep this small. poll default: 1 (minimum 1; increase only for catch-up). respond_* default: 0 (recommended; compact ACK, no event replay).
responseModestringNoResponse shaping mode: minimal (default), delta_compact, full
pollOptionsobjectNoOptional controls: includeEvents (default true), includeActions (default true), includeResult (default true), maxBytes (default unlimited)
requestIdstringFor respond_permission/user_inputRequest ID from actions[]
decisionstringFor respond_permissionFor command approvals: "accept", "acceptForSession", "acceptWithExecpolicyAmendment", "decline", "cancel"; for file changes: "accept", "acceptForSession", "decline", "cancel"
execpolicyAmendmentstring[]For acceptWithExecpolicyAmendmentExec policy amendment list (required when decision="acceptWithExecpolicyAmendment")
denyMessagestringNoInternal note on deny (not sent to app-server)
answersobjectFor respond_user_inputFor respond_user_input: questionId -> { answers: string[] }

Returns (poll and respond_*): { sessionId, status, pollInterval?, cursorResetTo?, events, nextCursor, actions?, result? }

{ "action": "poll", "sessionId": "sess_abc123", "cursor": 0 }
{
  "action": "respond_permission",
  "sessionId": "sess_abc123",
  "requestId": "req_xyz",
  "decision": "accept"
}
{
  "action": "respond_user_input",
  "sessionId": "sess_abc123",
  "requestId": "req_abc",
  "answers": { "question_id": { "answers": ["choice_1"] } }
}

Event Polling Semantics

codex_check(action="poll") returns an append-only event stream with cursor pagination:

  • cursor: the first event id you want (use the previous nextCursor)
  • nextCursor: pass this back on the next poll
  • cursorResetTo: when present, older events were evicted; restart from this cursor to avoid gaps
  • maxEvents: max events returned per call
  • If cursor is omitted, codex-mcp continues from that session's last consumed cursor.
  • If responseMode is omitted, codex-mcp uses minimal.
  • pollOptions.includeEvents/includeActions/includeResult default to true.
  • pollOptions.maxBytes is optional and enforces best-effort payload truncation (truncated, truncatedFields).
  • respond_* defaults to compact ACK (events: [], no cursor advance) unless you explicitly pass maxEvents.
  • poll defaults to maxEvents=1 to keep payloads small; increase temporarily (for example 10-20) when you need to catch up faster.
  • If poll is called with maxEvents=0, codex-mcp treats it as 1 to avoid no-op polling loops.
  • For respond_*, prefer maxEvents=0 instead of 1: 0 keeps approval ACK minimal and avoids consuming/replaying stream events in the same call. Use 1-5 only when you explicitly need immediate events.
  • For poll, keep windows small to reduce payload spikes and context pressure.

Event types include output, progress, approval_request, approval_result, result, error. Approvals/results/errors are pinned to reduce eviction risk.

Approvals & User Input

When the agent requests approval or user input, poll includes an actions[] list. Respond with:

  • respond_permission: decision is one of accept, acceptForSession, decline, cancel.
    • For command approvals, acceptWithExecpolicyAmendment is supported and requires execpolicyAmendment.
  • respond_user_input: send answers keyed by questionId.

Pending approvals auto-decline after advanced.approvalTimeoutMs.

Session Lifecycle & Cleanup

Sessions auto-clean up in the background:

  • idle > 30 minutes → cancelled
  • running/waiting_approval > 4 hours → cancelled
  • cancelled/error > 5 minutes → removed from memory

Error Model

Tools return errors as:

{ "content": [{ "type": "text", "text": "Error [CODE]: message" }], "isError": true }

Common codes include INVALID_ARGUMENT, SESSION_NOT_FOUND, SESSION_BUSY, SESSION_NOT_RUNNING, REQUEST_NOT_FOUND, CANCELLED, INTERNAL.

Client compatibility notes

  • Tool responses follow @modelcontextprotocol/sdk's CallToolResult contract: content (JSON text for wide compatibility), optional structuredContent (the canonical object), and isError. structuredContent is always object-shaped; when a tool returns a scalar/array, codex-mcp wraps it as { "value": ... }. Claude Desktop and other clients tend to surface the content text directly, which shows the raw JSON blob, so they should fall back to structuredContent when they want typed data (Cursor already does this automatically whenever structured output is available).
  • When an operation fails we set isError: true and return Error [CODE]: message in the content array instead of raising an MCP transport error. This keeps the STDIO channel healthy so Claude, Cursor, and other MCP clients stay connected even when a tool reports a problem.
  • codex-mcp uses the MCP stdio transport (src/index.ts), so stdout is reserved for newline-delimited JSON and all diagnostics go to stderr. Anything else on stdout—including shell/profile banners (e.g., PowerShell's oh-my-posh warning) or CLI wrappers that print prompts—will break the MCP handshake for Claude/Cursor. Run pwsh -NoProfile, disable profile banners, or wrap the command so stdout stays quiet before piping it into the client.
  • Windows command execution inside codex app-server may still inherit PowerShell profile side effects in some environments. This cannot be filtered by codex-mcp once emitted on stdout; if command turns are noisy or fail with profile errors, clean your PowerShell profile and prefer approvalPolicy="on-failure" / "never" to reduce approval churn.
  • If Windows command output shows mojibake, enforce UTF-8 in the shell (chcp 65001 and $OutputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()).
  • Startup guard behavior is controlled by CODEX_MCP_STDIO_MODE (auto/strict/off). Use strict in CI or hardened environments to fail fast on blocking contamination risks (while still surfacing heuristic risk warnings).
  • Retryable transport/API interruptions are emitted as progress events with data.method="codex-mcp/reconnect" and willRetry=true, so clients can surface reconnect state without treating it as terminal failure.
  • Approval/user-input flows rely on the actions[] array returned by codex_check(action="poll"). Claude and Cursor render approval buttons from this payload, so they need to poll at pollInterval, honour cursorResetTo, and reply within approvalTimeoutMs to avoid automatic declines.

Typical Workflow

1. codex(prompt="Fix bug X")           → { sessionId, threadId, status: "running" }
2. codex_check(action="poll", ...)      → events[], status, actions[]
3. codex_check(action="respond_permission", decision="accept")  (if needed)
4. codex_check(action="poll", ...)      → result when status="idle"
5. codex_reply(prompt="Also add tests") → new turn starts
6. codex_check(action="poll", ...)      → poll until done

Permission Model

Three layers of protection:

LayerMechanismOptions
0Approval Policynever, on-failure, on-request, untrusted
1Sandboxread-only, workspace-write, danger-full-access
2Async ApprovalCommand execution + file change approval via codex_check

Architecture

Same-platform assumption: codex-mcp assumes the MCP client and server run on the same machine. All communication uses stdio (local IPC), child processes share the local filesystem and ~/.codex/config.toml, and cwd paths refer to the local filesystem.

MCP Client ←stdio→ codex-mcp server ←stdio→ codex app-server ←→ Codex Agent
         (same machine, stdio transport)

Each session spawns an independent codex app-server child process. The MCP server translates between MCP tool calls and the app-server's JSON-RPC protocol.

Development

git clone https://github.com/xihuai18/codex-mcp.git
cd codex-mcp
npm install
npm run build
npm run typecheck
npm test
npm run check:stdio
npm run check:stdio:strict

End-to-end local test plan (after installing/configuring in an MCP client):

  • Full guide (LLM operator handbook): docs/E2E_LOCAL_TEST_PLAN.md
  • Quick English checklist: run codex → poll with codex_check(action="poll") → respond via respond_permission/respond_user_input if actions[] appears → continue polling until status is idle/error/cancelled.

Project Policies

License

MIT

Reviews

No reviews yet

Sign in to write a review