Skip to content

jaredboynton/cursor-oauth-opencode

Repository files navigation

cursor-oauth-opencode

OpenCode plugin that connects to Cursor's API, giving you access to Cursor models inside OpenCode with full tool-calling support.

Install

npx cursor-oauth-opencode setup --global
opencode auth login --provider cursor

For project-local setup:

npx cursor-oauth-opencode setup --project
opencode auth login --provider cursor

The setup command is idempotent. It adds the npm plugin entry and fallback model registries for both provider.cursor and provider.cursor-code in opencode.json, preserving existing user model overrides. Login stays on the primary provider only (opencode auth login --provider cursor).

Providers

The plugin registers two OpenCode providers that share one OAuth login, proxy, and model catalog. Mode is selected in the model picker:

Provider Picker path Behavior
Cursor cursor/<model> Native tool passthrough (code mode OFF)
Cursor Code cursor-code/<model> Single code sandbox tool (code mode ON)

Breaking default: cursor/* is native-tools / code mode OFF. To keep the previous sandbox-collapse behavior, pick cursor-code/<model>. There is no auto-rewrite of a previously selected cursor/* model.

Fleet-wide kill switch (forces OFF even for cursor-code/*): set CURSOR_OPENCODE_CODE_MODE=0 or provider.cursor.plugin.codeMode.enabled: false. That knob is read only under provider.cursor.plugin — a block under provider.cursor-code.plugin has no effect.

Reasoning variants

Reasoning-tier Cursor models are listed once in the picker; effort is chosen in OpenCode's Select variant menu (not as separate model slugs):

Picker model Variants Notes
grok-4.5 / grok-4.5-fast low / medium / high Cursor slug suffixes are shifted (high…-xhigh)
claude-4.6-opus, gpt-5.4, glm-5.2, … only levels Cursor exposes e.g. opus → high, gpt-5.4 → medium
composer-2.5 / composer-2.5-fast default only Non-effort axis; stay as separate models

Legacy full slugs (grok-4.5-fast-high, …) still resolve as aliases. After upgrade, re-run setup so opencode.json seeds the collapsed base ids.

Manual config

If you do not want to use the setup command, add this to ~/.config/opencode/opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": [
    "cursor-oauth-opencode@latest"
  ],
  "provider": {
    "cursor": {
      "name": "Cursor",
      "npm": "@ai-sdk/openai-compatible",
      "api": "http://127.0.0.1:65535/v1",
      "models": {
        "composer-2.5-fast": {
          "name": "Composer 2.5 Fast",
          "reasoning": true,
          "temperature": true,
          "attachment": false,
          "tool_call": true,
          "limit": {
            "context": 200000,
            "output": 64000
          }
        }
      }
    },
    "cursor-code": {
      "name": "Cursor Code",
      "npm": "@ai-sdk/openai-compatible",
      "api": "http://127.0.0.1:65535/v1/code",
      "models": {
        "composer-2.5-fast": {
          "name": "Composer 2.5 Fast",
          "reasoning": true,
          "temperature": true,
          "attachment": false,
          "tool_call": true,
          "limit": {
            "context": 200000,
            "output": 64000
          }
        }
      }
    }
  }
}

The fallback API URLs are placeholders so OpenCode can list the providers before login. After auth, the plugin starts a local proxy and replaces Cursor models with live Cursor model discovery. cursor-code must keep the /v1/code path suffix (merge-safety if a request falls back to provider.api).

Authenticate

opencode auth login --provider cursor

This opens Cursor OAuth in the browser. Tokens are stored in ~/.local/share/opencode/auth.json and refreshed automatically. Both providers use that single cursor auth entry.

Use

Start OpenCode and select a model under Cursor (native tools) or Cursor Code (sandbox code tool). The plugin starts a local OpenAI-compatible proxy on demand and routes requests through Cursor's gRPC API.

How it works

  1. OAuth — browser-based login to Cursor via PKCE (cursor provider only).
  2. Model discovery — queries Cursor's gRPC API for all available models.
  3. Local proxy — translates chat completions into Cursor's protobuf/HTTP/2 Connect protocol. Path selects mode: /v1/* (native) vs /v1/code/* (sandbox).
  4. Code mode (cursor-code) — advertises a single code tool to the Cursor model; the model writes one async JavaScript program that the proxy runs in a Node child sandbox, bridging each await tools.X() wave to OpenCode's tools while the Cursor bridge stays parked. cursor/* passes client tools through directly as MCP tools.

HTTP/2 transport runs through a Node child process (h2-daemon.mjs / legacy h2-bridge.mjs) because Bun's node:http2 support is not reliable against Cursor's API.

Prompt shaping (caveman + reasoning containment)

On every outbound Cursor Run the proxy can:

  • Caveman-compress tool-description prose and the OpenCode system prompt (plugin.caveman.level / CURSOR_OPENCODE_CAVEMAN, default full; system inherits via plugin.caveman.system / CURSOR_OPENCODE_CAVEMAN_SYSTEM).
  • Append a verbatim reasoning guard for runaway-reasoning models (claude-fable-5, claude-opus-4-8; CURSOR_OPENCODE_REASONING_GUARD=0).
  • Inject a coalesced harness appendix (interstitial text, overthink <system-reminder>, throttled continuity, single-shot [reasoning tail] / [thinking exhaustion] notes) for those same models.

Savings counters live under CURSOR_OPENCODE_SAVINGS=1 (plugin log file).

Architecture

OpenCode  -->  /v1/chat/completions       (cursor = code OFF)
          -->  /v1/code/chat/completions  (cursor-code = code ON)
                                              |
                                    Bun.serve (proxy)
                                              |
                                    Node child (h2-daemon / h2-bridge)
                                              |
                                     HTTP/2 Connect stream
                                              |
                                    api2.cursor.sh gRPC
                                      /agent.v1.AgentService/Run

Tool call flow (code mode, cursor-code)

1. Proxy advertises ONE code tool to the Cursor model (its description embeds
   OpenCode's real tool catalog)
2. Model emits code({script}); proxy runs the script in a Node child sandbox
3. Each await tools.X() wave -> proxy emits OpenAI tool_calls SSE, parks BOTH
   the Cursor bridge and the sandbox
4. OpenCode executes the tools, sends results in the follow-up request
5. Proxy feeds results to the parked sandbox; the next wave repeats step 3
6. Script returns -> its value becomes the code tool result; the Cursor bridge
   resumes and streams the model's final answer

With cursor/* (or the kill switch forcing OFF) the proxy passes each client tool through directly: the model calls a tool via mcpArgs, the proxy emits OpenAI tool_calls, pauses the H2 stream, and resumes with mcpResult on the follow-up request.

Develop locally

bun install
bun run build
bun test/smoke.ts

Logs

Plugin diagnostics never print to the terminal (they would paint over the OpenCode TUI). They land in ~/.cache/cursor-oauth-opencode/plugin.log. Override the path with CURSOR_OPENCODE_LOG_FILE; set CURSOR_OPENCODE_LOG_STDERR=1 to also mirror lines to stderr when debugging outside the TUI.

Requirements

About

OpenCode plugin for Cursor OAuth and models

Resources

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors