MCP Server Not Showing Up in Claude Desktop? A Systematic Debugging Guide
You edited claude_desktop_config.json, restarted Claude Desktop, and... nothing. No new tools, no server indicator, no error dialog. The most frustrating part of debugging Model Context Protocol (MCP) servers is that when a stdio server fails to launch, Claude Desktop usually fails silently — the server just doesn't appear.
The good news: it's almost never a mystery once you read the logs. This guide walks through exactly where Claude Desktop writes per-server logs, how to read the stderr stream, the three error signatures that account for the overwhelming majority of failures, and a methodical isolation checklist that gets you to root cause every time.
TL;DR
- Read the logs first. macOS:
~/Library/Logs/Claude. Windows:%APPDATA%\Claude\logs. The filemcp.loghas general connection info;mcp-server-SERVERNAME.loghas the stderr output from your specific server. (MCP docs) - Tail them live while you restart Claude Desktop:
tail -n 20 -f ~/Library/Logs/Claude/mcp*.log(macOS). spawn ... ENOENTmeans Claude Desktop can't find your command on its PATH. Fix: use an absolute path tonpx/node/uv/pythoninstead of the bare name. (real GitHub issue)- A JSON parse error or unexpected token usually means a typo (trailing comma, missing bracket) in your config — which silently disables all servers, not just one.
- Missing/empty env vars happen because stdio servers inherit only a limited, platform-dependent subset of environment variables. Pass secrets explicitly via the
envkey. (MCP docs) - Always fully quit and reopen Claude Desktop after a config change — closing the window is not enough. (MCP docs)
- Isolate by running the exact command from
configin a terminal, and by testing with the MCP Inspector:npx @modelcontextprotocol/inspector <command> <args>.
Want to skip the manual JSON checking? mcp-config-lint (a free pip install) catches the syntax and path mistakes that cause most "server not showing up" failures before you even restart.
Step 1: Find and read the logs
This is the single highest-leverage step. Don't guess — read what Claude Desktop actually recorded when it tried to launch your server.
Per the official MCP documentation, Claude Desktop writes MCP-related logs to:
| OS | Log directory |
|---|---|
| macOS | ~/Library/Logs/Claude |
| Windows | %APPDATA%\Claude\logs |
There are two kinds of files you care about (source):
mcp.log— general logging about MCP connections and connection failures.mcp-server-SERVERNAME.log— error (stderr) logging from the individual server namedSERVERNAME(the key you used inmcpServers).
So if your config block is "mcpServers": { "filesystem": { ... } }, the per-server log is mcp-server-filesystem.log.
Tail the logs live as you restart
The most reliable workflow is to follow the logs in real time, then fully quit and reopen Claude Desktop so you capture the launch attempt as it happens.
macOS / Linux:
tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
Windows (PowerShell) — the official docs show a type one-shot (it shows recent logs only, not a live follow):
type "$env:AppData\Claude\logs\mcp*.log"
If you want a live follow on Windows, Get-Content works well:
Get-Content "$env:AppData\Claude\logs\mcp-server-SERVERNAME.log" -Wait -Tail 20
Tip: You can also reach these from inside the app. Open Claude Desktop Settings → Developer, where you can see configured servers and edit the config. Per the MCP docs, you check connected servers and available tools via the "Add files, connectors, and more" (plus) icon → Connectors menu.
Why "logged to stderr" matters
When a server uses the local stdio transport (the default for command-based servers in claude_desktop_config.json), the official docs are explicit:
"all messages logged to stderr (standard error) will be captured by the host application automatically."
And a critical corollary:
"Local MCP servers should not log messages to stdout (standard out), as this will interfere with protocol operation."
This is a real gotcha when writing your own server: a stray print() / console.log() to stdout corrupts the JSON-RPC stream and can break the connection. Route all diagnostics to stderr instead — that's what lands in mcp-server-SERVERNAME.log. (MCP debugging docs)
Step 2: Match the error signature
Open mcp-server-SERVERNAME.log (and mcp.log) and look for one of these. These three cover the large majority of "not showing up" reports.
Signature A: spawn npx ENOENT (or spawn node ENOENT, spawn uv ENOENT)
This is the most common failure. ENOENT is the OS's "no such file or directory" error — here it means Claude Desktop could not find the command you specified.
The root cause is that Claude Desktop does not inherit your terminal's full environment, and in particular it may not have the same PATH. So even though npx works perfectly in your shell, the app launches with a different (often minimal) PATH and can't resolve the bare command name.
A real-world example: in rohlik-mcp issue #6, a macOS user hit repeated spawn npx ENOENT errors. The underlying cause was that Claude Desktop's runtime PATH didn't include the Node.js install directory even though npx was on the user's shell PATH. The fix was to replace the bare command with an absolute path:
{
"mcpServers": {
"rohlik": {
"command": "/Users/adam/.local/share/mise/installs/node/22.14.0/bin/npx",
"args": ["..."]
}
}
}
How to fix it yourself — find the absolute path of your command and paste it into "command":
# macOS / Linux
which npx # e.g. /usr/local/bin/npx
which node
which uv
# Windows
where.exe npx # e.g. C:\Program Files\nodejs\npx.cmd
where.exe node
On Windows, note the resolved file is often npx.cmd (not a bare npx) — use the exact path where.exe returns. If you use a version manager (nvm, mise, fnm, asdf, pyenv), the path will live inside that manager's install directory, as in the example above.
Related working-directory note: the docs warn that the working directory for a server launched via the client config "may be undefined (like
/on macOS)." Always use absolute paths for files and directories in yourargsand.envtoo — never relative paths like./data. (source)
Signature B: JSON parse error / "Unexpected token"
If you see a JSON/parse error in mcp.log, your claude_desktop_config.json has a syntax mistake. The catch: a single bad character disables every server, not just the one you were editing, because the whole file fails to parse.
The usual culprits:
- A trailing comma after the last item in an object or array (valid in JS, invalid in JSON).
- A missing comma between two server entries.
- Mismatched brackets/braces.
- Unescaped backslashes in Windows paths — JSON requires
"C:\\Users\\you\\..."(double backslashes).
The official troubleshooting checklist for "server not showing up" lists "Check your claude_desktop_config.json file syntax" as an explicit step. (source)
How to fix: validate the file with any JSON linter (see Step 3) and watch for those four mistakes specifically.
Signature C: env not passed (missing API key, missing APPDATA)
Your server does launch, but it crashes or behaves as if a secret is missing. This is the environment-inheritance problem again, stated plainly by the docs:
"MCP servers launched over stdio inherit only a limited subset of environment variables automatically (the exact set is platform-dependent)."
So an API_KEY you exported in your shell will not automatically reach the server. You have to pass it explicitly with the env key:
{
"mcpServers": {
"myserver": {
"command": "mcp-server-myapp",
"env": {
"MYAPP_API_KEY": "some_key"
}
}
}
}
A documented Windows-specific variant: if your server's log shows an error referencing ${APPDATA} inside a path, you may need to add the expanded value of %APPDATA% to the server's env block (source):
{
"brave-search": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": {
"APPDATA": "C:\\Users\\user\\AppData\\Roaming\\",
"BRAVE_API_KEY": "..."
}
}
}
The same docs add an important Windows caveat: npx may keep failing if npm isn't installed globally. If it is, %APPDATA%\npm will exist on your system; if not, install it with npm install -g npm.
Other signatures you may see
- "Server transport closed unexpectedly, this is likely due to the process exiting early." — the server process crashed right after launch. This points back to one of the three causes above (or a bug in the server). Reproduce it directly in a terminal (Step 3) to see the real stack trace. (discussion #325)
command not found: /Users/you/DesktoporERROR: You must supply a command.— yourcommand/argsare split wrong, so a path argument is being treated as the executable, ornpx -yhas no package after it. Re-check that the package name is the firstargand the directories come after it. (discussion #325)
Step 3: The systematic isolation checklist
Work top to bottom. Each step removes a variable, so by the end you've localized the fault.
1. Confirm Claude Desktop fully restarted
A config change requires a full quit and reopen — closing the window is explicitly not enough. From the docs: "Server code changes: Restart the client (for Claude Desktop, fully quit and reopen; closing the window is not enough)." On macOS use Cmd+Q (or Claude menu → Quit); on Windows quit from the system tray, not just the X button. (source)
2. Validate the config before you restart
Most "server not showing up" failures are config typos that disable everything. Validate the JSON before you spend a restart cycle on it.
The official config locations are:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
You can validate with any JSON linter. For a faster, MCP-aware check, our free mcp-config-lint does exactly this — it parses claude_desktop_config.json, flags trailing commas / mismatched brackets, and warns when a command is a bare name that may not resolve on Claude Desktop's PATH (the spawn ENOENT trap from Signature A):
pip install mcp-config-lint
mcp-config-lint
It's a 10-second check that prevents the two most common silent failures.
3. Run the exact command yourself
Copy the command and args straight out of your config and run them in a terminal. The official troubleshooting steps recommend exactly this — manually running the server to surface errors. For the filesystem server, for example:
# macOS / Linux
npx -y @modelcontextprotocol/server-filesystem /Users/username/Desktop /Users/username/Downloads
# Windows
npx -y @modelcontextprotocol/server-filesystem C:\Users\username\Desktop C:\Users\username\Downloads
If this errors in your terminal, you've found the problem without involving Claude Desktop at all. (source)
4. Use absolute paths everywhere
Per the docs' "Server initialization" guidance, common path problems include an incorrect executable path, missing files, and permission issues — and the recommended remedy is to "try using an absolute path for command." Apply the same to every directory/file in args and any .env. (source)
5. Confirm secrets are in the env block
If the command runs in your terminal (where your shell env is loaded) but fails under Claude Desktop, suspect environment inheritance. Move every required variable into the env key as shown in Signature C.
6. Test with the MCP Inspector
The MCP Inspector is an interactive, transport-agnostic UI for testing a server in isolation. The docs call it "your first stop" for debugging. It runs through npx without installation:
npx @modelcontextprotocol/inspector <command> <args>
For an npm-published server:
npx -y @modelcontextprotocol/inspector npx @modelcontextprotocol/server-filesystem /Users/username/Desktop
For a local TypeScript server:
npx @modelcontextprotocol/inspector node path/to/server/index.js args...
If the Inspector connects and lists your tools, the server is fine and the problem is in your Claude Desktop config or environment. If the Inspector also fails, the problem is in the server itself. Either way, you've cut the search space in half. (Inspector docs)
7. Re-read the per-server log one more time
After each change, fully restart and re-tail mcp-server-SERVERNAME.log. The error signature should change as you fix each layer — that's how you know you're making progress and not chasing a stale failure.
A complete, known-good config to compare against
When in doubt, diff your file against the canonical example from the official quickstart (replace username):
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/username/Desktop",
"/Users/username/Downloads"
]
}
}
}
On a successful launch, the docs note you'll see an MCP server indicator in the bottom-right of the conversation input box, and clicking it shows the server's available tools. If that indicator never appears, you're back to Step 1 — read the log. (source)
FAQ
Q: Where exactly are the per-server logs on Windows?
A: %APPDATA%\Claude\logs. The file mcp-server-SERVERNAME.log holds the stderr output of the server whose key is SERVERNAME in your config; mcp.log holds general connection logging. (source)
Q: My server works in the terminal but not in Claude Desktop. Why?
A: Almost always one of two things: (1) Claude Desktop launches with a different, often minimal PATH, so a bare npx/node/uv command isn't found (spawn ENOENT) — fix with an absolute path; or (2) environment variables you have in your shell aren't inherited — pass them via the env key. Both are documented behaviors. (env inheritance, absolute-path fix)
Q: I fixed one server but now none of them load.
A: That's the classic JSON syntax-error symptom — a trailing comma or missing bracket makes the entire claude_desktop_config.json unparseable, taking down every server at once. Lint the file (e.g. mcp-config-lint) and look specifically for commas and brackets.
Q: Why shouldn't my server print to stdout? A: For stdio-transport servers, stdout is the JSON-RPC channel. Per the docs, "Local MCP servers should not log messages to stdout… as this will interfere with protocol operation." Log to stderr instead, which Claude Desktop captures into the per-server log file automatically. (source)
Q: Do I really have to fully quit, or can I just close the window? A: Fully quit. The docs are explicit that "closing the window is not enough" — the app needs a full restart to reload config and relaunch servers. (source)
Q: What's the fastest way to know whether it's my config or my server?
A: Run the MCP Inspector against the server (npx @modelcontextprotocol/inspector <command> <args>). If it connects, the server is healthy and the fault is in your Claude Desktop config/env. If it doesn't, the fault is in the server. (source)
Skip the setup entirely
If you'd rather not spend an afternoon trading restarts with a log tail, the Hatchloop MCP Setup Pack ($15) ships pre-validated config templates for the common servers, OS-specific absolute-path and env blocks already filled in, and a copy-paste debugging runbook — built around exactly the failure modes above. It's the "just make it work" option; everything in this guide is also enough to do it yourself for free.
Sources
- Connect to local MCP servers — Model Context Protocol — official config locations, log file names (
mcp.log,mcp-server-SERVERNAME.log), troubleshooting checklist,env/APPDATAfix, manual-run step. - Debugging — Model Context Protocol — log directories, stderr capture, stdout warning, environment-variable inheritance, working-directory/absolute-path guidance, "fully quit and reopen" requirement.
- MCP Inspector — Model Context Protocol — Inspector install/run commands and usage.
- rohlik-mcp Issue #6 — "spawn npx ENOENT … needs absolute path override" — real-world
spawn npx ENOENTreport and absolute-path fix on macOS. - modelcontextprotocol Discussion #325 — service fails to start — real error strings ("Server transport closed unexpectedly…", "command not found…", "You must supply a command.") and config-syntax root causes.
Last reviewed June 2026. Paths and behaviors reflect the official MCP documentation at modelcontextprotocol.io as of that date; Claude Desktop internals can change between releases, so always confirm against your current logs.
Published by Hatchloop. Free MCP config linter: pip install mcp-config-lint · MCP Setup Pack → · More guides