Files
fusion/plugins/fusion-plugin-cursor-runtime
gsxdsm 5e5b0dbb8f FN-9098: bridge scoped Fusion tools into Cursor
Publish engine-owned Fusion tools to Cursor through a crash-safe, worktree-scoped MCP bridge.

- preserve operator MCP configuration with locking, journaling, quarantine, and lease reconciliation
- enforce identity-scoped fn_* provenance so injected custom and MCP tools are never exposed
- secure loopback dispatch with per-session tokens, heartbeats, cleanup, and normalized tool events
- document the Cursor contract and cover bridge lifecycle, config hygiene, and failure handling

Files changed:
 .changeset/fn-9098-cursor-mcp-bridge.md            |   7 +
 docs/cursor-cli-contract.md                        | 140 ++-------------
 docs/mcp.md                                        |   4 +
 .../src/__tests__/agent-session-helpers.test.ts    |  24 +++
 .../src/__tests__/step-session-executor.test.ts    |  16 ++
 .../src/__tests__/web-fetch-universal.test.ts      |   4 +-
 packages/engine/src/agent-heartbeat.ts             |   3 +-
 packages/engine/src/agents/agent-runtime.ts        |   9 +
 .../engine/src/agents/agent-session-helpers.ts     |  26 +--
 packages/engine/src/execution/reviewer.ts          |   1 +
 .../engine/src/execution/step-session-executor.ts  |  31 ++--
 .../engine/src/executor/execute-workflow-step.ts   |   4 +-
 packages/engine/src/merger.ts                      |   4 +-
 plugins/fusion-plugin-cursor-runtime/README.md     |  18 +-
 plugins/fusion-plugin-cursor-runtime/package.json  |   2 +-
 .../src/__tests__/cursor-mcp-config.test.ts        | 100 +++++++++++
 .../cursor-mcp-server-failure.stream.jsonl         |   3 +
 .../fixtures/cursor-mcp-tool-call.stream.jsonl     |   4 +
 .../src/__tests__/runtime-adapter.test.ts          |  57 +++++-
 .../src/__tests__/worktree-hygiene.test.ts         |  52 ++++++
 .../src/cursor-mcp-config.ts                       | 196 +++++++++++++++++++++
 .../src/mcp-schema-server.cjs                      | 155 ++++++++++++++++
 .../src/prompt-transport.ts                        |   4 +-
 .../src/runtime-adapter.ts                         |  67 +++++--
 .../src/tool-bridge.ts                             |  48 +++++
 .../src/tool-mapping.ts                            |  11 ++
 plugins/fusion-plugin-cursor-runtime/src/types.ts  |   6 +-
 .../src/worktree-hygiene.ts                        | 117 ++++++++++++
 28 files changed, 934 insertions(+), 179 deletions(-)

Fusion-Task-Id: FN-9098

Fusion-Task-Lineage: 11b6cb10-ce0e-4f33-9007-c83f2bbf82ea

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-08-15 16:51:54 -07:00
..
2026-08-13 01:41:54 -07:00

fusion-plugin-cursor-runtime

Cursor CLI-backed provider/runtime plugin for Fusion.

Contract summary

  • Provider ID: cursor-cli
  • Binary probes: cursor-agent, then cursor
  • Expected failure states: missing binary, missing Cursor IDE install, locked macOS keychain, unauthenticated runtime
  • Model discovery: cursor-agent models (plain text id - Label output; no --json support) with header/tip/empty-state filtering, dedupe, and fallback metadata
  • Auth status: cursor-agent status --format json (isAuthenticated), probed against the same candidate binary that succeeded --version

Notes

Status/auth and model discovery behavior follows docs/cursor-cli-contract.md.

External Integration Evidence

  • Canonical upstream repository: Cursor CLI is closed-source and has no canonical upstream source repository. Its public issue tracker is https://github.com/cursor/cursor.
  • Docs / homepage: https://cursor.com/docs/cli/overview
  • Release / download: curl https://cursor.com/install -fsS | bash (macOS/Linux/WSL), or irm 'https://cursor.com/install?win32=true' | iex (Windows PowerShell).
  • Binary: cursor-agent
  • Checksum: upstream-pending-verification; Cursor publishes no versioned checksum manifest. Verified local provenance: 2026.08.11-e8db854 on 2026-08-15.

Execution transport contract

Fusion runs one supervised cursor-agent --print --output-format stream-json turn per prompt. The prompt is supplied on stdin, the process cwd is the Fusion task worktree, and the init event confirmed that cwd is the Cursor workspace without a --workspace argument. Stream JSON emits init, thinking, assistant, tool_call, and terminal result events; session IDs are retained with --resume on the next turn.

Fusion tool mode Cursor flags
coding --force --trust
readonly or unset --mode plan --trust

--print already grants built-in write and shell tools. --force controls approval, so it is limited to coding sessions whose cwd is Fusion's isolated task worktree. Fusion does not use --auto-review, worktree, add-dir, plugin-dir, or sandbox override flags.

Fusion MCP bridge

When a session has Fusion fn_* custom tools, Fusion starts a token-protected loopback bridge and stages a per-session stdio entry in the task worktree's .cursor/mcp.json. Cursor receives --approve-mcps only after that lease is staged. The stdio child receives FUSION_CURSOR_TOOL_BRIDGE_URL and FUSION_CURSOR_TOOL_BRIDGE_TOKEN; mcp-schema-server.cjs must be copied into the built package.

Fusion records the original config before its first write, persists live server entries in .cursor/.fusion-mcp-state.json, and removes its entry on disposal. The config is excluded from git while a lease is live. A git-tracked .cursor/mcp.json disables the bridge rather than risking a step-boundary commit. If an operator makes the config unparsable during a session, Fusion quarantines that worktree and leaves the config and exclusion untouched; repair the JSON and remove fusion-custom-tools-* entries (or delete the config), then the next Cursor session reconciles it.

Worktree hygiene and recovery

Fusion may briefly create a git-dir fusion-cursor-exclude.lock during bootstrap, then .cursor/.fusion-mcp.lock while a session composes the config. Both are excluded before they exist. The state record can contain a pending journal after a crash; the next Cursor session resolves it from exact config bytes. A hard-killed lease is reaped by its heartbeat TTL, not by assuming an exit hook ran. A final empty .cursor/ directory is removed with a single non-recursive attempt after its nested lock is released; a peer race leaves it for the next reconciliation.

Quarantined configuration

A lane reports bridge-start-failed when .cursor/.fusion-mcp-state.json contains a quarantine record. Fusion deliberately refuses to rewrite that config and keeps its info/exclude marker, because the malformed file can still contain fusion-custom-tools-* entries that must not enter git. Do not delete the state file by hand. Instead repair mcp.json and remove every Fusion entry, or delete mcp.json; the next Cursor session clears quarantine and removes the marker automatically.

All turns use superviseSpawn with a finite lifetime. The Windows prompt transport prefers a direct executable; .cmd/.bat shims validate and reject cmd metacharacters before a quoted cmd launch, .ps1 uses PowerShell -File, and unknown extensions fail loudly. PI_CURSOR_CLI_FIRST_LINE_TIMEOUT_MS and PI_CURSOR_CLI_TIMEOUT_MS optionally tune cold-start and inactivity guards.