A self-hosted MCP server that lets claude.ai (and other MCP clients) delegate work to OpenAI Codex CLI — billed through the operator's existing ChatGPT subscription, not per-token API usage.
Claude Code can already shell out to Codex CLI locally (via codex-plugin-cc)
because it has a local shell. claude.ai has no shell — custom MCP connectors
are reached from Anthropic's cloud over HTTPS, with no way to run a local CLI.
Codex Bridge closes that gap: a small always-on server, designed to run on a
personal VPS, that exposes Codex CLI as MCP tools over HTTPS using a
ChatGPT-authenticated Codex CLI session running on the server itself.
claude.ai ──HTTPS(OAuth 2.1)──▶ Codex Bridge MCP Server ──subprocess──▶ Codex CLI ──ChatGPT session──▶ OpenAI
(Anthropic's cloud) (your VPS) (codex exec)
- MCP server: Python, MCP Python SDK (
FastMCP) directly — no separate web framework. Streamable HTTP transport. - Job manager: wraps
codex execas a detached subprocess per job. State (queued/running/done/errored/cancelled) and captured stdout/stderr paths persist in SQLite, so a server restart doesn't orphan job tracking. Every job is confined to an explicit working-directory allowlist — the tools never accept an arbitrary filesystem path. - Auth: OAuth 2.1 (dynamic client registration + PKCE), the only thing claude.ai's Connectors feature actually speaks. One resource owner (username/password you set at install time), tokens persisted to SQLite.
| Tool | Purpose |
|---|---|
codex_delegate(prompt, working_dir, model?) |
Submit a task, returns a job_id immediately |
codex_status(job_id) |
Cheap poll — job state and timestamps |
codex_result(job_id, max_chars?) |
Tailed stdout/stderr once the job is done or errored |
codex_cancel(job_id) |
Cancel a running or queued job |
codex_delegate never blocks on the Codex run — MCP tool calls must return
quickly, and Codex jobs can run for minutes. Submit, then poll.
Requires a Linux box you control (tested against Ubuntu). You'll need root.
git clone https://github.com/jonwadsworth/codex-bridge.git /opt/codex-bridge
cd /opt/codex-bridge
sudo ./setup/install.shThe installer is idempotent — checks for/installs uv, Node, and Codex CLI;
runs codex login (you complete the ChatGPT sign-in yourself, in your own
browser — the installer never touches your credentials); prompts for your
domain, a working-directory allowlist, and a login credential; generates
/etc/codex-bridge/env; installs and starts the systemd service on
127.0.0.1:8427.
You still need to do two things it can't do for you:
- Point a reverse proxy or tunnel (Cloudflare Tunnel, nginx+certbot, etc.) at
http://localhost:8427for your domain — Codex Bridge only binds loopback. - Add
https://<your-domain>/mcpas a custom connector in claude.ai (Settings → Connectors → Add custom connector), and sign in with the credential the installer printed.
.github/workflows/deploy.yml SSHes into your server and runs
deploy/deploy.sh (git pull && uv sync && systemctl restart) on every push
to main. To enable it:
- Generate a dedicated SSH keypair — don't reuse an existing admin key.
- Add the public half to
/root/.ssh/authorized_keyson your server, prefixed with a forced command so this key can only ever run that one script:command="/opt/codex-bridge/deploy/deploy.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA... - Add the private half as the
ATLAS_CODEXBRIDGE_DEPLOY_KEYsecret on the GitHub repo, and the server's hostname/IP asATLAS_HOST.
- Every request to the MCP server is OAuth-authenticated — no anonymous access.
codex_delegate'sworking_diris checked against a fixed allowlist (CODEXBRIDGE_WORKDIR_ALLOWLIST) set at install time — never an arbitrary path.- Job submission is rate-limited (
CODEXBRIDGE_MAX_CONCURRENT_JOBS,CODEXBRIDGE_RATE_LIMIT_PER_HOUR) to bound both cost and blast radius. - Every job also runs under Codex CLI's own command-execution sandbox
(
--sandbox,CODEXBRIDGE_SANDBOX_MODE, defaultworkspace-write) — Codex Bridge never passes--dangerously-bypass-approvals-and-sandbox. ~/.codex/auth.jsonand the server's own OAuth credential are secrets — never logged, never committed..gitignoreexcludes.env/*.dbby default.- The optional CI deploy key is scoped with a forced SSH command, so even a leaked key can only re-run the fixed deploy script, not arbitrary commands.
- This is a personal-use bridge, not a resale or multi-tenant proxy — OpenAI's ToS govern what you do with a ChatGPT-authenticated Codex session accessed this way. Don't share your instance's credential with anyone whose usage you wouldn't want counted against your own plan.
- Single operator, single Codex identity, one server — no multi-tenancy.
- No
codex_reviewtool yet (mirroring/reviewfrom the official plugin) — tracked as a stretch goal. - No session resume support (
codex exec resume) yet —codex_status/codex_resultreport thesession_idCodex CLI assigns each run (parsed from its exec banner), but nothing in Codex Bridge uses it to resume. - Headless login (
codex login) needs either--device-auth(requires Device Code Authorization enabled in your ChatGPT account's Security Settings) or an SSH-tunneled browser flow — the installer won't attempt it for you, see its printed instructions. - If the service restarts while a job is running, the job survives
(
KillMode=processin the systemd unit), but the exit code is unavailable — it's reported asdonewith a note, since the reparented process can no longer be waited on for a real exit status. - Job history/log storage on disk has no retention/cleanup policy yet — will grow unbounded under heavy use.