cursor-agent-bridge
by cybas
README.md
# Cybas Agents Bridge
> **⚠️ WARNING:** This MCP server gives a connected AI agent the ability to read,
> edit, and (with durable authorization) run local commands in configured
> workspaces on your machine. Only connect trusted MCP clients. Never expose
> HTTP mode on a public network without authentication, Origin allowlisting,
> `CURSOR_ALLOWED_WORKSPACES`, and a loopback bind (`CURSOR_BRIDGE_HOST`,
> default `127.0.0.1`) behind a tunnel.
An MCP server that lets Claude Code / ChatGPT (or any MCP client) hand off coding
tasks to the local [Cursor Agent CLI](https://docs.cursor.com/cli), with durable
workstream authorization, named sessions, and async jobs.
## Setup
```json
{
"mcpServers": {
"cursor-agent-bridge": {
"command": "node",
"args": ["/path/to/cursor-agent-bridge/index.js"]
}
}
}
```
Requires the `cursor-agent` CLI on `PATH` (or `CURSOR_AGENT_PATH`).
State directory defaults to `~/.cursor-agent-bridge` (`CURSOR_BRIDGE_STATE_DIR`).
Do not store bridge state inside a public git repo.
## Tools (v3.1)
| Tool | Purpose |
|------|---------|
| `cursor_agent_help` | Read-only operator guide for workflows, job states, recovery, auth, and sessions |
| `cursor_agent_delegate` | Sync Cursor task; `session_name` + optional `authorization_id` |
| `cursor_agent_start_job` / `_job_status` / `_job_inspect` / `_job_result` / `_cancel_job` | Durable long-running jobs and restart-aware recovery |
| `cursor_agent_sessions` / `_session_forget` / `_session_terminate` | Named sessions (`builder`, `reviewer`, …) |
| `cursor_agent_authorize` / `_authorizations` / `_revoke_authorization` | Durable workstream authz |
| `cursor_agent_local_exec` | Allowlist-primary local `execFile` under `process.local` |
| `cursor_agent_diagnostic_exec` | Narrow `diagnostic.exec` (version/`-c` import checks, git read-only) |
| `cursor_agent_git_inspect` | Structured read-only git inspection |
| `cursor_agent_diff` | Legacy convenience wrapper around inspect |
| `cursor_agent_commit_plan` | Validate-only commit plan → immutable `plan_id` |
| `cursor_agent_commit` | Prefer `plan_id` + `confirmed=true` (legacy files path still works) |
| `cursor_agent_push` | Push only; requires `expected_head_sha` + `branch`; remote **name** only |
Typical workflow: authorize → delegate/job → `git_inspect` → `commit_plan` → show plan →
`commit(plan_id)` → inspect commit → approve push → push.
For long-running work, prefer `cursor_agent_start_job`. Save the returned `job_id` and
retrieve the result later with `cursor_agent_job_result`; do not continuously poll. If a
job is `orphaned` or legacy `lost` after an MCP/bridge restart, call `cursor_agent_job_inspect`
and retrieve its persisted result before retrying. These states do not prove that the
remote Cursor worker failed.
An agent that is near its context limit must return `CONTEXT_NEAR_FULL`; start a fresh
named session with `new_session: true` for the next unrelated task.
### Commit plans
`cursor_agent_commit_plan` snapshots HEAD, branch, file content hashes, and dirty-set
without mutating the index. `cursor_agent_commit({ plan_id, confirmed: true })` re-checks
HEAD/branch/hashes/empty index/expiry before staging.
## Diagnosing HTTP 405
Bridge stderr logs safe request lines: `method path … status=…`.
1. Restart the new bridge process behind the tunnel.
2. Trigger the ChatGPT connector once.
3. If you see `[http] … POST /mcp …` the request reached Express.
4. If ChatGPT reports 405 but **no** bridge log line appears, the 405 is upstream
(Cloudflare / tunnel / wrong URL / Access), not the MCP transport.
5. If the log shows another method (e.g. `PUT`/`DELETE`) with `status=405`, Express
is correctly rejecting it (`Allow: GET, POST, OPTIONS`).
6. `OPTIONS /mcp` is handled (204) for CORS preflight when Origin is allowlisted.
`GET /healthz` — liveness only (no secrets/paths).
## Authorization model
Call `cursor_agent_authorize` with `confirmed=true` after human approval. The
bridge returns an `authorization_id` that later calls must present. Capabilities
are never silently broadened.
**Level-2 local** (recommended default):
- capabilities: `files.read`, `files.write`, `process.local`, `git.read`,
`git.stage_selected`, `git.commit`
- `network=deny`, `ssh=deny`
`process.local` does **not** enable Cursor `--force --sandbox disabled`. It is
**allowlist-primary** (python/node/git/npm/pytest/…). Prefer
`cursor_agent_diagnostic_exec` for narrow version/import checks. Unrestricted Cursor
(shell+network+SSH conflated by the CLI) requires `network=allow` and the
`network` capability (high risk).
## Named sessions
Sessions are keyed by `workspace + session_name`. A fresh `reviewer` session
does not overwrite or resume `builder`.
## HTTP mode
```bash
export CURSOR_BRIDGE_TOKEN=...
export CURSOR_ALLOWED_WORKSPACES=/abs/path/one,/abs/path/two
export CURSOR_BRIDGE_ALLOWED_ORIGINS=https://chatgpt.com
export CURSOR_BRIDGE_HOST=127.0.0.1 # default
PORT=8787 node index.js --http
```
See `start-http.example.sh`. Copy to a gitignored local launcher and keep secrets
in `.env.local` / `.http_token`.
HTTP mode **refuses to start** if `CURSOR_ALLOWED_WORKSPACES` is empty.
Cloudflare Access: set `CF_ACCESS_TEAM_DOMAIN`, `CF_ACCESS_AUD` (required for
assertion audience enforcement), and optionally `CF_ACCESS_ALLOWED_EMAIL`.
`GET /healthz` — liveness only (no secrets/paths).
## Important limitations
Cursor CLI only exposes `--sandbox enabled|disabled` and `--force`. There is no
separate “local shell but no network/SSH” switch. The bridge therefore:
- keeps commit/push as bridge-owned git actions;
- runs Level-2 local commands through allowlisted `cursor_agent_local_exec` and a
narrower `cursor_agent_diagnostic_exec` profile;
- documents that allowlisted interpreters may still open sockets.
Clients that already loaded the MCP server must reconnect to see schema changes.
## Tests
```bash
npm test
```
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues