Skip to main content
Glama
benzkittisak

codex-async-mcp

by benzkittisak
README.md
# agent-async-mcp

Local MCP server that runs Codex, Cursor, and Gemini CLI tasks asynchronously — returns a `job_id` immediately instead of blocking, so the orchestrating agent never hits the MCP 60-second timeout.

## How it works

```
Claude (orchestrator)
  │
  ├─ codex_start(prompt, cwd)  →  job_id (instant)
  │
  └─ codex_wait(job_id)        →  blocks up to 50 s, returns result
                                   loop again on timeout
```

A sequential queue ensures only one agent process runs at a time. Jobs are persisted in SQLite so the queue survives server restarts.

---

## Install

```bash
curl -fsSL https://raw.githubusercontent.com/benzkittisak/claude-codex-mcp/master/install.sh | bash
```

The installer will:
- Clone this repo to `~/.local/share/agent-async-mcp/`
- Create an isolated Python venv
- Symlink `agent-async` to `~/.local/bin/`
- Detect Claude Code, Codex, Cursor, Claude Desktop and ask which to register

**Uninstall:**

```bash
curl -fsSL https://raw.githubusercontent.com/benzkittisak/claude-codex-mcp/master/install.sh | bash -s uninstall
# or, if already installed:
agent-async uninstall
```

---

## CLI

```bash
agent-async list-agents              # show detected / registered agents
agent-async add-agent claude-code    # register with Claude Code CLI
agent-async add-agent codex          # register with Codex CLI
agent-async add-agent cursor         # register with Cursor IDE
agent-async add-agent claude-desktop # register with Claude Desktop
agent-async remove-agent <agent>     # unregister
agent-async status                   # open real-time job monitor
agent-async update                   # pull latest + reinstall
agent-async check-update             # check without installing
agent-async enable-auto-update       # schedule daily auto-update (09:00)
agent-async disable-auto-update      # remove scheduled auto-update
agent-async uninstall                # remove everything
```

---

## Requirements

- Python 3.11+
- One or more agent CLIs: `codex`, `cursor`, `gemini` (optional — only needed for the tools you use)
- Claude Code CLI (recommended orchestrator)

---

## MCP Tools (13 total)

### Codex

| Tool | Description |
|------|-------------|
| `codex_start(prompt, cwd, approval_policy?, context_files?)` | Queue a Codex task → returns `job_id` instantly |
| `codex_wait(job_id, timeout_seconds=50)` | Block until done; loop on `{"status":"timeout"}` |
| `codex_await_any(timeout_seconds=50)` | Block until ANY queued job completes |

### Cursor

| Tool | Description |
|------|-------------|
| `cursor_start(prompt, cwd, approval_policy?, context_files?)` | Queue a Cursor headless task → `job_id` |
| `cursor_wait(job_id, timeout_seconds=50)` | Block until done |

### Gemini

| Tool | Description |
|------|-------------|
| `gemini_start(prompt, cwd, approval_policy?, context_files?)` | Queue a Gemini CLI task → `job_id` |
| `gemini_wait(job_id, timeout_seconds=50)` | Block until done |
| `gemini_confluence_start(title, cwd, ...)` | Ask Gemini to draft/publish a Confluence page |
| `gemini_pr_start(cwd, pr_goal, ...)` | Ask Gemini to draft/publish a PR |

### Shared / Queue

| Tool | Description |
|------|-------------|
| `job_list(limit=20)` | List recent jobs (all agents), newest first |
| `job_cancel(job_id)` | Cancel running or pending job |
| `queue_status()` | `{"busy": bool, "pending_count": int}` |
| `agent_notify_done(job_id, summary?)` | Called BY an agent to signal completion |

### `approval_policy` values

| Value | Behavior |
|-------|----------|
| `full-auto` | No prompts, no sandbox (use for automation) |
| `auto-edit` | Auto-applies edits |
| `suggest` | Read-only — pauses for interactive input (avoid in automation) |

---

## Permissions (settings.local.json)

Add to your Claude Code project's `.claude/settings.local.json`:

```json
{
  "permissions": {
    "allow": [
      "mcp__agent-async__codex_start",   "mcp__agent-async__codex_wait",
      "mcp__agent-async__cursor_start",  "mcp__agent-async__cursor_wait",
      "mcp__agent-async__gemini_start",  "mcp__agent-async__gemini_wait",
      "mcp__agent-async__queue_status",  "mcp__agent-async__job_list",
      "mcp__agent-async__job_cancel",    "mcp__agent-async__agent_notify_done",
      "mcp__agent-async__codex_await_any"
    ]
  }
}
```

---

## Usage pattern

```python
# Start a job (returns immediately)
result = codex_start(
    prompt="In app/services/foo.rb line 42, change X to Y. Do not change anything else.",
    cwd="/path/to/repo",
    approval_policy="full-auto"
)
job_id = result["job_id"]

# Wait in a loop (each call blocks up to 50 s)
while True:
    result = codex_wait(job_id, timeout_seconds=50)
    if result["status"] == "timeout":
        continue
    break  # "done" | "error" | "cancelled"
```

---

## Job data

Jobs are persisted in `~/.agent-async/`:

```
~/.agent-async/
  queue.db          ← SQLite: job metadata, status, token usage
  jobs/<job_id>/
    output.txt      ← stdout + stderr from the agent process
```

---

## Troubleshooting

### `agent-async: command not found`

`~/.local/bin` not in PATH. Run:

```bash
source ~/.zshrc   # or ~/.bashrc
```

Or open a new terminal. The installer adds it automatically.

### `status: "error"` immediately after `*_start`

The agent CLI failed to start. Check output:

```bash
cat ~/.agent-async/jobs/<job_id>/output.txt
```

| Message | Fix |
|---------|-----|
| `command not found: codex` | Install codex: `npm install -g @openai/codex` |
| `command not found: gemini` | Install gemini CLI from github.com/google-gemini/gemini-cli |
| `permission denied` | `cwd` doesn't exist or is inaccessible |

### `status: "running"` forever

The subprocess is hung. Most common cause: `approval_policy="suggest"` waiting for interactive input. Always use `"full-auto"` for automation.

```bash
agent-async status   # open monitor to see live state
```

Cancel a stuck job:

```python
job_cancel(job_id="<job_id>")
```

### Old jobs filling up disk

```bash
find ~/.agent-async/jobs -maxdepth 1 -type d -mtime +7 -exec rm -rf {} +
```

---

## Project structure

```
agent-async-mcp/
├── install.sh
├── mcp-monitor.py
├── pyproject.toml
└── src/
    └── agent_async_mcp/
        ├── server.py       # MCP entry point, tool definitions
        ├── job_manager.py  # queue, spawn, wait, cancel
        ├── db.py           # SQLite schema + helpers
        ├── config.py       # paths, timeouts, agent binaries
        └── cli.py          # agent-async CLI
```

## Development

```bash
git clone https://github.com/benzkittisak/claude-codex-mcp
cd claude-codex-mcp
pip install -e ".[dev]"
pytest tests/ -v
```

TDQS

A4.2/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a distinct purpose: start, list, poll, and cancel. There is no overlap in functionality, and the descriptions clearly differentiate them.

Naming Consistency5/5

All tools follow a consistent 'codex_verb' pattern using snake_case, making it predictable for an agent to infer tool behavior from the name.

Tool Count5/5

Four tools cover the essential operations for managing async jobs (start, list, poll, cancel) without redundancy or missing critical actions.

Completeness5/5

The tool set covers the full lifecycle of an async job: initiating (start), monitoring (poll, list), and termination (cancel). No obvious gaps are present.

Maintenance

ActivityInactive
ResponsivenessNo issues