Skip to main content
Glama
lipey1

Cursor Agent MCP

by lipey1
README.md
<div align="center">

# πŸ–±οΈ Cursor Agent MCP

**A fast, hardened [Model Context Protocol](https://modelcontextprotocol.io) server that lets any MCP host (Claude Code, Claude Desktop, and others) drive the [Cursor Agent CLI](https://cursor.com/docs/cli).**

Offload heavy, repo‑aware "thinking" β€” search, analysis, planning, edits β€” from your host model to `cursor-agent`, keeping the host's context small and your token bill low.

[![Node](https://img.shields.io/badge/node-%E2%89%A518-3c873a?logo=node.js&logoColor=white)](https://nodejs.org)
[![MCP](https://img.shields.io/badge/MCP-stdio-6E56CF)](https://modelcontextprotocol.io)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Status](https://img.shields.io/badge/status-active-brightgreen.svg)]()

</div>

---

## Why this exists

Large hosts like Claude Code burn tokens when they read big codebases directly. This server exposes a set of **focused, verb-centric tools** (`chat`, `edit`, `analyze`, `search`, `plan`, `raw`) that delegate the heavy lifting to the Cursor Agent CLI with tight scopes and concise outputs β€” so the host stays cheap and fast.

It also fixes a very real papercut: on Linux, `cursor-agent -p` can take **60–90 seconds just to start** because it loads your desktop's MCP servers and syncs marketplace plugins before answering. This server ships a **`bare_config` mode** that runs the CLI against an isolated config directory, cutting cold starts to **~15 seconds** β€” without touching your real `~/.cursor` setup.

```mermaid
flowchart LR
    A[Claude / MCP host] -- stdio --> B[Cursor Agent MCP]
    B -- spawn --> C[cursor-agent CLI]
    C -- isolated CURSOR_CONFIG_DIR --> D[(no user MCPs/plugins<br/>fast startup)]
    C --> E[Model: auto / gpt-5 / composer-2]
```

---

## Highlights

- ⚑ **`bare_config` fast mode** β€” isolated `CURSOR_CONFIG_DIR` skips user MCPs/plugins (~90s β†’ ~15s on Linux).
- 🧰 **10 tools** β€” chat, edit, analyze, search, plan, raw, legacy run, plus async start/check/cancel for long jobs.
- πŸ”‘ **First-class auth & model** β€” pass `api_key` and `model` per call or via env; API keys are redacted in debug logs.
- 🧡 **Async jobs** β€” fire long tasks in the background and poll them without hitting tool-call timeouts.
- πŸ›‘οΈ **Hardened spawning** β€” `shell: false` (no injection), Zod-validated inputs, robust timeouts and optional idle-kill.
- πŸ”Œ **Host-agnostic** β€” works with Claude Code, Claude Desktop, or any stdio MCP client.

---

## Requirements

- **Node.js 18+** (tested through Node 22)
- **Cursor Agent CLI** on your `PATH` as `agent` or `cursor-agent` (or point to it with `CURSOR_AGENT_PATH`)
- A **Cursor API key** (`crsr_…`) if you use `bare_config` (an isolated config can't reuse the desktop login)

```bash
# verify the CLI is available
agent --version
```

Install the CLI from the [Cursor CLI docs](https://cursor.com/docs/cli) if it's missing.

---

## Installation

```bash
git clone https://github.com/lipey1/cursor-agent-mcp.git
cd cursor-agent-mcp
npm install        # or: npm ci
```

Run it directly (stdio):

```bash
node ./server.js
```

Most of the time you won't run it by hand β€” your MCP host launches it for you (see below).

---

## Configure your MCP host

Add an entry pointing at `server.js`. Recommended fast defaults:

```json
{
  "mcpServers": {
    "cursor-agent": {
      "command": "node",
      "args": ["/absolute/path/to/cursor-agent-mcp/server.js"],
      "env": {
        "CURSOR_AGENT_PATH": "/home/you/.local/bin/agent",
        "CURSOR_API_KEY": "crsr_your_key_here",
        "CURSOR_AGENT_MODEL": "auto",
        "CURSOR_AGENT_FORCE": "1",
        "CURSOR_AGENT_TRUST": "1",
        "CURSOR_AGENT_BARE_CONFIG": "1",
        "CURSOR_AGENT_TIMEOUT_MS": "0",
        "CURSOR_AGENT_ASYNC_MAX_MS": "0"
      }
    }
  }
}
```

> **Never commit your real key.** Put it in the host's MCP env (or your shell environment), not in a tracked file.

- **Claude Code**: add the block to your project's `.mcp.json`.
- **Claude Desktop**: add it under `mcpServers` in `claude_desktop_config.json`.

---

## The `bare_config` fast path

On Linux, the Cursor Agent CLI loads `~/.cursor/mcp.json` **and** syncs marketplace plugins (Prisma, Figma, Notion, …) before it answers β€” often **60–90 seconds** of pure startup, even for a one-line question.

Setting `CURSOR_AGENT_BARE_CONFIG=1` (or `bare_config: true` per call) points the CLI at an isolated `CURSOR_CONFIG_DIR` (`~/.cursor-agent-mcp` by default). It skips your desktop MCPs and plugins entirely.

| Configuration | Cold start | Notes |
|---|---:|---|
| Default (loads `~/.cursor`) | ~60–90s | Your real desktop MCPs + marketplace plugins |
| `bare_config: true` | **~15–20s** | Isolated config; your `~/.cursor` is untouched |
| + telemetry disabled (default) | **~15–20s** | Child gets `OTEL_SDK_DISABLED=true` (set `CURSOR_AGENT_KEEP_TELEMETRY=1` to opt back in) |

OpenTelemetry fan-out alone can add ~15–50s per call (CDN contacts on every spawn). This server disables it in the child process by default.

Because the isolated config has no saved login, **provide an API key** when using this mode.

---

## Tools

All tools share a **COMMON** set of arguments:

| Arg | Type | Description |
|---|---|---|
| `output_format` | `"text" \| "json" \| "markdown"` | Response format (default `text`) |
| `model` | `string` | CLI model id (`auto`, `gpt-5`, `composer-2`, …); overrides `CURSOR_AGENT_MODEL` |
| `api_key` | `string` | Cursor API key; prefer setting it via env |
| `force` | `boolean` | Pass `--force` (run shell without prompts) |
| `trust` | `boolean` | Pass `--trust` (default `true`) |
| `bare_config` | `boolean` | Use the isolated fast config |
| `config_dir` | `string` | Explicit `CURSOR_CONFIG_DIR` override |
| `cwd` | `string` | Working directory for the CLI |
| `executable` | `string` | Explicit path to the CLI binary |
| `extra_args` | `string[]` | Extra argv passed through |
| `echo_prompt` | `boolean` | Prepend the effective prompt to the result |

| Tool | Purpose |
|---|---|
| `cursor_agent_chat` | One-shot chat with a prompt |
| `cursor_agent_edit_file` | Prompt-based file edit (diff or apply) |
| `cursor_agent_analyze_files` | Analyze one or more paths |
| `cursor_agent_search_repo` | Code search with include/exclude globs |
| `cursor_agent_plan_task` | Produce a numbered plan for a goal |
| `cursor_agent_raw` | Escape hatch: pass raw argv to the CLI |
| `cursor_agent_run` | Legacy single-shot chat (kept for compatibility) |
| `cursor_agent_start` | Start a long task in the background β†’ `job_id` |
| `cursor_agent_check` | Poll a background `job_id` |
| `cursor_agent_cancel` | Kill a background job |

### Examples

**Chat (fast mode, explicit model):**

```json
{
  "name": "cursor_agent_chat",
  "arguments": {
    "prompt": "Who created React?",
    "model": "auto",
    "bare_config": true
  }
}
```

**Scoped code search:**

```json
{
  "name": "cursor_agent_search_repo",
  "arguments": {
    "query": "fetch(",
    "include": ["src/**/*.ts", "app/**/*.tsx"],
    "exclude": ["node_modules/**", "dist/**"],
    "output_format": "markdown"
  }
}
```

**Long task without timeouts:**

```json
// 1) start
{ "name": "cursor_agent_start", "arguments": { "prompt": "Refactor the auth module and add tests", "label": "auth-refactor" } }
// β†’ returns { "job_id": "job_1_..." }

// 2) poll until status is completed/failed
{ "name": "cursor_agent_check", "arguments": { "job_id": "job_1_...", "full": true } }
```

---

## Environment variables

| Variable | Meaning |
|---|---|
| `CURSOR_AGENT_PATH` | Absolute path to `agent` / `cursor-agent` (default: `agent` on PATH) |
| `CURSOR_API_KEY` / `CURSOR_AGENT_API_KEY` | API key passed as `--api-key` and into the child env |
| `CURSOR_AGENT_MODEL` | Default model (`--model`) |
| `CURSOR_AGENT_FORCE` | `"1"`/`"true"` β†’ inject `--force` |
| `CURSOR_AGENT_TRUST` | `"1"`/`"true"` β†’ inject `--trust` (default **true**) |
| `CURSOR_AGENT_BARE_CONFIG` / `CURSOR_AGENT_FAST` | `"1"` β†’ isolated `CURSOR_CONFIG_DIR` |
| `CURSOR_AGENT_BARE_CONFIG_DIR` | Where the bare config lives (default `~/.cursor-agent-mcp`) |
| `CURSOR_AGENT_CONFIG_DIR` | Always use this `CURSOR_CONFIG_DIR` (even without the bare flag) |
| `CURSOR_AGENT_TIMEOUT_MS` | Hard runtime ceiling per call (default `30000`); `"0"` disables |
| `CURSOR_AGENT_ASYNC_MAX_MS` | Max lifetime for async jobs (default `1800000`); `"0"` disables |
| `CURSOR_AGENT_IDLE_EXIT_MS` | Idle-kill threshold; `"0"` disables (recommended) |
| `CURSOR_AGENT_KEEP_TELEMETRY` | `"1"` β†’ keep CLI OpenTelemetry on; default is off (`OTEL_SDK_DISABLED=true` in the child) |
| `CURSOR_AGENT_ECHO_PROMPT` | `"1"` β†’ prepend the prompt to the result |
| `DEBUG_CURSOR_MCP` | `"1"` β†’ stderr diagnostics (API keys redacted) |

---

## Quick smoke test

A tiny stdio client is included:

```bash
# list tools and call chat
node ./test_client.mjs "Hello from smoke test"

# fast mode + explicit key
CURSOR_AGENT_BARE_CONFIG=1 \
CURSOR_API_KEY="crsr_your_key" \
node ./test_client.mjs "Say only OK"

# call the raw tool with --help (no implicit --print)
TEST_TOOL=cursor_agent_raw TEST_ARGV='["--help"]' node ./test_client.mjs
```

---

## Troubleshooting

| Symptom | Fix |
|---|---|
| `agent not found` | Set `CURSOR_AGENT_PATH` or add the CLI to `PATH` |
| ~60–90s before the first token | Enable `CURSOR_AGENT_BARE_CONFIG=1` or `bare_config: true` |
| Auth error / 401 | Set `CURSOR_API_KEY` (or `CURSOR_AGENT_API_KEY`), or pass `api_key` per call |
| Cut off mid-answer | Raise `CURSOR_AGENT_TIMEOUT_MS` or set it to `"0"` to disable; keep `CURSOR_AGENT_IDLE_EXIT_MS=0` |
| Empty output | Verify the model id and credentials; try `cursor_agent_raw` with `argv: ["--version"]` |

---

## Security notes

- Child processes are spawned with `shell: false` β€” no shell injection or quoting pitfalls.
- All tool inputs are validated with [Zod](https://zod.dev).
- API keys passed via argv are **redacted** in debug logs; prefer env over per-call `api_key`.
- `bare_config` isolates only the CLI's config directory β€” it never modifies your real `~/.cursor`.
- `.gitignore` excludes `.env`, keys, and the bare config dir so secrets don't get committed.

---

## Manager skill (`/cursor-agent on|off`)

Optional skill so **Claude Code / Claude Desktop local Code** acts as manager: it briefs Cursor Agent, waits, and only reviews the result. When off, Claude does the work itself.

Not for Cursor IDE (you are already the Cursor Agent there).

The slash command name is the **skill folder name** β†’ `/cursor-agent`.

```bash
chmod +x skills/cursor-agent/install.sh
./skills/cursor-agent/install.sh
```

Then open a **new** Claude Code session (or `/reload-skills`) and type `/` β†’ pick **`cursor-agent`**.

Examples: `/cursor-agent on` Β· `/cursor-agent off` Β· `/cursor-agent status`.

Details: [skills/cursor-agent/README.md](skills/cursor-agent/README.md).

---

## Project layout

```
cursor-agent-mcp/
β”œβ”€β”€ server.js          # MCP server: tools, spawning, async jobs
β”œβ”€β”€ test_client.mjs    # stdio smoke-test client
β”œβ”€β”€ package.json
β”œβ”€β”€ skills/
β”‚   └── cursor-agent/   # slash command: /cursor-agent
β”œβ”€β”€ misc/              # Host/agent instruction docs (cost-aware usage)
β”œβ”€β”€ LICENSE
└── README.md
```

---

## Credits

This project builds on the original [`sailay1996/cursor-agent-mcp`](https://github.com/sailay1996/cursor-agent-mcp).
Enhancements in this fork β€” model/API-key options, `bare_config` fast startup, `--trust` handling, async job hardening, and this documentation β€” by **[Felipe Estrela](https://github.com/lipey1)**.

## License

[MIT](LICENSE) β€” see the license file for details.

TDQS

B3/5.0

Scored across 10 tools

Disambiguation4/5

Most tools have distinct purposes (chat, edit, analyze, search, plan, raw, async start/check/cancel). However, cursor_agent_chat and cursor_agent_run both perform chat, though the latter is marked as legacy, causing potential confusion.

Naming Consistency4/5

All tools share the 'cursor_agent_' prefix and use snake_case. Most follow a verb_noun pattern (e.g., chat, edit_file, analyze_files, search_repo, plan_task), but 'raw' and 'run' are verb-only, which is a minor inconsistency.

Tool Count5/5

With 10 tools, the set is well-scoped for the domain of interacting with a Cursor agent. It covers common operations without being too sparse or overwhelming.

Completeness4/5

The tool set covers core interactions (chat, file editing, code search, analysis, planning, async jobs, raw access). There are no obvious dead ends, though some advanced IDE operations might be missing, but they are not central to the agent's purpose.

Maintenance

ActivitySlowing
ResponsivenessNo issues