- Errorfilesystem
Stdio server is missing "command", Claude Code has nothing to launch.
Fix: Add "command": "npx" (or "node", "uvx", a binary path…) with any flags in "args".
- Errorlinear
Unknown key "serverUrl", Claude Code will ignore it.
Fix: Rename "serverUrl" to "url".
{
"mcpServers": {
"filesystem": {
"command": "<command>",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"./"
]
},
"linear": {
"type": "http",
"url": "https://mcp.linear.app/mcp"
}
}
}# Adds to user scope (~/.claude.json) by default.
# Append --scope project to write a shareable .mcp.json into the repo instead.
claude mcp add filesystem -- '<command>' -y @modelcontextprotocol/server-filesystem ./
claude mcp add --transport http linear https://mcp.linear.app/mcpWhere configs live: .mcp.json = project scope (checked into the repo, shared with the team) · ~/.claude.json = user scope (what claude mcp add writes by default) · claude_desktop_config.json = Claude Desktop, a different app, same JSON shape, different file.
Three config files, one classic mix-up
Claude Code reads MCP servers from more than one place, and most “my server doesn’t show up” reports are really scope confusion. There are three scopes, and a fourth file that belongs to a different app entirely.
| File | Scope | Who gets it |
|---|---|---|
.mcp.json | Project | Everyone who clones the repo, check it in. Servers need one-time approval per user. |
~/.claude.json | User / local | What claude mcp add writes by default, your machine, every project (user) or one project (local). |
claude_desktop_config.json | Claude Desktop | The desktop chat app, a different program. Same JSON shape, zero effect on Claude Code. |
The claude_desktop_config.json trap deserves emphasis: countless tutorials target Claude Desktop, and their configs look byte-for-byte compatible. They are, but Claude Code never reads that file. If a server works in Desktop and is invisible in your terminal, this is why. For team projects, prefer project scope: a committed .mcp.json means every teammate (and every agent) gets the same tools, which matters once you start running several Claude Code sessions in parallel.
Your AI workspace for shipping software.
Download AIDEN free and point it at your existing Claude Code or Codex setup. No credit card, running in minutes.
Download AIDEN freeFree to start · macOS 12+ · No credit card required
stdio vs http vs sse, when each
A stdio server is a program Claude Code launches for you, it spawns command with args as a child process and speaks JSON-RPC over stdin/stdout. Use it for anything local: filesystem access, a database on localhost, a CLI wrapper. No port, no network, dies with the session.
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": { "DATABASE_URL": "${DATABASE_URL}" }
}
}
}A remote server is something already running elsewhere, you give Claude Code a URL instead of a command. "type": "http" (streamable HTTP) is the modern transport hosted providers use; "type": "sse" is the older Server-Sent Events variant, kept for servers that haven’t migrated yet.
{
"mcpServers": {
"linear": {
"type": "http",
"url": "https://mcp.linear.app/mcp",
"headers": { "Authorization": "Bearer ${LINEAR_TOKEN}" }
}
}
}Rule of thumb: runs on your machine → stdio; lives behind an https endpoint → http; the vendor’s docs literally say SSE → sse. If these terms are new, the AI glossary covers MCP, transports, and the rest of the agent vocabulary in one page.
Env var expansion: the right way to handle secrets
Claude Code expands ${VAR}, and ${VAR:-default} with a fallback, inside command, args, env, url, and headers when it launches a server. The token lives in your shell; the config file stays committable. This is not optional hygiene: .mcp.json is designed to be checked into git, so any literal key you paste there is one git push away from being public.
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}",
"API_BASE": "${API_BASE:-https://api.example.com}"
}The validator above warns when an env or header value looks like a real token (long, token-shaped, or matching known prefixes like ghp_ or sk-). If you see that warning on a config you’ve already committed, rotate the key, scrubbing git history is much harder than exporting a variable.
The three ways MCP configs actually break
After syntax errors (trailing commas, comments, single backslashes in Windows paths), almost every broken config falls into one of three buckets, all silent, because Claude Code skips entries it can’t use rather than crashing.
Stringified args
"args": "-y my-server ./" is one argument, not three. Args must be an array with one string per token, and numbers like ports still get quoted, because process arguments are always strings.Wrong key names
mcp_servers, serverUrl, comand, JSON has no schema, so typos don’t error, they just get ignored. The only accepted top-level key is mcpServers, exact camelCase.Secrets in the repo
${VAR} expansion, keep real values in your shell, and let the file be boring enough to commit.The same discipline that keeps configs clean keeps agents effective: explicit, checked-in, reviewable context. That’s the idea behind a good AGENTS.md / CLAUDE.md file too, and behind choosing a small set of MCP servers that actually earn their context window instead of installing everything.