# codex-review MCP server

The Codex reviewer bridge for ARIS.

## Why this exists

ARIS drove its Codex reviewer with `codex mcp-server`. Codex CLI 0.155.0
**removed that subcommand**: `codex --help` no longer lists it and the binary
contains no trace of the string. Because it is no longer recognised, the old
invocation is parsed as a prompt for the interactive CLI, which dies with
`Error: stdin is not a terminal` — and since the ARIS row sets
`failOnStartupError: true`, that failure aborted the whole Harness plugin tree
and dsh would not start at all.

Codex still ships `codex app-server`, a JSON-RPC service over stdio. It is not
an MCP server, so it cannot be dropped in directly; this bridge translates.

## Shape

```
dsh -- MCP (stdio) --> server.py -- app-server protocol (stdio) --> codex app-server
```

It exposes the same two tools the old server did, so nothing downstream of the
MCP boundary changes:

| tool | behaviour | app-server calls |
|---|---|---|
| `codex` | start a session, run one turn, return the reply | `thread/start` → `turn/start` |
| `codex-reply` | continue an existing thread by id | `thread/resume` (only if unseen) → `turn/start` |

Every successful call returns `structuredContent.threadId`. ARIS reads that
field to continue a review thread, which the Debate Protocol requires — the
harness only renders MCP `content` to the model, so the bridge returns both.

One `codex app-server` child is spawned on first use and kept alive for the
process lifetime: threads live inside it, and recycling it would make
previously returned threadIds unresumable.

## Configuration

Mounted by `dsh/cordis.patch.yml` in the ARIS bundle:

```yaml
- id: aris-codex
  name: '@deepseek-ai/dsh-mcp-client'
  config:
    transport: stdio
    serverName: codex
    command: python
    args: [<...>/mcp-servers/codex-review/server.py]
    cwd: !!js process.env.HOME
    toolCallTimeoutMs: 1200000
    failOnStartupError: true
```

`cwd` is pinned to a directory that outlives the run, so the reviewer never
depends on the Harness launch directory still existing.

## Environment overrides

| variable | default | purpose |
|---|---|---|
| `CODEX_BIN` | vendored `codex.exe` under the npm global root | CLI to launch |
| `CODEX_REVIEW_CWD` | `$HOME` | default session working directory |
| `CODEX_REVIEW_TIMEOUT_SEC` | `1200000` | per-turn ceiling (ms) |
| `CODEX_REVIEW_DEBUG` | unset | set to `1` to log every frame to `codex-mcp-debug.log` |
| `CODEX_REVIEW_SERVER_NAME` | `codex` | MCP `serverInfo.name` |

## Testing

```
python test_bridge.py
```

Drives the bridge over MCP exactly as dsh does — `initialize`, `tools/list`,
then a `codex` call followed by a `codex-reply` on the returned threadId — and
asserts both succeed. A passing run prints `RESULT: OK` and proves the MCP
surface, the app-server translation, and thread continuation together.
