Fix 'MCP Server Failed to Connect' in Claude Code (2026)
Model Context Protocol servers are how Claude Code reaches beyond its built-in tools — into your database, your issue tracker, a browser, your filesystem. When they work, they’re invisible. When they don’t, you get four blunt words in claude mcp list:
✗ Failed to connect
No stack trace. No hint. And because the same server often works perfectly in Claude Desktop or when you run it by hand, the error feels like a Claude Code bug. It usually isn’t. “Failed to connect” is a transport-layer message — it means Claude Code couldn’t even start a conversation with the server, let alone call a tool. That narrows the problem enormously, and it’s what makes this fixable in minutes once you know the decision tree.
This guide is that decision tree. It’s built from the official Claude Code MCP troubleshooting docs, the open bug reports (like issue #1611), and the failure modes that actually show up in day-to-day use. If you just want the fast path, start with the 60-second triage. If you want to understand why it broke — so it stays fixed — read on.
New to MCP itself? Read What is MCP (Model Context Protocol)? first, then come back here to debug it.
The 60-second triage
Before anything else, run these two commands in your shell (not inside a claude session):
claude mcp list # status of every configured server
claude mcp get <name> # the exact command / URL + scope Claude Code stored
Then branch on what you see:
Status in claude mcp list | What it means | Jump to |
|---|---|---|
✓ Connected | Healthy — your problem is elsewhere | — |
✗ Failed to connect | Server didn’t start / URL didn’t respond | stdio · HTTP |
✗ Connection error | The connection attempt threw | stdio · HTTP |
! Needs authentication | Reachable, but requires sign-in / token | Auth |
! Connected · tools fetch failed | Connected but couldn’t list tools | No tools |
⏸ Pending approval | Project server you haven’t approved yet | Approval |
| (nothing / “No MCP servers”) | Wrong scope or wrong file path | Scope |
The single highest-value move in all of MCP debugging: take the command from claude mcp get and run it yourself. Everything below is a structured way of doing exactly that.
The mental model: transport before tools
An MCP connection has two layers, and “Failed to connect” is always the lower one:
Your prompt
│
▼
┌───────────────┐
│ TOOL LAYER │ "search issues", "query db" ← works only if the layer below is up
└───────────────┘
▲
│ ← "Failed to connect" lives HERE
┌───────────────┐
│ TRANSPORT │ stdio: a subprocess on your machine
│ LAYER │ http/sse: a request to a URL
└───────────────┘
So the first question is never “why won’t the tool run?” It’s “can Claude Code even reach the server?” And that splits cleanly by transport type:
┌─────────────────────────────┐
│ claude mcp get <name> │
│ type = ? │
└─────────────┬───────────────┘
│
┌───────────────────┴────────────────────┐
▼ ▼
type: "stdio" type: "http" / "sse"
(command + args) (a url)
│ │
Run the command curl -I <url>
directly in a shell │
│ ┌───────────┼────────────┐
┌───────┴────────┐ ▼ ▼ ▼
▼ ▼ 404 / 405 401 / 403 no response
starts & errors: URL path is authenticate URL / network
waits missing Node, wrong (/mcp or is wrong
→ config bug browser, key, --header)
(see below) PATH
Find your branch, then jump to it. If claude mcp get won’t even show your server, you’re in the scope / path branch, not this one.
Fix a local (stdio) server
A stdio server is a program Claude Code launches as a subprocess and talks to over standard input/output — filesystem, Playwright, most npx-based servers. “Failed to connect” here means the process didn’t start, or died on launch.
Step 1 — Run the exact stored command by hand
Copy the command and args from claude mcp get <name> and run them directly:
npx -y @playwright/mcp@latest
Two outcomes, two very different diagnoses:
- It starts and just waits for input (no prompt returns, no error). The server is healthy. Your problem is that Claude Code is storing or launching a different command than the one you just ran. Go to Step 2.
- It errors immediately. The message names what’s missing — Node.js not found, a browser not installed, a bad package name, a missing API key. Fix that, then re-check
claude mcp list.
Step 2 — The missing -- separator (the #1 stdio mistake)
When you add a stdio server, everything after -- is the command Claude Code runs. Omit the separator and Claude Code mis-parses the pieces — storing the wrong command, or treating your args as its own flags:
# ❌ WRONG — no separator, args get swallowed
claude mcp add fs npx -y @modelcontextprotocol/server-filesystem /data
# ✅ RIGHT — everything after -- is the server's launch command
claude mcp add fs -- npx -y @modelcontextprotocol/server-filesystem /data
Run claude mcp get fs. If the stored command doesn’t match what you typed, remove and re-add it with the --:
claude mcp remove fs
claude mcp add fs -- npx -y @modelcontextprotocol/server-filesystem /data
Step 3 — PATH and Node/npx problems
Claude Code inherits a PATH that may not match your interactive shell — especially with Node installed via nvm, fnm, asdf, Homebrew, or Volta. Symptoms: the command works in your terminal but “Failed to connect” in Claude Code, and running it by hand is fine.
Fixes, in order of preference:
- Pin the package version so
npxdoesn’t stall resolving “latest”: use@playwright/mcp@latest(or a fixed version), never a bare package name. - Use an absolute path to the binary or interpreter if PATH is the issue:
claude mcp add fs -- /usr/local/bin/node /abs/path/to/server.js /data - Check your Node version.
npx-based servers need Node 18+.nvm’s default may be older than the version you think you’re on — verify withnode -vin the same environment Claude Code launches from. (This site’s build notes the same trap: the machine default can lag behind the version you use interactively.)
Step 4 — Windows: wrap npx in cmd /c
On Windows, npx (and most npm-installed tools) is a .cmd shim, not a real executable, and Claude Code can’t always spawn it directly. Route it through the command interpreter:
# ❌ Fails on Windows — npx is a .cmd shim
claude mcp add fs -- npx -y @modelcontextprotocol/server-filesystem C:\data
# ✅ Works — run it through cmd /c
claude mcp add fs -- cmd /c npx -y @modelcontextprotocol/server-filesystem C:\data
The equivalent in .mcp.json:
{
"mcpServers": {
"fs": {
"type": "stdio",
"command": "cmd",
"args": ["/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "C:\\data"]
}
}
}
Step 5 — Missing environment variables
If the server connects but shows no tools — or exits right after launch — it’s usually missing a required env var (an API key). See The server connects but no tools appear.
Fix a remote (HTTP) server
A remote server lives at a URL (--transport http or sse). Here “Failed to connect” means the HTTP request didn’t get a usable response. Diagnose it with one command:
curl -I https://mcp.sentry.dev/mcp
PowerShell: use
curl.exe, notcurl. Plaincurlis an alias forInvoke-WebRequestand won’t behave like real curl.
Read the status code like a map:
| curl result | Diagnosis | Fix |
|---|---|---|
404 or 405 | Server is up, your URL path is wrong. Many MCP endpoints answer only POST, so a 404/405 still proves reachability. | Compare to the server’s documented endpoint; claude mcp remove <name> and re-add with the correct URL. |
401 or 403 | Server is up, you must authenticate. | OAuth or token |
200 | Reachable and open. Problem is elsewhere (client version, headers). | Update Claude Code; re-add. |
| No response | URL is wrong or the network/VPN/firewall is blocking it. | Verify the URL; test from another network. |
As of Claude Code v2.1.191, a 404 now surfaces a precise message when you select the server in /mcp — MCP endpoint not found at <url>. Check the URL in your MCP config. — with the exact URL it tried. Older versions show a generic Error POSTing to endpoint, which is why upgrading (claude update) is a good early move.
Authentication (401 / 403 and “Needs authentication”)
Two auth shapes, two fixes:
OAuth (browser sign-in) — Sentry, Linear, Notion and similar:
/mcp # inside a claude session
# → select the server → choose "Authenticate" → approve in browser
If the browser doesn’t open, copy the URL printed in the terminal and open it manually.
Static token — GitHub and similar. Pass it at add time:
claude mcp add --transport http github https://api.githubcopilot.com/mcp \
--header "Authorization: Bearer <YOUR_TOKEN>"
“Connection timed out at startup”
This is a distinct status: the server is correct, but it didn’t finish starting inside the default 30-second startup window — classic for an npx server downloading its package on first run.
Raise the limit with MCP_TIMEOUT (milliseconds):
# macOS / Linux
MCP_TIMEOUT=60000 claude
# PowerShell — set on the same line
$env:MCP_TIMEOUT = "60000"; claude
Two things worth knowing:
MCP_TIMEOUTis startup only. For slow tool calls after connection, add a per-server"timeout"(ms) inside that server’s.mcp.jsonentry — e.g."timeout": 600000for a 10-minute tool.- Warm the cache first. Running the server’s command once by hand downloads the package, so the next Claude Code startup is fast and may not need the bumped timeout at all.
”No MCP servers configured”
You added a server, but /mcp or claude mcp list shows nothing. This is never a connection failure — it’s Claude Code looking in the wrong place. Two causes.
Cause 1 — Wrong scope
claude mcp add defaults to local scope, which ties the server to the exact directory you ran it from. Open Claude Code in a different project and it’s gone. The three scopes:
| Scope | File | Visible to |
|---|---|---|
local | ~/.claude.json (under this project’s entry) | Only you, only this project (default) |
project | .mcp.json in the repo root | Everyone who clones the repo |
user | ~/.claude.json (top-level mcpServers key) | Only you, all projects |
Precedence when the same name exists in more than one: local › project › user.
Want a server everywhere? Add it at user scope:
claude mcp add --scope user --transport http docs https://code.claude.com/docs/mcp
Cause 2 — Wrong file path
Claude Code reads only ~/.claude.json and <project>/.mcp.json. It ignores hand-written configs at paths people commonly guess:
✗ ~/.claude/mcp.json
✗ ~/.claude/config/mcp.json
✗ ~/.claude/.mcp.json
✗ %APPDATA%\Claude\mcp.json ← that's Claude *Desktop*, a different app
On Windows, ~/.claude.json is %USERPROFILE%\.claude.json. If you’ve set CLAUDE_CONFIG_DIR, Claude Code reads .claude.json from inside that directory instead.
Migrating from Claude Desktop? Don’t copy
claude_desktop_config.jsonby hand — runclaude mcp add-from-claude-desktop(macOS/WSL).
.mcp.json changes that never take effect
.mcp.json is read at session start. Edit it, and you must exit and restart the session — a live /mcp reconnect won’t pick up new entries.
If a server still won’t appear after restart:
- Run
/mcpand look for a parse warning — Claude Code skips malformed entries and names the bad field. A trailing comma or unquoted value is the usual culprit. - If you previously rejected a project-scoped server at the approval prompt, that “no” is remembered. Reset it:
claude mcp reset-project-choices - A
⏸ Pending approvalstatus just means you haven’t approved a project server yet — run/mcp, select it, approve.
Environment-variable expansion in .mcp.json
You don’t have to hard-code secrets. .mcp.json expands ${VAR} inside the command, args, env, url and headers fields, with ${VAR:-default} for a fallback:
{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp",
"headers": { "Authorization": "Bearer ${GITHUB_MCP_TOKEN}" }
},
"db": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@some/db-mcp"],
"env": { "DATABASE_URL": "${DATABASE_URL:-postgres://localhost:5432/dev}" }
}
}
}
A “Failed to connect” that only happens on a teammate’s machine is often an unset variable here — the reference expands to empty, and the server rejects the bad URL or missing key.
The server connects but no tools appear
A green ✓ Connected with an empty tool list (or ! Connected · tools fetch failed) means the transport is fine but the server registered nothing — nearly always a missing required env var, usually an API key. The server starts, sees no key, and exposes zero tools rather than crashing.
Supply the variable:
# at add time
claude mcp add mydb --env DATABASE_URL=postgres://... -- npx -y @some/db-mcp
# or in .mcp.json
"env": { "DATABASE_URL": "postgres://..." }
Then restart the session and check /mcp. If it’s an HTTP server, tools fetch failed more often points at auth or a wrong endpoint — run claude mcp get <name> for the detail.
The macOS keychain / AbortError case (issue #1611)
A stubborn variant, tracked in issue #1611: a server that works perfectly in Claude Desktop and when run by hand, but fails only in the Claude Code CLI on macOS, with symptoms like AbortError: child process aborted, a keychain lookup failure (security find-generic-password ... "Claude Code" — item not found), and empty log directories under ~/Library/Caches/claude-cli-nodejs/.
If this is you:
- Update first —
claude update. Platform-integration bugs like this get patched; check whether your version still reproduces it. - Prefer a fully-qualified command over relying on inherited environment — absolute
nodepath plus absolute server path, so the subprocess can’t inherit a broken PATH or shell state. - Check the cache/log directory exists and is writable —
~/Library/Caches/claude-cli-nodejs/. A missing or permission-locked cache dir has been part of the repro. - Try user scope in
~/.claude.jsonrather than a project.mcp.json, to rule out project-approval and per-directory state as a factor.
This is the one class of failure where “it’s not you, it’s a known bug” can genuinely be true — so confirm your version against the issue before spending an hour on your own config.
Common mistakes checklist
- ❌ Forgetting
--before a stdio command → wrong command stored. (Verify withclaude mcp get.) - ❌ Adding a server at local scope, then opening a different project and wondering where it went.
- ❌ Editing
~/.claude/mcp.json— a path Claude Code never reads. - ❌ On Windows, calling
npxwithout acmd /cwrapper. - ❌ Confusing Claude Code (CLI) config with Claude Desktop (
claude_desktop_config.json) — different apps, different files. - ❌ Assuming a 404 from
curlmeans “broken.” For MCP endpoints it usually means “reachable, wrong path.” - ❌ Not restarting the session after editing
.mcp.json. - ❌ Committing a real token into project
.mcp.jsoninstead of using${VAR}expansion.
Best practices to prevent this
- Pin versions.
@latestor a fixed version beats a bare package name — no surprise resolution stalls at startup. - Prefer
--scope userfor personal tools you always want, and--scope project(committed.mcp.json) for team tools. Use local scope only for throwaway experiments. - Keep secrets out of config via
${VAR:-default}expansion; document required vars in your README. - Add servers one at a time and run
claude mcp listafter each — a batch that “all fails” is harder to bisect. - Prune servers you don’t use. Every connected server loads its tool definitions into every session’s context window, so dead servers cost you tokens and attention on every turn.
claude mcp remove <name>when you’re done.
Quick-reference: symptom → fix
| Symptom | Most likely cause | First command to run |
|---|---|---|
✗ Failed to connect (stdio) | Bad command / PATH / missing -- | claude mcp get <name>, then run the command by hand |
✗ Failed to connect (http) | Wrong URL or auth | curl -I <url> |
! Needs authentication | OAuth / token required | /mcp → Authenticate, or --header |
Connection timed out at startup | npx download > 30s | MCP_TIMEOUT=60000 claude |
No MCP servers configured | Wrong scope or file path | claude mcp add --scope user ... |
Connected but no tools | Missing API-key env var | --env KEY=value / .mcp.json env |
| Works in Desktop, fails in CLI (macOS) | Known platform bug | claude update; see #1611 |
Edited .mcp.json, nothing changed | Session not restarted | Exit and relaunch claude |
Keep learning: official sources and talks
Primary sources (current as of July 2026):
- Claude Code Docs — Connect to MCP servers (quickstart + troubleshooting) · MCP reference · Environment variables
- Model Context Protocol — Introduction · Build a server
- GitHub — claude-code issue #1611 (macOS CLI connection bug) · Report a new issue
Useful searches (try on YouTube — Anthropic and developer channels):
- “Claude Code MCP server failed to connect fix”
- “claude mcp add stdio vs http transport”
- “MCP server Windows npx cmd /c Claude Code”
- “Claude Code MCP_TIMEOUT startup timeout”
Go deeper on this site: What is MCP? · The rise of AI agents · Fixing context window exceeded errors · What is context engineering? · How large language models actually work
The reason “Failed to connect” feels mysterious is that it collapses a dozen distinct problems into one message. But every one of those problems answers to the same reflex: reproduce the connection outside Claude Code. Run the stdio command in a terminal; curl the HTTP URL. The moment you do, the vague four-word error becomes a specific one — missing Node, wrong path, 404, expired token — and specific errors have specific fixes. Get that reflex into your fingers and MCP stops being a black box. It’s just a subprocess, or an HTTP request, that hasn’t told you what it needs yet.