# mcp-codex-worker

A stdio MCP server that bridges MCP clients to the Codex app-server runtime. Provides **5 task tools** for fully autonomous agent orchestration — spawn, wait, respond, message, cancel. All commands and file edits are auto-approved. Full observability via file-backed reporting and MCP resource subscriptions.

Does not call OpenAI APIs directly — all work is delegated to `codex app-server` (see [codex-app-server protocol reference](https://github.com/openai/codex/blob/main/codex-rs/app-server/README.md)).

## Install

```bash
npx -y mcp-codex-worker@latest
```

Add to Claude Code:

```json
{
  "mcpServers": {
    "codex-worker": {
      "command": "npx",
      "args": ["-y", "mcp-codex-worker@latest"],
      "env": {
        "CODEX_LB_API_KEY": "${CODEX_LB_API_KEY}"
      }
    }
  }
}
```

### Companion skill (optional)

```bash
npx -y skills add -y -g yigitkonur/skills-by-yigitkonur/skills/run-codex-subagents
```

## Requirements

- Node 22+
- `codex` CLI installed
- `CODEX_LB_API_KEY` or `OPENAI_API_KEY` in environment

## Tools

| Tool | Purpose |
|---|---|
| `spawn-task` | Create and start a task. Returns `task_id`, `disk_paths`, and "what to do next" guidance. |
| `wait-task` | Block until completion/failure/input. Returns output, liveness signals, and next actions. |
| `respond-task` | Answer agent questions (`user_input` only — approvals are auto-handled). |
| `message-task` | Send follow-up instructions to a running task. |
| `cancel-task` | Cancel one or more tasks (single or batch). |

### Model selection

Only `gpt-5.4` — pass the `reasoning` parameter:

| Value | Use case |
|---|---|
| `gpt-5.4(medium)` | Default. Most coding, refactors, debugging. |
| `gpt-5.4(high)` | Multi-file reasoning, subtle bugs, design decisions. |
| `gpt-5.4(xhigh)` | Deep research, novel architecture. |
| `gpt-5.4(low)` | Trivial mechanical edits. |

### Typical workflow

```
spawn-task { prompt: "..." }
  → { task_id: "bold-eagle-456", status: "working", disk_paths: {...} }
    ---
    **What to do next:**
    - Call `wait-task` with task_id to block until done.
    - If you have more tasks, launch them now — all run in parallel.

wait-task { task_id: "bold-eagle-456" }
  → { status: "completed", output: [...] }
    ---
    **What to do next:**
    - Read `task:///bold-eagle-456` for the full result.
```

No `respond-task` needed for command/file approvals — they're auto-approved instantly.

## Auto-Approval

The server auto-approves ALL Codex approval requests without waiting:

| Request | Response | Log |
|---|---|---|
| Command approval | `accept` | `[auto-approve] cmd: npm test` |
| File change | `accept` | `[auto-approve] file change` |
| MCP elicitation | `accept` | `[auto-approve] elicitation` |
| Permission request | `grant all for session` | `[auto-approve] permissions` |

Only `user_input` (agent asks a question) and `dynamic_tool` (external tool needs data) still pause the task.

Combined with `approval_policy = "never"` and `sandbox_mode = "danger-full-access"` from your `config.toml`, agents run fully autonomously.

## Reporting & Observability

Every task persists to `~/.mcp-codex-worker/tasks/<task-id>/`:

| File | Content |
|---|---|
| `meta.json` | Task state snapshot (refreshes every 10s during activity) |
| `summary.log` | Formatted one-liners: `[HH:MM:SS] cmd: npm test (exit 0, 1.2s)` |
| `verbose.log` | Full execution trace, streaming command output |
| `events.jsonl` | Raw Codex notification stream — every event with timestamp |

### MCP Resources

| URI | Content |
|---|---|
| `task:///all` | Scoreboard (auto-subscribed, push on change) |
| `task:///{id}` | Task detail with metadata |
| `task:///{id}/log` | Summary log |
| `task:///{id}/log.verbose` | Verbose log (reads from disk) |
| `task:///{id}/events` | Raw event trace (JSONL from disk) |

### Resource Subscriptions

```json
{ "resources": { "subscribe": true, "listChanged": true } }
```

- `task:///all` auto-subscribed at startup
- `notifications/resources/updated` on status changes (immediate) and output (throttled 1s)
- `notifications/resources/list_changed` on task creation

## Codex App-Server Integration

This server acts as a client to the [Codex app-server](https://github.com/openai/codex/blob/main/codex-rs/app-server/README.md) protocol. Key integration points:

| Feature | How we use it |
|---|---|
| `initialize` | `experimentalApi: true`, then `account/login/start` with API key |
| `thread/start` | Omit `approvalPolicy`/`sandbox` — config.toml takes effect |
| `turn/start` | Pass `effort` for reasoning level |
| Approval requests | Auto-respond via `respondToServerRequest()` |
| `turn/completed` | Captures turn status in summary log |
| `item/*` notifications | Event capture module processes 6 types into logs |
| `error` notification | Captures `codexErrorInfo` classification |
| stderr | Piped to verbose.log and events.jsonl for diagnostics |
| Process exit | Detects exit code/signal, classifies auth errors |

### Auth

On startup, sends `account/login/start` with `CODEX_LB_API_KEY` (or `OPENAI_API_KEY`) to switch from stale OAuth tokens to API key auth. This prevents the "refresh token already used" crash.

### Crash Recovery

On restart, loads all `meta.json` files from disk. Terminal tasks restore as-is. Non-terminal tasks (RUNNING, WAITING_ANSWER) are marked UNKNOWN since Codex sessions don't survive restarts.

## Wire States (SEP-1686)

| State | Meaning |
|---|---|
| `submitted` | Queued, not started |
| `working` | Agent executing |
| `input_required` | Paused — needs `user_input` or `dynamic_tool` response |
| `completed` | Done |
| `failed` | Error (includes AUTH_TOKEN_EXPIRED, RATE_LIMITED classifications) |
| `cancelled` | Interrupted by user |
| `unknown` | Crash recovery fallback |

## Environment Variables

| Variable | Description | Default |
|---|---|---|
| `CODEX_LB_API_KEY` | API key for codex-lb provider | — |
| `OPENAI_API_KEY` | Fallback API key | — |
| `CODEX_APP_SERVER_COMMAND` | Codex binary path | `codex` |
| `CODEX_APP_SERVER_ARGS` | App-server arguments | `app-server --listen stdio://` |
| `CODEX_HOME_DIRS` | Colon-separated profile roots for failover | `~/.codex` |
| `CODEX_ENABLE_FLEET` | Enable fleet mode (sub-agent instructions) | off |

## Development

```bash
npm install
npm run build        # TypeScript compile
npm test             # 158 unit tests
npm run smoke        # live Codex test (needs CODEX_LB_API_KEY)
npm run serve        # start locally
```

### Testing with mcpc

```bash
mcpc --config config.json cw connect @test
mcpc @test tools-list
mcpc @test resources-read "task:///all"
mcpc @test tools-call spawn-task '{"prompt":"echo hello","reasoning":"gpt-5.4(low)"}'
```

Use the local build (`node --import tsx src/index.ts`) for mcpc — `npx` has bridge startup timing issues.
