Guide
Claude Desktop not working with your MCP server? Five checks that fix it
By Aman Singh · Published · Updated · 10 min read
Claude Desktop is not working with your MCP server: you added it to the config, and nothing happens. No tools, no error, just an assistant that acts as if the server does not exist. The cause is almost always one of five things, and they are quick to rule out if you check them in order.
This guide gives you that order, and a short script that starts every server in your config the way a client does and prints the real error. The script and each failure below were run in October 2026 with Node.js 20 and version 1.32.1 of the official @modelcontextprotocol/sdk. It covers local servers that the app starts itself (stdio). The same ideas apply to Cursor and Claude Code.
Still not connecting after the five checks? Have me debug your MCP server →
Is it the app or your MCP server?
If Claude Desktop stopped working right after you added or edited an MCP server, start by taking the servers out of the picture. Quit the app fully, rename claude_desktop_config.json (for example to claude_desktop_config.backup.json) and open the app again.
- It works without the config: the problem is your config or one of its servers. Rename the file back and work through the checks below.
- It still does not open or work: the problem is the app itself, not MCP. Update or reinstall Claude Desktop, then add your config back.
Quit the app fully and restart
Do this first, and again after every config change. Closing the window often leaves the app running in the menu bar or system tray, and the config is only read at startup. Quit from the tray or menu icon, then open it again.
Run a checker that shows the real error
When a server fails inside Claude Desktop you usually get a vague message. The script below reads the same config file, starts each local server with its command, arguments and environment, asks it to list its tools, and prints what the server said on stderr if it fails.
mkdir mcp-check && cd mcp-check
npm init -y
npm install @modelcontextprotocol/sdk
# save the script below as check-mcp.mjs, then:
node check-mcp.mjs "/path/to/claude_desktop_config.json"// Starts every server in a Claude Desktop style config the way a client does,
// and reports which ones answer. Usage: node check-mcp.mjs path/to/config.json
import { readFileSync } from "node:fs";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const configPath = process.argv[2];
if (!configPath) {
console.error("Usage: node check-mcp.mjs path/to/claude_desktop_config.json");
process.exit(2);
}
let text;
try {
text = readFileSync(configPath, "utf8");
} catch (err) {
console.error(`Cannot read ${configPath}: ${err.message}`);
process.exit(2);
}
let config;
try {
config = JSON.parse(text);
} catch (err) {
console.error(`Config is not valid JSON: ${err.message}`);
console.error("On Windows, paths need doubled backslashes or forward slashes.");
process.exit(1);
}
const TIMEOUT_MS = 10_000;
let failed = 0;
for (const [name, server] of Object.entries(config.mcpServers ?? {})) {
if (!server.command) {
console.log(`SKIP ${name}: no "command" (remote servers are added in the app, not here)`);
continue;
}
const transport = new StdioClientTransport({
command: server.command,
args: server.args ?? [],
env: server.env,
stderr: "pipe",
});
const stderrLines = [];
transport.stderr?.on("data", (chunk) => stderrLines.push(...String(chunk).split("\n")));
const client = new Client({ name: "check-mcp", version: "1.0.0" });
let timer;
try {
const timeout = new Promise((_, reject) => {
timer = setTimeout(() => reject(new Error(`no answer within ${TIMEOUT_MS / 1000}s`)), TIMEOUT_MS);
});
await Promise.race([client.connect(transport), timeout]);
const { tools } = await Promise.race([client.listTools(), timeout]);
console.log(`OK ${name}: ${tools.length} tool(s): ${tools.map((t) => t.name).join(", ")}`);
} catch (err) {
failed++;
console.log(`FAIL ${name}: ${err.message}`);
const tail = stderrLines.filter(Boolean).slice(-5);
// macOS/Linux report ENOENT; on Windows the shell prints "not recognized".
const notFound =
err.code === "ENOENT" || tail.some((line) => /not recognized|not found|ENOENT/i.test(line));
if (notFound) {
console.log(` "${server.command}" was not found. Use the full path to the program.`);
}
if (tail.length) console.log(` server stderr:\n ${tail.join("\n ")}`);
} finally {
clearTimeout(timer);
await client.close().catch(() => {});
}
}
process.exit(failed ? 1 : 0);The config file is claude_desktop_config.json: on macOS under ~/Library/Application Support/Claude/, on Windows under %APPDATA%\Claude\. Cursor reads .cursor/mcp.json in the same format. Here is the output against a test config with one working server and three broken ones (run on Windows, trimmed):
OK orders: 3 tool(s): get_order, list_orders, cancel_order
FAIL missing-command: MCP error -32000: Connection closed
"npx-does-not-exist" was not found. Use the full path to the program.
server stderr:
'npx-does-not-exist' is not recognized as an internal or external command,
operable program or batch file.
OK noisy: 1 tool(s): ping
FAIL crashes: MCP error -32000: Connection closed
server stderr:
Error: ORDERS_API_KEY is not set
SKIP remote-one: no "command" (remote servers are added in the app, not here)Each failure points at a different check below. The apps also keep their own logs: Claude Desktop writes one per server, typically ~/Library/Logs/Claude/mcp-server-NAME.log on macOS and under %APPDATA%\Claude\logs\ on Windows. They contain the same stderr text.
MCP error -32000: Connection closed
This is the error most people search for, and on its own it says very little. In the official SDK, -32000 is the code for ConnectionClosed: the server's process ended, or closed its output, before it answered. It is a symptom. The cause is whatever the server wrote to stderr just before it exited.
I reproduced it with the SDK's own client (version 1.32.1, Node.js 26.12.1, Windows 11, 24 October 2026). Each row is a separate server setup:
| Server setup | Error the client got | What stderr said | Fix |
|---|---|---|---|
| Exits on start: an env var is missing | -32000 Connection closed | Missing API_KEY | Check 3: set it in the env block |
| Command does not exist | -32000 Connection closed | '...' is not recognized as an internal or external command | Check 2: use an absolute path |
| Starts, prints a banner, never answers | -32001 Request timed out, after 60 s | Nothing | Check 4: make sure it speaks MCP on stdio |
| npx -y @modelcontextprotocol/server-everything, with or without cmd /c | None: connected, 16 tools | Nothing | None needed |
- -32000 means the process died. Run the command by hand or use the checker above to read its last words: usually a missing environment variable, a wrong path or a command that was not found.
- -32001 means the process is alive but not talking MCP. Typical causes are a script path that starts something else, a server that runs in HTTP mode unless told to use stdio, or a first-run
npxdownload that outlasts the timeout.
Check 1: the config file
If the file is not valid JSON, the app may ignore every server in it without a word. The most common cause on Windows is a path with single backslashes, because \U and \o are not valid escapes:
{ "mcpServers": { "orders": { "command": "node",
"args": ["C:\Users\me\orders\dist\server.js"] } } }Config is not valid JSON: Bad escaped character in JSON at position 62
On Windows, paths need doubled backslashes or forward slashes.Either of these forms is valid:
"args": ["C:/Users/me/orders/dist/server.js"]
"args": ["C:\\Users\\me\\orders\\dist\\server.js"]Trailing commas are the other usual culprit. Paste the file into a JSON validator if the checker reports a position you cannot find.
Check 2: the command
The app starts your server by running the command you gave it. It does this without your shell profile, so a command that works in your terminal can be missing for the app. This is the classic spawn ... ENOENT error. It is especially common when Node comes from a version manager such as nvm or asdf, because the version your terminal picks is not on the app's PATH (a write-up of the asdf case shows it).
The fix is to give the full path to Node and to your script. Find the path with:
which node # macOS / Linux
where node # Windows{
"mcpServers": {
"orders": {
"command": "/usr/local/bin/node",
"args": ["/Users/me/orders/dist/server.js"],
"env": { "ORDERS_API_KEY": "your-key-here" }
}
}
}On Windows, many guides tell you to wrap npx as "command": "cmd" with "args": ["/c", "npx", ...]. In my test the SDK client connected either way, because it starts servers through cross-spawn, which finds npx.cmd. If your client still reports spawn npx ENOENT, the cmd /c wrapper is the fix. If you built the server yourself, pointing node at the compiled file avoids npx altogether.
Check 3: the process stays up
If the command starts but the process exits straight away, the client reports "Connection closed". In the test above, a server that needs ORDERS_API_KEY and does not find it exits immediately, and the only clue is the line it wrote to stderr. Do not count on your shell's environment being there: set required variables in the config's env block.
You can see the same thing by hand. Run the exact command from a terminal. A healthy stdio server prints nothing and waits for input, which is normal; press Ctrl+C to stop it. A crashing one prints its error and returns to the prompt.
ORDERS_API_KEY=your-key node /Users/me/orders/dist/server.jsCheck 4: the handshake
After starting, the client and server exchange messages over the process's standard input and output. Two things go wrong here.
- Output on stdout. In stdio mode, stdout carries protocol messages only. My test server printed a one-line banner with
console.log, and the SDK client tolerated it (thenoisyline above says OK). That does not make it safe: other clients may reject it, and a message that looks like JSON could corrupt the exchange. Log withconsole.error. - A slow start. A server launched through
npx -y some-packagemay download the package on first run, which can outlast the client's patience. Install the package once, or run a built file withnode.
Check 5: the tools
If the checker lists your tools but the assistant never uses them, the server is fine and the problem is selection. Make each tool description say what it does and when to use it, keep the tool list short, and ask the assistant a question that clearly needs the tool. The build guide covers how to write them, and the PostgreSQL MCP server guide shows a schema-discovery tool pattern that helps the assistant pick the right tool first time.
Remote servers are different
Everything above is for local servers started by the app. A server that lives at a URL is not started by the app and is not set up in the JSON file. In Claude Desktop, remote servers are added through the app's settings (Settings, then Connectors); an issue on the Webflow MCP server shows people hitting exactly this. The checker above skips entries with no command for that reason.
Symptom cheat sheet
| What you see | Likely check | Try this |
|---|---|---|
| No servers at all, no error | 1 Config | Validate the JSON; fix backslashes and trailing commas |
| spawn ... ENOENT, or command not recognized | 2 Command | Use absolute paths to node and your script |
| MCP error -32000: Connection closed | 3 Process | Run the command by hand; set env vars in the config |
| MCP error -32001: Request timed out | 4 Handshake | Check it speaks MCP on stdio; avoid downloading at startup |
| Connected but never used | 5 Tools | Rewrite descriptions; trim the tool list |
| Remote URL does nothing | Remote | Add it in the app's connector settings |
Common questions
Why is Claude Desktop not working after I added an MCP server?+
What does MCP error -32000: Connection closed mean?+
Why does my MCP server work in the terminal but not in Claude Desktop?+
Where does Claude Desktop keep MCP logs?+
Can I print debug output from my MCP server?+
Does the same fix apply to Cursor and Claude Code?+
Want it working and hardened?
If you would rather hand this over, I build and debug MCP servers for existing APIs: see custom MCP server development, or bug fixing for Node.js and Python apps if the problem is elsewhere in your stack.
Next steps
Keep reading
Need a hand with this?
Tell me what you are working on. Free scoping call, fixed quote within 48 hours.
Book a call