MCP Server Not Showing Up in Claude Code? Read the Status First
Your MCP server is configured but Claude can't see it. `claude mcp list` tells you which of five different problems you actually have — pending approval, a failed spawn, a Windows .cmd shim, zero advertised tools, or a server that was never in the list to begin with.
When an MCP server doesn't show up in Claude Code, run claude mcp list before changing any config. The status next to each server tells you which of five distinct problems you have, and they need completely different fixes. Editing .mcp.json at random is how people lose an afternoon.
claude mcp listYou are looking for one of these, and each points somewhere specific:
| What you see | What it actually means |
|---|---|
✔ Connected | Transport is fine. If tools are missing, jump to zero tools. |
⏸ Pending approval | The server is configured but you never approved it. |
✘ Failed to connect | Claude Code tried to start or reach it and could not. |
not configured | A remote server entry with an empty url. |
| absent entirely | Wrong scope, or a WebSocket server — which never appears here. |
A failure status means Claude Code couldn't connect to that server, not that the list command failed. That distinction matters more than it sounds: people see a red mark next to claude mcp list and start debugging the CLI.
⏸ Pending approval — and why approving it can still fail
Project-scoped servers defined in a repo's .mcp.json need a one-time approval before they load. Until you give it, they sit at ⏸ Pending approval (run \claude` to approve). Run claude` interactively in the project and accept.
The part that catches teams out is what happens in a freshly cloned repo. As of v2.1.196, approvals are read only from settings files that aren't checked into the repository — until you trust the workspace. So a clone cannot approve its own servers: enableAllProjectMcpServers or enabledMcpjsonServers committed to the project's .claude/settings.json is ignored in an untrusted folder, and the server stays pending instead of connecting.
This is the failure mode where everything looks correct. The config is right there in version control, it works on the machine that wrote it, and it silently does nothing for everyone who clones. The fix is to run claude in the folder and accept the trust dialog.
An untracked .claude/settings.local.json behaves the same way — its approvals apply only after you've trusted that folder or a parent, because Claude Code runs git to check whether the file is tracked and only does that in a trusted folder.
✘ Failed to connect — run the command yourself
Take the exact command that follows -- in your claude mcp add line and run it directly in your shell.
# what you configured
claude mcp add my-server -- npx -y @acme/mcp-server
# what to run to isolate the problem
npx -y @acme/mcp-serverIf it errors in your own shell, the problem isn't Claude Code — it's the command, the package, or the environment. That one step separates "Claude Code is broken" from "this server has never worked," and they are very different afternoons.
Two configuration details cause most genuine spawn failures:
Relative paths. Paths in command and args resolve against the directory Claude Code was launched from, not against .mcp.json. Use absolute paths for local scripts. If your server genuinely needs the project root, Claude Code sets CLAUDE_PROJECT_DIR in the spawned server's environment — read it from inside the server process (process.env.CLAUDE_PROJECT_DIR) rather than assuming a working directory. Note that referencing ${CLAUDE_PROJECT_DIR} in the command or args of a .mcp.json entry needs a default, like ${CLAUDE_PROJECT_DIR:-.}, because the variable is set in the server's environment rather than Claude Code's own.
A misplaced --. For stdio servers, -- separates Claude's own flags from the command that runs the server. Everything after it is passed through untouched. Put --transport or --scope on the wrong side and you'll configure something you didn't intend.
Since v2.1.219, claude mcp list appends the failure detail to the status line, and claude mcp get <name> shows it on an Issue: line — the HTTP status or error code plus whatever error text the server returned. If you're on an older build you'll see the bare status with no explanation, which is worth knowing before you conclude there's nothing to go on.
Windows: Node refuses to spawn npx
If the server works on a colleague's Mac and fails on your Windows machine with spawn npx ENOENT or EINVAL, the cause usually isn't MCP at all.
On Windows, npx is npx.cmd — a shell script, not a native executable. Since CVE-2024-27980, Node errors with EINVAL when a .bat or .cmd file is passed to child_process.spawn or spawnSync without the shell option set. Node's own documentation is explicit that on Windows, .bat and .cmd files can be invoked by spawning cmd.exe and passing the file as an argument.
So point the command at cmd and pass npx through as an argument:
{
"mcpServers": {
"my-server": {
"command": "cmd",
"args": ["/c", "npx", "-y", "@acme/mcp-server"]
}
}
}I develop on Windows, and this is the single most common reason an MCP config that works everywhere else does nothing on my machine. It is not documented in the MCP guides because it isn't an MCP problem — it's a Node security change that MCP configs happen to trip over constantly, since so many servers are distributed as npm packages.
Connected but zero tools
The /mcp panel shows a tool count next to each connected server, and it specifically flags servers that advertise the tools capability but expose none. If you see that, the transport is fine and the handshake completed — the server simply returned an empty tool list.
In practice this is nearly always the server's own fault, and nearly always visible on stderr. Run the server's command directly and read what it prints while starting up. If registration throws and the process stays alive, MCP has no way to tell Claude Code that anything went wrong; from the outside it looks like a healthy server with nothing to offer.
If the server is one you wrote, check that tool registration completes before you connect the transport. And if you're writing to stdout anywhere in a stdio server, fix that first — it corrupts the JSON-RPC stream, which I covered in building an MCP server.
If tools appeared once and then vanished mid-session, that's different: Claude Code supports list_changed notifications and refreshes capabilities when a server sends one, so a server that dynamically drops tools will be reflected immediately.
The server isn't in the list at all
Three reasons a configured server never appears:
It's a WebSocket server. WebSocket servers don't appear in claude mcp list output. Use claude mcp get <name> or the /mcp panel. Worth knowing before you re-add it three times.
You added it at the wrong scope. Scope decides which projects a server loads in:
| Scope | Loads in | Stored in |
|---|---|---|
| Local (default) | Current project only | ~/.claude.json |
| Project | Current project only, shared via version control | .mcp.json in project root |
| User | All your projects | ~/.claude.json |
Local scope is the default, and it's stored under that project's path in ~/.claude.json — so a server you added while working in one repo genuinely will not exist in another. If you wanted it everywhere, you wanted --scope user.
Note that MCP "local scope" and general local settings are different things stored in different places: local-scoped servers live in ~/.claude.json, while .claude/settings.local.json sits in the project directory. If you're weighing how per-project and global configuration differ between tools, I compared that directly in Claude Code vs Cursor context management.
The url is empty. A remote server with an empty url shows as not configured, and Claude Code doesn't attempt to connect at all. Plugins sometimes ship placeholder entries like this on purpose, for a connector you configure later.
Whitespace you cannot see
Claude Code warns when an MCP config value carries hidden leading or trailing whitespace — it checks command, url, each args entry, and the values and key names under env and headers. The warning names the affected field without echoing its value, for example Leading or trailing whitespace in: headers.Authorization.
This overwhelmingly comes from pasting a token that brought a trailing newline with it. Claude Code does not trim the whitespace — it uses the value exactly as written, so you have to fix the config yourself. An auth header with an invisible \n produces a 401 that looks nothing like a formatting problem.
When it's the output limit, not the connection
A server that connects, exposes tools, and then seems to half-work may be hitting output limits rather than a transport fault. Claude Code warns when MCP tool output exceeds 10,000 tokens and limits output to 25,000 tokens by default. Raise it with MAX_MCP_OUTPUT_TOKENS:
export MAX_MCP_OUTPUT_TOKENS=50000The warning threshold itself is fixed. If a specific server floods you regularly, the better fix is on the server side — paginate, or declare anthropic/maxResultSizeChars on the tool.
Separately, if a server is slow to start rather than broken, MCP_TIMEOUT controls startup timeout:
MCP_TIMEOUT=10000 claudeKey takeaways
- Read `claude mcp list` before editing any config — the status names the problem, and the five statuses need five different fixes.
- A cloned repo cannot approve its own MCP servers. Committed approval settings are ignored until you trust the workspace.
- On Windows, point `command` at `cmd` with `/c` and pass `npx` as an argument — Node refuses to spawn `.cmd` files directly since CVE-2024-27980.
- Connected with zero tools means the handshake worked and the server returned nothing. Run its command directly and read stderr.
- WebSocket servers never appear in `claude mcp list`. Use `claude mcp get` or `/mcp` instead of re-adding them.
Frequently asked questions
Why does my MCP server show as connected but expose no tools?
The connection succeeded and the handshake completed, but the server advertised the tools capability and then returned an empty tool list. The /mcp panel flags exactly this case. It usually means tool registration runs after the server signals readiness, or it threw during registration and the process stayed alive. Run the server's command directly in your shell and watch stderr — the registration error is almost always printed there.
Why does my server work on macOS but not on Windows?
If the command is npx or npm, this is almost certainly Node refusing to spawn a .cmd file. Since CVE-2024-27980, Node errors with EINVAL when a .bat or .cmd is passed to child_process.spawn without a shell, and on Windows npx is npx.cmd. Point the command at cmd with /c and pass npx as an argument instead.
My .mcp.json is committed to the repo but teammates' servers stay pending. Why?
Approvals for project-scoped servers are only read from settings files once you trust the workspace. A cloned repository cannot approve its own servers: enableAllProjectMcpServers committed to .claude/settings.json is ignored in an untrusted folder, and the server stays at Pending approval. Run claude in the folder and accept the trust dialog first.
Is claude mcp list enough to see every server?
No. WebSocket servers don't appear in claude mcp list output at all. Use claude mcp get <name> or the /mcp panel to check those. If a server you configured is simply absent from the list, that is a real clue rather than a display bug.
Most of these are configuration problems wearing a connectivity costume. The status line tells you which one you have — the trick is reading it before you start editing.
If you're building the server rather than consuming someone else's, the setup steps and the stdio pitfalls are in how to build an MCP server. Managing what these tools know about a codebase is a related problem I've spent a lot of time on — ContextZero came out of it.
References
- Connect Claude Code to tools via MCPcode.claude.com · accessed 2026-08-11
- Node.js child_process documentationnodejs.org · accessed 2026-08-11
- Node.js April 2024 Security Releases (CVE-2024-27980)nodejs.org · accessed 2026-08-11
Last reviewed August 11, 2026
Tahir Nazir
Senior AI Engineer & Full-Stack Lead
5+ years shipping AI-powered products — RAG pipelines, agentic workflows, and MCP tooling. Top Rated on Upwork with a 100% job success score.
More about Tahir →Keep reading
New posts land here first. Follow along by RSS, or get in touch if you are building something similar.
Related articles
How to Build an MCP Server (TypeScript, End to End)
A working Model Context Protocol server in TypeScript — project setup, tool registration with Zod, stdio transport, and wiring it into Claude Code and Cursor without breaking the JSON-RPC stream.How-toAI Engineering11 min readClaude Code vs Cursor: How Each One Decides What Your Agent Knows
Both tools read project instructions from disk, but they disagree on file names, load order, and scoping. Here is the concrete difference — and how to keep one repo working well in both.ComparisonAI Engineering8 min readRAG Retrieval Returns the Wrong Chunks: A Production Debugging Guide
Your RAG demo worked and production doesn't. Before you swap the embedding model, check the four things that actually break retrieval: recall settings, chunk boundaries, keyword blindness, and where the answer sits in the prompt.TroubleshootingAI Engineering11 min read