Skip to content

jonwadsworth/codex-bridge

Repository files navigation

Codex Bridge

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.

Why

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.

Architecture

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 exec as 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.

MCP tools

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.

Install

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.sh

The 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:

  1. Point a reverse proxy or tunnel (Cloudflare Tunnel, nginx+certbot, etc.) at http://localhost:8427 for your domain — Codex Bridge only binds loopback.
  2. Add https://<your-domain>/mcp as a custom connector in claude.ai (Settings → Connectors → Add custom connector), and sign in with the credential the installer printed.

Push-to-deploy (optional)

.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:

  1. Generate a dedicated SSH keypair — don't reuse an existing admin key.
  2. Add the public half to /root/.ssh/authorized_keys on 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...
    
  3. Add the private half as the ATLAS_CODEXBRIDGE_DEPLOY_KEY secret on the GitHub repo, and the server's hostname/IP as ATLAS_HOST.

Security model

  • Every request to the MCP server is OAuth-authenticated — no anonymous access.
  • codex_delegate's working_dir is 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, default workspace-write) — Codex Bridge never passes --dangerously-bypass-approvals-and-sandbox.
  • ~/.codex/auth.json and the server's own OAuth credential are secrets — never logged, never committed. .gitignore excludes .env/*.db by 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.

Known limitations (v1)

  • Single operator, single Codex identity, one server — no multi-tenancy.
  • No codex_review tool yet (mirroring /review from the official plugin) — tracked as a stretch goal.
  • No session resume support (codex exec resume) yet — codex_status/ codex_result report the session_id Codex 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=process in the systemd unit), but the exit code is unavailable — it's reported as done with 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.

About

Self-hosted MCP server that lets claude.ai delegate tasks to OpenAI Codex CLI, billed through a ChatGPT subscription

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors