Cursor MCP Server Shows Disconnected or No Tools

Added an MCP server in Cursor but it stays disconnected, or no tools appear in chat. 90% of the time it's a bad PATH, a JSON typo, or a stdout leak. Diagnose and fix in five minutes.

You added an MCP server to Cursor — filesystem, GitHub, a custom one — and the status dot stays red. Or it goes green but no tools show up in chat. Or it connects on launch and drops a few minutes later. Cursor’s MCP layer is thin: it spawns a process, speaks JSON-RPC over stdio (or hits a remote HTTP/SSE endpoint), and registers whatever tools the server advertises. When it breaks, the cause is almost always in the spawn (wrong path, missing runtime), the config file (a JSON typo that voids the whole file), the handshake (the server leaked text onto stdout), or the transport (stdio shape used for a remote URL, or vice versa).

Fastest fix that resolves most cases: open the latest entry in the MCP logs (Output panel, Cmd/Ctrl + Shift + U, then pick MCP Logs from the dropdown), read the first error line, then (a) use an absolute path for command, and (b) run your mcp.json through python3 -m json.tool to catch a stray comma. Those two cover the majority of disconnects as of June 2026.

Where things live (June 2026)

Cursor renamed the panel in early 2026. The current paths:

  • Settings panel: Cmd/Ctrl + Shift + J opens Cursor Settings; the section is now labeled Tools & MCP (older builds called it Features → MCP). There is also a master Enable MCP servers switch that ships off in some installs — check it first.
  • Add a server via UI: Tools & MCP → + Add New MCP Server opens a dialog with three fields: Name, Transport Type (stdio / SSE / Streamable HTTP), and Command or URL. This writes to mcp.json for you.
  • Config file (global): ~/.cursor/mcp.json — applies to every project.
  • Config file (project): .cursor/mcp.json in the repo root — shared with your team. If both exist, both load.
  • Logs: Output panel (Cmd/Ctrl + Shift + U) → MCP Logs channel. This is where the real error string (ENOENT, JSON parse error, auth failure, crash) shows up.

Common causes

Ordered by hit rate, highest first.

1. A JSON typo silently voids the whole file

A single trailing comma, missing quote, or unbalanced brace makes Cursor ignore the entire mcp.json — no error popup, every server just vanishes. This is the most common “nothing shows up at all” cause.

How to judge: run a parser, not your eyes:

python3 -m json.tool ~/.cursor/mcp.json   # or: jq . ~/.cursor/mcp.json

If it prints an error and a line number, that’s it. If it pretty-prints the file, the JSON is valid and the bug is elsewhere.

2. Command not on PATH (spawn ENOENT)

You configured "command": "npx" or "command": "uvx", but a Cursor launched from the Dock/Start menu does not source your shell rc, so the nvm/fnm/asdf/Homebrew PATH entry is missing. The server never starts even though the exact command works in your terminal.

How to judge: in MCP Logs, look for spawn npx ENOENT, spawn uvx ENOENT, or command not found. That string is this bug, every time.

3. Stdio server printed to stdout instead of stderr

An MCP stdio server must reserve stdout for JSON-RPC frames only. A banner, log line, or warning on stdout makes Cursor read malformed JSON and disconnect.

How to judge: run the server command manually in a terminal. Anything non-JSON on stdout is the bug. All diagnostics must go to stderr.

4. Wrong transport shape in mcp.json

A remote server needs url (+ headers); a local one needs command + args. Mixing them — a url under a stdio-shaped entry, or command on a remote one — fails silently.

How to judge: open mcp.json. Stdio entries use command / args / env; remote entries use url / headers and a transport of streamable-http or sse. The UI’s Transport Type field must match the keys.

5. Server needs env vars Cursor did not pass

GitHub’s local server wants GITHUB_PERSONAL_ACCESS_TOKEN; custom servers want API keys. Setting them in your shell rc does nothing — the spawned process only sees what’s under the env key (or in a file referenced by envFile).

How to judge: run the server command outside Cursor with the same env exported. If it works there but not in Cursor, env is the gap.

6. Tools loaded but disabled in chat

Tools & MCP shows green and a tool count, but the model never calls a tool. Cursor exposes a per-tool toggle in the tools list at the top of the chat panel, and new tools can default to off.

How to judge: open the tools list at the top of the chat panel. If your server’s tools are listed but toggled off, flip them on.

7. Cursor cached a failed handshake

After you fix the underlying issue, Cursor sometimes keeps the server stuck in a failed state until you toggle it.

How to judge: Tools & MCP → toggle the server off, wait ~3 seconds, toggle it on. If it connects now, that was the symptom.

Which bucket are you in?

Symptom in the UIMost likely causeJump to
No servers at all show upJSON typo voids file, or master toggle offCause 1, panel toggle
One server red, spawn ... ENOENT in logsCommand not on PATHCause 2, Step 2
Green dot then drops after a minuteServer crashed (often stdout leak)Cause 3, Step 4
Green dot, tool count = 0Handshake failed / wrong transportCause 4, Step 4
Green dot, tools exist, never calledTools disabled in chatCause 6, Step 7
Remote URL returns HTML/401/404Wrong URL or auth headerCause 4, Step 5

Before you start

  • Know whether your server is stdio (local process) or remote (HTTP/SSE) — they are configured differently.
  • Have the server’s README handy for the exact command, args, env vars, or url.
  • Debug one server at a time; two at once is twice the pain.

Step-by-step fix

Step 1: Validate the JSON, then run the server outside Cursor

First parse the file (python3 -m json.tool ~/.cursor/mcp.json). Then copy the command and args into a terminal and run them. A healthy stdio server prints nothing on stdout (or only JSON) and stays alive waiting for input. If it crashes immediately, the bug is in the server, not Cursor.

Step 2: Use an absolute path for the command

Replace "npx" with the full path. Find it with which npx (or where npx on Windows), then paste it in. Same for uvx, python, node. This is the single most reliable fix for spawn ENOENT.

{
  "mcpServers": {
    "filesystem": {
      "command": "/Users/you/.nvm/versions/node/v22.14.0/bin/npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you/projects"]
    }
  }
}

Step 3: Pass env explicitly (or use envFile)

Anything the server needs must be under env in the entry, or pulled from a file via envFile. Cursor does not inherit your shell environment for spawned MCP processes.

{
  "mcpServers": {
    "github-local": {
      "command": "/usr/local/bin/docker",
      "args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
      "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "github_pat_..." }
    }
  }
}

Note the env var is GITHUB_PERSONAL_ACCESS_TOKEN. The old @modelcontextprotocol/server-github npm package is deprecated; GitHub now ships an official server (Docker image above, or the hosted remote in Step 5).

Step 4: Read the MCP logs for the handshake

Output panel (Cmd/Ctrl + Shift + U) → MCP Logs. Search for your server name. You want to see an initialize request and a successful response. Common failures:

  • Failed to parse JSON / Unexpected token — the server leaked text onto stdout (fix the server to log to stderr).
  • spawn ... ENOENT — back to Step 2.
  • 0 tools or No tools or prompts — handshake completed but the server advertised nothing; check the server’s own startup args.

Step 5: For remote servers, prefer the hosted endpoint and verify it

GitHub’s hosted server is the least error-prone path — no runtime, no Docker. Use the url shape with a bearer header:

{
  "mcpServers": {
    "github": {
      "url": "https://api.githubcopilot.com/mcp/",
      "headers": { "Authorization": "Bearer github_pat_..." }
    }
  }
}

Confirm the endpoint independently before blaming Cursor:

curl -X POST https://api.githubcopilot.com/mcp/ \
  -H "Authorization: Bearer github_pat_..." \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'

A healthy response is JSON containing serverInfo and capabilities. HTML, a 401/403, or a 404 means the URL or token is wrong (regenerate the PAT with the right scopes). For servers that use OAuth instead of a static token, Cursor handles the browser flow and registers the redirect cursor://anysphere.cursor-mcp/oauth/callback.

Step 6: Toggle, then fully restart

Tools & MCP → toggle the server off, then on. If the change still doesn’t register, fully quit Cursor (Cmd+Q / quit from the tray — not just closing the window) and relaunch. MCP servers re-spawn on launch and on toggle, not on file save.

Step 7: Enable the tools in chat

Open the tools list at the top of the chat panel, find your server, and flip the per-server and per-tool toggles on. New tools default to off in some Cursor builds, which looks exactly like a broken server.

How to confirm it’s fixed

  • Tools & MCP shows a green dot and a tool count greater than zero.
  • MCP Logs shows initialize succeeding with no parse errors after it.
  • In chat, send a prompt that should trigger a tool (e.g. “List my GitHub repos”) and watch for a tool-call card that executes and returns.
  • Quit and relaunch Cursor; confirm the server reconnects automatically with the same tool count.

Long-term prevention

  • Pin server versions in args (e.g. @modelcontextprotocol/server-filesystem@2026.1.0), not floating tags, so a bad upstream release can’t break you overnight.
  • Keep mcp.json in version control without secrets; load tokens from envFile or the shell-wrapped runner instead.
  • Add a CI step that runs python3 -m json.tool .cursor/mcp.json so a typo never lands.
  • Document required env vars and scopes in your README next to the MCP block.
  • Prefer hosted/remote servers when a vendor offers one — fewer moving parts than a local runtime.

Common pitfalls

  • Editing mcp.json while Cursor is open and expecting a hot reload. It reads on launch and on toggle.
  • Confusing user-level ~/.cursor/mcp.json with workspace-level .cursor/mcp.json — both exist, both load, and a stale global entry can shadow your project one.
  • Letting a stdio server print “Server started on port 3000” to stdout. That one line breaks the protocol.
  • Using GITHUB_TOKEN when the GitHub server expects GITHUB_PERSONAL_ACCESS_TOKEN.
  • Assuming Cursor discovers tools added after launch. It does not poll; restart.

FAQ

  • Where is mcp.json? ~/.cursor/mcp.json for global, .cursor/mcp.json in a workspace for project scope. Both load if both exist.
  • Stdio vs remote — which should I pick? Stdio for local processes (filesystem, git). Remote (HTTP/SSE) for hosted or team-shared servers, like GitHub’s https://api.githubcopilot.com/mcp/. Remote avoids PATH and runtime headaches.
  • The whole list is empty after I edited the file. Why? Almost always a JSON syntax error voiding the file. Run python3 -m json.tool ~/.cursor/mcp.json. Also confirm the master Enable MCP servers toggle is on.
  • Why does the dot go red after a few minutes? The server process exited. Open MCP Logs or run the command manually to see the crash on stderr.
  • It works in my terminal but not in Cursor. Classic PATH gap — Cursor launched from the Dock doesn’t source your shell rc. Use an absolute command path (Step 2).
  • Can I share an MCP setup with my team? Yes — commit .cursor/mcp.json, keep secrets out (use envFile), and document required env vars and scopes in the README.

Tags: #Cursor #mcp #Troubleshooting #Debug