Skip to content

yelixir-dev/cursor-ai-proxy-bridge

Repository files navigation

🌐 English · 한국어

Cursor AI Bridge

Cursor AI Bridge read-only dashboard

OpenAI-compatible gateway for local Cursor AI automation, with a safe read-only operations dashboard.

MVP status Node.js 20+ OpenAI-compatible API Read-only dashboard MIT License

Cursor AI Bridge is a trusted-environment HTTP bridge that exposes a small OpenAI-compatible API in front of Cursor's local CLI/agent backend. It keeps local automation behind a Fastify security boundary, client API-key auth, and a read-only operations dashboard.

Important

Cursor AI Bridge does not bundle Cursor credentials, tokens, or a hardware-ID reset feature. Use it only with your own Cursor CLI/account environment and expose it only on localhost or a trusted VPN/tailnet.

At a glance

Area Summary
API surface /health, /dashboard, /v1/models, /v1/chat/completions
Core value OpenAI-compatible clients can call a Cursor-backed local bridge instead of managing Cursor process invocation themselves.
Dashboard Mobile-friendly, read-only status page with backend, model, workspace, auth, and endpoint information.
Safety boundary /v1/* fails closed without a configured client API key; real workspace access is explicit opt-in.
Current scope MVP: deterministic mock backend plus Cursor CLI backend adapter; non-streaming and SSE streaming chat completions.

One-shot local preview:

npm install
CURSOR_BRIDGE_API_KEY=sk-curbr-local-dev \
CURSOR_BRIDGE_BACKEND=mock \
npm run build && npm start

Then open:

http://127.0.0.1:9994/dashboard

A healthy preview shows a read-only dashboard and returns OpenAI-compatible model/chat responses from the mock backend.

What this bridge does

  • Provides OpenAI-compatible endpoints:
    • GET /health
    • GET /dashboard
    • GET /v1/models
    • POST /v1/chat/completions
  • Requires client API-key auth for /v1/* through either:
    • Authorization: Bearer <CURSOR_BRIDGE_API_KEY>
    • x-api-key: <CURSOR_BRIDGE_API_KEY>
  • Returns 503 configuration_error on /v1/* when CURSOR_BRIDGE_API_KEY is not configured.
  • Ships a deterministic mock backend for dashboard/API smoke tests without Cursor login state.
  • Includes a cursor-cli backend adapter for local Cursor CLI/agent execution.
  • Defaults to chat-only temporary workspace mode so real project files are not mounted by default.
  • Supports explicit real-workspace mode only when a real workspace path is configured and valid.
  • Uses Fastify with Helmet/CSP, body limits, rate limiting, and Zod request validation.
  • Normalizes OpenAI content-part arrays such as [{"type":"text","text":"..."}] into plain text before calling Cursor CLI.
  • Instructs Cursor CLI to emit strict JSON when a tool is needed, then converts valid Cursor output into standard OpenAI tool_calls.
  • Avoids credential input forms, token display, credential persistence UI, and reset-hwid behavior.

Architecture

OpenAI-compatible client
  -> Cursor AI Bridge :9994
  -> Cursor CLI / agent backend
  -> normalized OpenAI chat.completion response
flowchart LR
  C[OpenAI-compatible client] -->|Bearer / x-api-key| B[Cursor AI Bridge]
  D[Read-only dashboard] -->|status only| B
  B --> H[/health]
  B --> M[/v1/models]
  B --> X[/v1/chat/completions]
  X --> W{Workspace mode}
  W -->|default| T[Temporary chat-only directory]
  W -->|explicit opt-in| R[Real workspace path]
  X --> A[Cursor CLI backend]
Loading

The bridge keeps the HTTP/auth/dashboard boundary separate from Cursor upstream authentication. Cursor login/session material should remain owned by the local Cursor CLI environment, not by this dashboard.

Requirements

  • Node.js 20+
  • npm 10+
  • macOS, Linux, or WSL for source operation
  • Cursor CLI/account environment for real cursor-cli backend use
  • A configured client-facing CURSOR_BRIDGE_API_KEY for /v1/* traffic

For UI/API development and smoke testing, the mock backend does not require Cursor login.

Installation

git clone <your-cursor-ai-bridge-repository-url> cursor-ai-bridge
cd cursor-ai-bridge
npm install
cp .env.example .env

Minimal local .env:

CURSOR_BRIDGE_HOST=127.0.0.1
CURSOR_BRIDGE_PORT=9994
CURSOR_BRIDGE_API_KEY=replace-with-a-long-random-client-key
CURSOR_BRIDGE_BACKEND=mock
CURSOR_BRIDGE_WORKSPACE_MODE=chat-only

Build and run:

npm run build
npm start

For a real Cursor-backed run, switch the backend. Some Cursor installations expose the CLI binary as cursor; on the Oracle/systemd host it may be installed as agent, and local Cursor Agent installs may expose cursor-agent, so point CURSOR_BRIDGE_CURSOR_BIN at the executable that works in that environment.

CURSOR_BRIDGE_BACKEND=cursor-cli
CURSOR_BRIDGE_CURSOR_BIN=/home/ubuntu/.local/bin/agent
CURSOR_BRIDGE_DEFAULT_MODEL=composer-2.5
CURSOR_BRIDGE_CURSOR_TIMEOUT_MS=600000

The cursor-cli backend passes --print --trust for headless chat completions and deliberately omits --mode. With the regular cursor binary it runs cursor agent --print ...; with a standalone binary named agent it runs agent --print ... and omits the duplicate subcommand. --trust prevents headless workspace-trust prompts from blocking systemd runs, while omitting --mode keeps Cursor Agent in its writable default headless mode instead of the read-only ask or plan modes.

Cursor Agent backed requests can take longer than ordinary HTTP model calls. In production, use a 600s-class bridge timeout for composer-2.5; a shorter upstream timeout can surface as a router failure even when the underlying agent would have completed successfully.

When exposing composer-2.5 through LiteLLM, set model metadata, request timeouts, and a model-group fallback explicitly so downstream OpenAI-compatible clients see the intended context budget and LiteLLM has a safe route when the agent backend times out:

model_list:
  - model_name: composer-2.5
    litellm_params:
      model: openai/composer-2.5
      api_base: http://127.0.0.1:9994/v1
      api_key: os.environ/CURSOR_BRIDGE_API_KEY
      request_timeout: 600
      timeout: 600
    model_info:
      max_input_tokens: 200000
      max_tokens: 200000
      context_window: 200000

litellm_settings:
  request_timeout: 600
  fallbacks:
    - composer-2.5:
        - <fallback-model-group>

Without a composer-2.5 fallback, LiteLLM may return an error such as No fallback model group found for original model_group=composer-2.5 when the agent route exceeds its timeout.

First verification

Health check:

curl -fsS http://127.0.0.1:9994/health

Authenticated model list:

export CURSOR_BRIDGE_API_KEY="$YOUR_CURSOR_BRIDGE_API_KEY"

curl -fsS http://127.0.0.1:9994/v1/models \
  -H "Authorization: Bearer [BRIDGE_CLIENT_TOKEN]"

Non-streaming chat completion:

curl -sS http://127.0.0.1:9994/v1/chat/completions \
  -H "Authorization: Bearer [BRIDGE_CLIENT_TOKEN]" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "cursor-fast",
    "messages": [{"role": "user", "content": "Reply exactly: OK"}],
    "temperature": 0
  }'

SSE streaming chat completion:

curl -N -sS http://127.0.0.1:9994/v1/chat/completions \
  -H "Authorization: Bearer $CURSOR_BRIDGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "cursor-fast",
    "stream": true,
    "messages": [{"role": "user", "content": "Reply in chunks"}]
  }'

OpenAI content-part array requests are also accepted and normalized to plain text for the text-only Cursor CLI backend:

curl -sS http://127.0.0.1:9994/v1/chat/completions \
  -H "Authorization: Bearer $CURSOR_BRIDGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "composer-2.5",
    "messages": [
      {
        "role": "user",
        "content": [{"type": "text", "text": "Reply exactly: OK"}]
      }
    ]
  }'

Image blocks are represented as [image omitted: cursor composer bridge is text-only] because this bridge currently targets text chat completion semantics, not multimodal Cursor automation. Unsupported typed blocks are represented as [unsupported content type omitted: <type>], and each message may include up to 1,000 content parts.

LiteLLM model entry example:

model_name: composer-2.5
litellm_params:
  model: openai/composer-2.5
  api_base: http://127.0.0.1:9994/v1
  api_key: os.environ/CURSOR_BRIDGE_API_KEY

Web dashboard

Open:

http://127.0.0.1:9994/dashboard

The dashboard is intentionally read-only. It can show:

  • bridge version, uptime, and request counters;
  • backend mode and backend health;
  • auth configured/not-configured state without printing the API key;
  • workspace safety mode;
  • available model IDs;
  • curl examples with redacted key placeholders.

It does not include a key input/save UI. If admin writes are added later, they should use a separate admin policy and keep /v1/* client authentication fail-closed.

Configuration

Variable Default Notes
CURSOR_BRIDGE_HOST 127.0.0.1 HTTP bind address. Keep local-only unless behind trusted network controls.
CURSOR_BRIDGE_PORT 9994 HTTP port.
CURSOR_BRIDGE_API_KEY unset Required for /v1/*; missing key returns 503 configuration_error.
CURSOR_BRIDGE_BACKEND mock mock or cursor-cli.
CURSOR_BRIDGE_DEFAULT_MODEL cursor-fast Default model and /v1/models discovery entry when custom (for example composer-2.5).
CURSOR_BRIDGE_WORKSPACE_MODE chat-only chat-only or real-workspace.
CURSOR_BRIDGE_REAL_WORKSPACE unset Required only for real-workspace; path must exist.
CURSOR_BRIDGE_CURSOR_BIN cursor Cursor CLI executable name/path; set to /home/ubuntu/.local/bin/agent or /Users/yorha/.local/bin/cursor-agent when using standalone agent binaries.
CURSOR_BRIDGE_CURSOR_TIMEOUT_MS 120000 Clamped to 1 second–10 minutes.

Workspace safety

Default mode:

CURSOR_BRIDGE_WORKSPACE_MODE=chat-only

In this mode, each request runs through a temporary chat-only directory. This is the safe default for bridge experiments because it avoids exposing a real project checkout to automated requests.

Real workspace mode must be explicit:

CURSOR_BRIDGE_WORKSPACE_MODE=real-workspace
CURSOR_BRIDGE_REAL_WORKSPACE=/absolute/path/to/project

The configured path must exist. Do not bind a sensitive workspace unless the calling client and network boundary are trusted.

Client authentication

CURSOR_BRIDGE_API_KEY is the client-facing bridge key, not a Cursor upstream credential.

CURSOR_BRIDGE_API_KEY=replace-with-a-long-random-client-key

Supported request headers:

Authorization: Bearer <key>
x-api-key: <key>

Security behavior:

  • /health and /dashboard are unauthenticated read-only status endpoints.
  • /v1/models and /v1/chat/completions require the client key.
  • If the client key is unset, /v1/* returns 503 instead of opening the bridge.
  • Raw keys and Cursor auth material are never printed by the dashboard.

Development

npm run verify

The quality gate runs:

  • TypeScript typecheck
  • ESLint
  • Prettier format check
  • Vitest tests
  • production build

Useful commands:

npm run dev
npm test
npm run typecheck
npm run lint
npm run build
npm audit --omit=dev

Security notes

  • Treat this as a trusted-environment bridge, not a public internet service.
  • Keep CURSOR_BRIDGE_HOST=127.0.0.1 by default.
  • If binding to 0.0.0.0, place it behind a trusted VPN/tailnet/private proxy and keep a strong CURSOR_BRIDGE_API_KEY.
  • Do not log or commit .env, Cursor auth files, tokens, or API keys.
  • Keep real workspace mode off unless the caller is trusted.

License

MIT. See package.json for the current package license declaration.

About

No description, website, or topics provided.

Resources

Stars

7 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors