Skip to main content
Glama
README.md
# codex-mcp

**Expose the Codex engine as MCP tools, so any MCP-capable agent can use it — including teams that cannot use Codex directly.**

Codex is a strong coding engine: it plans, edits files, runs commands, and keeps a thread alive. But getting an OpenAI account, a payment method, and stable network access is not possible for everyone. Codex itself supports custom OpenAI-compatible providers, which means the engine can run on a domestic model (DeepSeek, Qwen, or any compatible endpoint).

This project wraps `codex app-server` in a local MCP server. Any agent that speaks MCP over stdio — DSH, WorkBuddy/CodeBuddy, Trae, Qoder, Claude Desktop, Cursor — can call Codex as tools, with approvals, resume, usage and event polling.

```
your agent  ──MCP(stdio)──▶  codex-mcp  ──JSON-RPC──▶  codex app-server  ──▶  provider
```

---

## Why not just use Codex directly?

| Situation | Direct Codex | codex-mcp |
|---|---|---|
| You already live in another agent (DSH, WorkBuddy, Trae, Qoder) | Switch tools and lose the session | Codex becomes a tool inside your agent |
| OpenAI signup / payment / network is a blocker | Cannot start | Point Codex at a domestic provider and keep the engine |
| You need approvals before commands run | Terminal prompts only | `codex_start` + `codex_poll` + `codex_approve` over MCP |
| You want a long-running thread | One terminal session | Thread id persists; `codex_resume` continues it |
| You want usage and event progress | Terminal UI only | `codex_poll` returns items, commands, approvals, token usage |

It is not a replacement for the agent's own planning loop. It exposes the Codex execution engine as a tool.

---

## Tools

| Tool | Arguments | Purpose |
|---|---|---|
| `codex_run` | `prompt`, `cwd?`, `model?`, `sandbox?`, `context?`, `timeoutSec?` | Blocking run; auto-approves; returns final text, usage, thread id |
| `codex_start` | `prompt`, `cwd?`, `model?`, `sandbox?`, `approvalPolicy?`, `context?` | Start a thread/turn and return immediately |
| `codex_poll` | `threadId`, `cursor?` | Read new events, status, text, usage, pending approvals |
| `codex_approve` | `threadId`, `approvalId`, `decision` | Answer an approval: `accept`, `acceptForSession`, `decline`, `cancel` |
| `codex_interrupt` | `threadId` | Interrupt the running turn |
| `codex_resume` | `sessionId`, `prompt`, `cwd?`, `model?`, `sandbox?`, `timeoutSec?` | Continue an existing thread and wait |

`codex_run` is the simple path. `codex_start` → `codex_poll` → `codex_approve` is the interactive path: the host can show progress and let a human approve each command.

---

## Requirements

- Node.js 18 or newer
- Codex CLI installed and on `PATH` (or set `CODEX_EXE`)
- A Codex provider home (`CODEX_HOME`) with a `config.toml`
- An API key for that provider, passed through an environment variable

```bash
npm install -g @openai/codex
```

---

## Provider setup (DeepSeek example)

`CODEX_HOME/config.toml`:

```toml
model = "deepseek-chat"
model_provider = "deepseek"

[model_providers.deepseek]
name = "DeepSeek"
base_url = "https://api.deepseek.com/v1"
env_key = "DEEPSEEK_API_KEY"
wire_api = "chat"
```

Then export the key for the process that launches the MCP server:

```bash
export DEEPSEEK_API_KEY=...        # macOS / Linux
$env:DEEPSEEK_API_KEY = "..."      # Windows PowerShell
```

The server also falls back to `deepseekApiKey` in `~/.my-agent/credentials.json` if the environment variable is empty. It never logs or writes the key.

Any OpenAI-compatible provider works the same way; change `base_url`, `env_key`, and `model`.

---

## Environment variables

| Variable | Meaning |
|---|---|
| `CODEX_EXE` | Path or command for the Codex binary. Default: `codex` |
| `CODEX_HOME` | Provider home containing `config.toml`. Default: Codex's own default |
| `DEEPSEEK_API_KEY` | Optional; used when the provider requires it |
| `MY_AGENT_HOME` | Optional; overrides `~/.my-agent` for the credentials fallback |

---

## Client configuration

The server is a standard stdio MCP server. The only portable part of every config is:

```
command: node
args:    ["<absolute-path>/server-appserver.mjs"]
```

### DSH

```yaml
- insert:
    - id: codex-mcp
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: codex
        transport: stdio
        command: node
        args:
          - C:/path/to/codex-mcp/server-appserver.mjs
        env:
          CODEX_EXE: codex
          CODEX_HOME: C:/path/to/your/codex-home
        toolCallTimeoutMs: 1800000
        failOnStartupError: true
```

`toolCallTimeoutMs` matters: a Codex turn can run far longer than the MCP client's default 60 seconds.

### WorkBuddy / CodeBuddy

Put this in the project root (or pass it with `--mcp-config`):

```json
{
  "mcpServers": {
    "codex": {
      "command": "node",
      "args": ["C:/path/to/codex-mcp/server-appserver.mjs"],
      "env": {
        "CODEX_EXE": "codex",
        "CODEX_HOME": "C:/path/to/your/codex-home"
      }
    }
  }
}
```

See `mcp.example.json`. WorkBuddy CLI does not auto-load a project-root `.mcp.json`; pass `--mcp-config` or configure the desktop connector.

### Trae / Qoder / Claude Desktop / Cursor

Add the same `command` / `args` / `env` block in the host's MCP settings. No server-side change is needed.

---

## Compatibility

- **Protocol:** MCP `2024-11-05` over stdio, verified with a handshake test.
- **Any stdio MCP client:** the server does not depend on DSH-specific APIs.
- **Tested hosts:** DSH and WorkBuddy/CodeBuddy. Trae, Qoder, Claude Desktop and Cursor use the same stdio contract, but each host has its own configuration surface.
- **Long turns:** set a tool timeout of at least 30 minutes; otherwise the client may kill a legitimate Codex run.

Run the protocol test without spending model tokens:

```bash
node test-handshake.mjs
# initialize ok, protocol 2024-11-05
# tools: codex_approve, codex_interrupt, codex_poll, codex_resume, codex_run, codex_start
```

Full tests (these do call the provider):

```bash
node test-appserver.mjs   # codex_run + protocol
node test-start.mjs       # start/poll/approve
```

---

## Project instructions and context

Before starting a thread, the server reads, in order:

- `~/.dsh/AGENTS.md`
- `~/.agents/AGENTS.md`
- `AGENTS.md` / `AGENTS.local.md` from the project root down to `cwd`

They are passed as Codex `developerInstructions`, capped at 32 KB. The optional `context` argument appends task-specific memory or a handoff brief.

---

## Security

- The API key is passed only to the Codex child process; it is never logged or written to disk.
- Sandbox mode per call: `read-only`, `workspace-write`, `danger-full-access`.
- Two approval layers remain: the host's approval for the MCP tool call, and Codex's own approval policy for commands. `codex_start` lets the host approve Codex commands, but the two models are not unified.
- Do not expose this server over a network transport without adding authentication.

---

## Limits

- **Tool-level, not a loop replacement.** Your agent still plans; Codex executes inside one thread.
- **No token-level streaming.** `codex_poll` gives event-level progress, not the native TUI stream.
- **No native Codex UI.** Rollout view, plan mode, and the TUI are not reproduced.
- **Two ecosystems.** Codex's own MCP servers and skills live in `CODEX_HOME`; your agent's tools are separate.

---

## License

MIT — see [LICENSE](LICENSE).