Skip to main content
Glama
cybas
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
```