Claude Code MCP Server Not Loading: The Diagnostic Order
Most advice for this is a list of things to try in no particular order, which is how people end up reinstalling Node at 1am. Each step's answer determines whether the next one can even be true.
You added an MCP server, the command printed Added…, and the tools are not there. Most advice for this is a list of things to try in no particular order, which is how people end up reinstalling Node at 1am. There is a fixed order to check, because each step's answer determines whether the next one can even be true. Work down it and you will land on the actual cause instead of the first plausible one.
1. The server is not in the list at all → you edited a file that does not apply here
This is the single most common cause, and it is a scope problem, not a syntax problem. Claude Code stores MCP configuration at three scopes, in two files:
local ~/.claude.json under the entry for ONE project path ← the default project .mcp.json in the project root, shared via git user ~/.claude.json top level, applies to all your projects
Local is the default scope. If you ran claude mcp add foo -- npx -y foo with no --scope, that server was written into ~/.claude.json keyed to the directory you happened to be in. Open the project next door and it is gone — correctly, by design, and with no message saying so. The fix is almost always:
claude mcp add --scope user <name> -- npx -y <package>
Two further traps in this step. A project-scope server must be in .mcp.json at the project root — a .mcp.json nested in a subdirectory, or a .claude/.mcp.json, is not the documented location and will not be picked up. And MCP “local scope” has no relationship to .claude/settings.local.json; that file holds general settings, not MCP servers. The naming collision has cost more debugging hours than the feature has saved.
2. It is listed, but with the wrong command → scope precedence, and nothing merges
When the same server name is defined at more than one scope, Claude Code connects once, using the highest-precedence definition: local, then project, then user. The important detail is what “uses” means — the entire entry from that source wins. Fields are not merged across scopes. A stale local-scope entry pointing at a path that no longer exists silently beats the correct project entry your team committed, and the error you see is a connection failure with no hint that a shadowing definition exists.
claude mcp get <name> shows the resolved entry. If the command in it is not the command you wrote, you have found your problem: remove the shadowing definition rather than editing the one you were looking at.
Nothing warns you that two scopes define the same server. The higher one simply wins, whole.
3. ⏸ Pending approval → this is not an error
Project-scoped servers from .mcp.json are not connected to until you approve them in an interactive session — a security boundary, since .mcp.json arrives with the repository. Run claude in the project, review the prompt, approve. To reset those choices later: claude mcp reset-project-choices.
The version of this that looks like a bug: a repository cannot approve its own servers. As of v2.1.196, claude mcp list and claude mcp get read .mcp.json approvals only from settings files that are not checked into the repository, until you trust the workspace by running claude in it and accepting the workspace-trust dialog. So a freshly cloned repo that ships enableAllProjectMcpServers in its committed .claude/settings.json is ignored, and the server sits at ⏸ Pending approval looking broken. Accept the trust dialog and it connects.
4. Approved, still absent → check the disable lists
There are two unrelated pairs of settings that can suppress a server, and their names are close enough to be genuinely confusing:
enabledMcpjsonServers/disabledMcpjsonServers— control approval of servers defined in a project's.mcp.json. A server indisabledMcpjsonServersis blocked in every mode, including headless runs.enabledMcpServers/disabledMcpServers— recorded per project in~/.claude.jsonwhen you toggle a server in the UI. Different mechanism, different file, unrelated to the pair above.
If you ever toggled a server off in a session and forgot, this is where that decision is living.
5. ✘ Failed to connect → the command cannot run, or cannot run in time
Now it is a process problem, and the questions are ordinary ones. Run the server's command yourself, exactly as configured, from the same directory:
npx -y some-mcp-server # a working stdio server starts and waits silently on stdin. # an error, a usage message, or an immediate exit is your answer.
- PATH.A GUI-launched client does not inherit your shell's PATH. A server that works in your terminal and fails in a desktop app is usually this — use an absolute path to the binary (
which npx) in that client's config. - The
--separator. Inclaude mcp add, everything after--is passed to the server untouched; everything before it is parsed as Claude's own flags. Flags for your server placed before the--get eaten. - Startup timeout. A first
npxrun that downloads a package can exceed the default.MCP_TIMEOUT=10000 claudesets a ten-second startup timeout; running the package once by hand to warm the npx cache also fixes it permanently. - Environment variables. Variables are set in the server'senvironment, not Claude Code's. Expansion like
${CLAUDE_PROJECT_DIR}inside a.mcp.jsoncommand needs a default —${CLAUDE_PROJECT_DIR:-.}— outside of plugin-provided configs. - Transport name. When configuring by JSON, the
typefield acceptsstreamable-httpas an alias forhttp, so a config copied straight from a server's docs works unmodified. If you hand-translated it to something else, translate it back.
6. ! Needs authentication → sign in, and know where that fails silently
Run claude mcp login <name> from your shell, or /mcp inside a session. Use claude mcp login <name> --no-browser on a remote box.
The trap is non-interactive mode: a claude -p run or an Agent SDK session has no /mcppanel and cannot run an OAuth flow. Recent versions tell Claude that the server's tools are unavailable until you authorise it, so the model can name the server that needs sign-in — but you have to complete the sign-in from an interactive session. If your CI keeps behaving as though a server does not exist, this is a strong candidate.
7. Connected, tools still not used → connection is not the last step
A green tick means the handshake completed and tools were retrieved. It does not mean the model calls them. Two current behaviours matter here:
- Tool search. On recent models, MCP tool definitions are deferred and searched rather than all loaded upfront — the default. That is usually what you want (it is the difference between ten servers costing you a large fixed slice of every context window and costing you approximately nothing), but it means a tool can be present and not visible in the way you expect.
ENABLE_TOOL_SEARCHcontrols it. - Failed servers are reported to the model.When a configured server fails to connect, recent versions tell Claude which server failed and why, so it can say so instead of answering as if the server were never configured. Older versions did not, which is where “the agent pretends my server does not exist” comes from.
8. It works in your terminal and not in your session
claude mcp listruns where you are standing, with your shell's environment, right now. A session has its own working directory (so its own local- and project-scope servers), possibly a different environment, and it resolved its server list when it started — before the edit you just made. Inside a session, /mcp is authoritative. If the two disagree, restart the session first; if they still disagree, check what directory the session is actually in.
For the full separation of “configured” vs “connected” vs “running as a process” — including why the process count is always higher than the server count — see how to see which MCP servers are actually running.
The two checks worth automating
Steps 1 and 2 are a file-archaeology problem, and it is the same archaeology every time: which config declares this server, and is another one shadowing it. We wrote that check into a free MCP server so the agent can answer it too. whats-loaded-mcp has an mcp_servers tool that lists every MCP server configured across your clients and the file that declares each one — plus the reason it exists, which is telling you what is consuming your context window before you type.
claude mcp add --scope user whats-loaded -- npx -y whats-loaded-mcp claude mcp add --scope user whats-running -- npx -y whats-running-mcp
Its sibling whats-running-mcp covers the process half of step 5 — what is actually alive, what is holding a port, and what is an orphan of a client that already quit. Both are MIT, read-only, no telemetry, and stay free: source for whats-loaded-mcp and whats-running-mcp on GitHub, and the rest of the set on our agent tools page.
The order, on one screen
claude mcp list status per server not listed → wrong scope. --scope user. check .mcp.json is at project ROOT wrong command → another scope shadows it. claude mcp get <name> ⏸ pending → approve interactively; accept the workspace trust dialog approved, absent → disabledMcpjsonServers / disabledMcpServers ✘ failed → run the command by hand. PATH, the -- separator, MCP_TIMEOUT ! needs auth → claude mcp login <name> (cannot be done in -p / SDK runs) green, unused → tool search; restart the session; check the session's cwd
Behaviour described here comes from Anthropic's Claude Code MCP documentation — installation scopes and precedence, health statuses, project-server approval and workspace trust, timeouts, and tool search. Where a behaviour changed in a specific version, that version is named above; check the docs against the version you are running before concluding you have found a bug.