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 + Jopens 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 tomcp.jsonfor you. - Config file (global):
~/.cursor/mcp.json— applies to every project. - Config file (project):
.cursor/mcp.jsonin 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 UI | Most likely cause | Jump to |
|---|---|---|
| No servers at all show up | JSON typo voids file, or master toggle off | Cause 1, panel toggle |
One server red, spawn ... ENOENT in logs | Command not on PATH | Cause 2, Step 2 |
| Green dot then drops after a minute | Server crashed (often stdout leak) | Cause 3, Step 4 |
| Green dot, tool count = 0 | Handshake failed / wrong transport | Cause 4, Step 4 |
| Green dot, tools exist, never called | Tools disabled in chat | Cause 6, Step 7 |
| Remote URL returns HTML/401/404 | Wrong URL or auth header | Cause 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, orurl. - 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 toolsorNo 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
initializesucceeding 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.jsonin version control without secrets; load tokens fromenvFileor the shell-wrapped runner instead. - Add a CI step that runs
python3 -m json.tool .cursor/mcp.jsonso 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.jsonwhile Cursor is open and expecting a hot reload. It reads on launch and on toggle. - Confusing user-level
~/.cursor/mcp.jsonwith 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_TOKENwhen the GitHub server expectsGITHUB_PERSONAL_ACCESS_TOKEN. - Assuming Cursor discovers tools added after launch. It does not poll; restart.
FAQ
- Where is mcp.json?
~/.cursor/mcp.jsonfor global,.cursor/mcp.jsonin 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
commandpath (Step 2). - Can I share an MCP setup with my team? Yes — commit
.cursor/mcp.json, keep secrets out (useenvFile), and document required env vars and scopes in the README.
Related
- Cursor YOLO Mode Runs Without Confirm
- Cursor Agent Mode Tool Call Stuck
- Cursor Config Conflict
- Cursor IDE State Out of Sync
- Cursor Extension Marketplace Broken
Tags: #Cursor #mcp #Troubleshooting #Debug