Skip to content
PrepMint

Troubleshooting

Why your MCP server isn't showing up in Claude Code

An MCP server that adds cleanly and then shows no tools has about ten possible causes, and each leaves a different fingerprint. A symptom-first triage guide: what the /mcp statuses actually mean, why scope cannot be changed in place, and the config error that makes Claude run your URL as a local process.

Rohan Surve9 min read

Last reviewed

You added an MCP server, the terminal said it was added, and Claude cannot see a single one of its tools. Nothing is on fire and nothing has crashed — which is exactly the problem, because there is no error message to search for.

Almost every version of this has one of about ten causes, and each leaves a different fingerprint. The documentation describes what each setting does; it does not tell you which setting to suspect when the symptom is silence. This is that map, written symptom first.

Start with what /mcp is actually telling you

Before changing anything, open the /mcp panel and read the status. It is the highest-value ten seconds in this whole process, because the status narrows ten possible causes to two or three.

The statuses mean different things than they look like they mean. failure is specifically about the connection: as the documentation puts it, "A failure status means Claude Code couldn't connect to that server, not that the list command failed." A server sitting at not configured is not a broken connection at all — a remote server whose configuration has an empty url shows that way, and Claude Code does not even attempt to connect to it.

So: connected with no tools, failed to connect, pending approval, and not configured are four different bugs. Fixing them in the wrong order is most of why this takes an afternoon.

"Added" does not mean it ran

The single most common misreading. When claude mcp add prints its confirmation, that confirmation is about the config file, not the process: "The Added confirmation means the entry was saved, not that the command runs."

It is worse than that for remote servers, because credentials are not checked either. The claude mcp add command saves the configuration without validating credentials, so a placeholder value is accepted at add time and the server simply fails to connect later — at which point you are debugging a connection while the actual mistake was a YOUR_TOKEN_HERE you meant to come back to.

Treat add as writing a line of JSON. The real test is starting a session and reading /mcp.

It connected, and the tool list is empty

This one confuses people because the status is green. A server that shows as connected but lists zero tools has started successfully but is not returning a tool list — the process is alive and the protocol handshake worked, so nothing is wrong with your transport, your path or your permissions.

The usual cause is environment: if the list is empty, the server started but did not register any tools, which usually means it is missing a required environment variable such as an API key. Many servers are written to start cleanly and expose nothing when they cannot authenticate, which is a defensible design and a miserable thing to debug.

There is a related trap worth knowing. If a referenced environment variable is not set and has no default value, the config still loads — Claude Code reports a missing-variable warning for that server in claude mcp list output and uses the unexpanded ${VAR} text as-is. So the server receives the literal string ${GITHUB_TOKEN} as its token, tries it, and fails in whatever way that server fails. Read `claude mcp list` output, not just the panel.

It works in one folder and not the next

If the server is there in one project and absent in another, you are looking at scope, and scope has two behaviours that surprise people.

First, local scope is the default, and a local-scoped server loads only in the project where you added it. "Local-scoped servers are tied to the project where you added them: the repository root, or the exact directory if you weren't in a git repository." That last clause matters — if you ran claude mcp add outside a git repository, the server is pinned to that exact directory, not to the tree beneath it.

Second, and this is the one that costs time: scope is fixed at the moment you add the server. "A server's scope is fixed when you add it, so changing scope means removing the entry and re-adding it at the new one." There is no command that moves it. If you meant it to be user-scoped and available everywhere, remove and re-add.

When the same server name is defined in more than one place, Claude Code connects once, using the definition from the highest-precedence source — and the entire entry from that source is used. Fields are not merged across scopes. A half-correct user-scoped entry will therefore mask a perfectly good project-scoped one rather than combining with it.

You edited .mcp.json and nothing happened

Claude Code reads .mcp.json at session start. Not on save, and not on /mcp refresh. If you edited the file with a session open, you are still looking at the state the file had when the session began.

Restart the session before concluding your edit did not work. This sounds obvious written down and accounts for a surprising share of "the fix did not work" second attempts.

It is stuck at pending approval

Project-scoped servers from .mcp.json are not loaded silently, and that is deliberate: for security reasons, Claude Code prompts for approval in interactive sessions before using them. The reason is stated plainly in the documentation — "The prompt exists so a repository you clone can't launch processes on your machine without your consent."

Two consequences catch people out.

A cloned repository 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 at pending approval instead of being connected and health-checked. You have to trust the folder yourself; the repo cannot vouch for itself, which is the entire point.

And the prompt does not exist everywhere. claude -p runs, Agent SDK sessions and cloud sessions cannot show it, so project-scoped servers load there without asking. If a server works in your headless CI job and hangs at pending on your laptop, nothing is broken — you are seeing the trust boundary do its job.

One more, easy to miss: a disabledMcpjsonServers entry in any settings file still rejects the server, whatever the approval state says.

The entry has a url, and Claude treats it as a local process

A pure configuration bug with a very confusing symptom. "A JSON entry that has a url but no type is a configuration error, because Claude Code reads an entry with no type as a stdio server."

So Claude tries to execute your HTTPS endpoint as a local command. The failure looks like a broken server or a network problem, and it is neither. Add the type field. When configuring via JSON, the type field accepts streamable-http as an alias for http, so both spellings are fine — omitting it is not.

While you are there: HTTP servers are the recommended option for connecting to remote MCP servers, and the SSE transport is deprecated. If you inherited an SSE config from a year-old tutorial, that is worth fixing before you debug it further.

Authentication fails right after you paste a token

If a token that is definitely correct is definitely being rejected, check for whitespace before checking anything else. Claude Code flags config values with hidden leading or trailing whitespace, and calls it what it is: a common cause of authentication failures after pasting a token.

Critically, it does not fix it for you. Claude Code does not trim the whitespace and uses the values exactly as written — so you have to edit the configuration to remove it. A trailing space copied out of a web UI is invisible in most editors and survives every retry.

It started, then died about thirty seconds in

There is a startup timeout, and its default is 30 seconds: the server took longer than the default 30-second startup timeout. Servers that build an index, warm a cache or authenticate against something slow on first run hit this and look like crashes.

Separately, once running, a per-server timeout is a hard wall-clock limit per tool call, and progress notifications from the server do not extend it. A server that streams progress updates for two minutes will still be cut off — being visibly busy does not buy it more time.

Two related behaviours worth knowing before you blame the network. If an HTTP or SSE server disconnects mid-session, Claude Code reconnects automatically with exponential backoff, up to five attempts starting at a one-second delay. Stdio servers are local processes and are not reconnected automatically. And authentication and not-found errors are never retried, because they require a configuration change to resolve — so a 401 will not heal itself no matter how long you wait.

It vanished, and nothing told you why

If a server that worked last week is simply gone, and you are on a managed machine, check policy before you check your config.

If an organisation deploys a managed-mcp.json, Claude Code loads only the servers that file defines. The documentation is unusually candid about the experience this produces: "Servers users had previously configured stop loading the next time they start a session, with no warning that policy is the reason."

That is the whole symptom — no error, no notice, just absence. If you are on a work laptop and a server disappeared without you touching anything, this is the first thing to rule out. Note also that nothing overrides a denylist match, and denylists merge from every settings source regardless, so a single denied entry anywhere wins.

The permission rule that never matches

Last one, because it looks like a connection problem and is not. A server can be connected and healthy while every call to it is blocked or prompting.

MCP permission rules use the server name as configured in Claude Code, optionally followed by a tool name. mcp__puppeteer matches any tool provided by the puppeteer server. The catch is in the syntax: the server segment must be glob-free, so the rule names a specific server you configured. A wildcard in the server position does not match broadly — it fails to name a server at all.

A triage order that saves time

Work down this list rather than across your config file:

  1. Read the /mcp status and pick the right bug — empty tool list, failed connection, pending approval and not configured are four different problems.
  2. Restart the session if you changed .mcp.json at all.
  3. Check claude mcp list for missing-variable warnings before suspecting the server.
  4. Confirm the scope, and remember it cannot be changed in place.
  5. Check type on any entry that has a url.
  6. Check for pasted whitespace in tokens.
  7. If it simply disappeared on a managed machine, suspect policy.

Most of the afternoon-length versions of this problem are one of the first three.

Practise this topic

Reading about it is half of it. Answer some questions on the same material — scored instantly, explanation for every one, no login.

Sources

Rohan Surve

Rohan Surve is a Technical Product Manager in Bengaluru with 12 years in enterprise delivery and 0→1 product building. He works with Claude, Claude Code, Cursor and MCP daily, and built PrepMint after noticing how much of what he "knew" about these tools was half-remembered from documentation he'd skimmed once. Every question here is written from working with the tool and checked against the vendor's own docs.

More articles by Rohan Surve

Question banks on this subject