Skip to content

jonaspauleta/cursor-bridge

Repository files navigation

cursor-bridge

CI npm version npm provenance license: MIT node

A thin MCP server bridging coding-agent CLIs to Claude Code (Opus). It exposes two tools: run_cursor_agent, which offloads implementation/review tasks to Cursor's cursor-agent CLI (Composer 2.5 Fast by default), and generate_image, which generates/edits images with gpt-image-2 by driving the Codex CLI. The final review gate stays on Opus.

Use via npx (recommended)

Published as @jonaspauleta/cursor-bridge. No clone or build needed:

# one-off
CURSOR_BRIDGE_ALLOWED_ROOT="$(pwd)" npx -y @jonaspauleta/cursor-bridge

Register with Claude Code:

claude mcp add --transport stdio --scope project \
  --env CURSOR_BRIDGE_ALLOWED_ROOT="$(pwd)" \
  cursor-bridge -- npx -y @jonaspauleta/cursor-bridge

Or as project-scoped .mcp.json:

{
  "mcpServers": {
    "cursor-bridge": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@jonaspauleta/cursor-bridge"],
      "env": {
        "CURSOR_API_KEY": "${CURSOR_API_KEY:-}",
        "CURSOR_BRIDGE_ALLOWED_ROOT": "${CLAUDE_PROJECT_DIR}"
      }
    }
  }
}

You can also run straight from GitHub without npm: npx github:jonaspauleta/cursor-bridge (npx clones and builds via the prepare hook).

Global (user scope) — follow the active project

Register once at user scope to make the tools (including generate_image) available in every project, with the workspace following whichever project you're in:

claude mcp add --transport stdio --scope user \
  --env CURSOR_BRIDGE_ALLOWED_ROOT=cwd \
  cursor-bridge -- npx -y @jonaspauleta/cursor-bridge

CURSOR_BRIDGE_ALLOWED_ROOT accepts a sentinel — cwd or ${CLAUDE_PROJECT_DIR} — instead of a fixed path. The server resolves it to CLAUDE_PROJECT_DIR (which Claude Code sets to the active project), else its working directory — so one global registration follows you across projects. Prefer cwd: Claude Code does not expand ${CLAUDE_PROJECT_DIR} for user-scope servers, so that form still works (the server resolves it internally) but Claude Code logs a harmless "Missing environment variables" warning for it. An unset or relative value still fails loudly; it never implicitly widens to $HOME.

Prerequisites (not bundled): the cursor-agent CLI (for run_cursor_agent) and/or the codex CLI v0.134.0+ (for generate_image) must be installed on PATH and logged in (cursor-agent login / codex login). CURSOR_BRIDGE_ALLOWED_ROOT is required: either an absolute path, or the cwd / ${CLAUDE_PROJECT_DIR} sentinel for global use.

Build & run

npm install
npm run build          # -> dist/index.js
node dist/index.js     # stdio MCP server (Claude Code launches this for you)

Register with Claude Code (local development)

To develop against your local build instead of the published package, wire the built dist/ at project scope:

# Export CURSOR_API_KEY in your shell profile — do NOT put it on argv (ps/history leak).
claude mcp add --transport stdio --scope project \
  --env CURSOR_BRIDGE_ALLOWED_ROOT="$(pwd)" \
  cursor-bridge -- node dist/index.js

CURSOR_API_KEY is read from the ambient environment and never hardcoded or passed on a command line. If unset, cursor-agent falls back to your interactive cursor-agent login session. CURSOR_BRIDGE_ALLOWED_ROOT is required: an absolute path, or the cwd / ${CLAUDE_PROJECT_DIR} sentinel.

The tool: run_cursor_agent

input type default notes
prompt string task/prompt sent to the worker
cwd string working dir; validated against CURSOR_BRIDGE_ALLOWED_ROOT
mode default/plan/ask default default = read-write (--force); plan/ask = read-only
model string composer-2.5-fast allowlisted (composer-2.5-fast, composer-2.5, claude-4.6-sonnet-medium)
timeoutMs number 270000 wall-clock; wrapper SIGKILLs cursor-agent past this

Returns the worker's final text on SUCCESS (plus structuredContent with usage). Every other outcome returns isError: true with a taxonomy-tagged message.

The tool: generate_image

Generates or edits images with gpt-image-2 by driving codex exec with the $imagegen skill. Subscription-only: it uses your codex login (ChatGPT/Codex plan) auth and counts toward your Codex usage limits — no API key. OPENAI_API_KEY is scrubbed from the child env so an ambient key can't silently switch you to API billing.

input type default notes
prompt string image task; free-form, may include edit/iterate instructions
outputDir string <allowedRoot>/generated-images absolute, validated inside the allowed root
referenceImages string[] paths attached via Codex -i (edit/iterate); png/jpg/jpeg/webp, inside root, max 8
count number 1 1–10 (gpt-image-2 ceiling)
size enum auto auto/1024x1024/1536x1024/1024x1536 (best-effort directive)
quality enum auto auto/low/medium/high (best-effort directive)
inlineImages boolean false also return generated images as base64 blocks (first 4)
timeoutMs number 300000 wall-clock; wrapper SIGKILLs codex past this

Each call writes into a fresh <outputDir>/<runId>/ subdir. On SUCCESS it returns the generated file paths (and Codex's summary); every other outcome returns isError: true. size/quality/count are natural-language directives templated into the prompt (the built-in image_gen tool is invoked by the model, not via CLI flags), so they are best-effort rather than hard API parameters.

Status taxonomy: SUCCESS | NO_IMAGE | AUTH_REQUIRED | TIMEOUT | TOOL_ERROR. Success means ≥1 image file actually landed on disk — the exit code is not trusted.

Requirements: the codex CLI (v0.134.0+) must be installed and on the server's PATH, and you must be logged in (codex login; check with codex login status). Override the binary with CODEX_AGENT_BIN. Unlike cursor-agent, Codex's -s workspace-write sandbox is genuinely enforced, so the image worker can only write within the workspace root and cannot run destructive shell outside it.

Smoke test: npm run test:smoke:codex (live gpt-image-2 call; requires codex login).

Status taxonomy

SUCCESS | AUTH_REQUIRED | TIMEOUT | TOOL_ERROR | MALFORMED. Success requires a parsed {"type":"result"} envelope with is_error:false; the exit code is NOT trusted (the auth-failure path is exit-code-unstable).

Auth pre-flight

cursor-agent status --format json   # {"isAuthenticated":true,...}

The server exposes preflightAuth() for a fail-fast check before a real call.

Security notes

  • argv is always an array; spawn runs with no shell — no command injection via the wrapper.
  • All MCP-tool inputs pass src/validate.ts (mode/model allowlist, cwd allowlist + symlink-safe) before reaching argv. The git-diff SHAs used by the final review gate are NOT validated here — they live in the orchestrator's shell (Part B) and are resolved mechanically with git rev-parse, never taken from task text.
  • Secrets come from env only; the logger redacts secret-looking values and never logs prompt bodies or raw output (stderr only). Never pass CURSOR_API_KEY on a command line (ps/history leak) — export it in your shell profile so .mcp.json's ${CURSOR_API_KEY} picks it up.
  • CURSOR_BRIDGE_ALLOWED_ROOT is REQUIRED — an absolute path, or the cwd / ${CLAUDE_PROJECT_DIR} sentinel (follows the active project, for global/user-scope use). It never implicitly defaults to $HOME; the server refuses to start on an unset/relative value and logs the resolved root. Set it as narrowly as possible.
  • Blast radius — VERIFIED on cursor-agent v2026.05.28: --sandbox enabled does NOT contain a --force worker on this build. A probe worker wrote a file outside --workspace (into $HOME) despite --sandbox enabled. --mode plan/ask are genuinely read-only and safe. But mode:default passes --force (auto-approves arbitrary shell + writes) and --workspace is only a cwd, not a jail — so a default-mode worker is effectively full user-level shell: it can read ~/.ssh, exfiltrate over the network, or git push. The wrapper still passes --sandbox enabled (harmless future-proofing should a later build enforce it — re-run the Task A20 Step 5 probe to recheck), but today you MUST treat mode:default as unsandboxed and run workers ONLY in disposable/throwaway git worktrees with NO access to real secrets. The assertWorkspacePath allow-root and the Opus security gate are the real controls; cwd validation alone does not contain --force.

Tests

npm test               # unit + in-memory round-trip (no network)
npm run test:smoke     # RUN_CURSOR_SMOKE=1; live call to Composer 2.5 Fast

About

MCP server bridging cursor-agent + codex (gpt-image-2) to Claude Code

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors