The quick answer
You add an MCP server to Claude Code with the claude mcp add command, not by hand-editing a JSON file. For a remote service:
$claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
For a local server that runs as a subprocess:
$claude mcp add --transport stdio db -- npx -y @bytebase/dbhub --dsn "postgresql://readonly:pass@host:5432/db"
Then run claude mcp list to confirm it registered, or /mcp inside a session to see live connection status and authenticate remote servers. One thing to get out of the way first: Claude Code does not read claude_desktop_config.json. That file belongs to the Claude Desktop app. Claude Code keeps its server config in ~/.claude.json and in per-project .mcp.json files, and the CLI writes those for you. (Claude Code MCP docs)
Pick a transport before you pick a command
Claude Code speaks three transports worth knowing, and which one you use determines the shape of the claude mcp add command.
- stdio runs the server as a local subprocess and talks to it over standard in/out. Use it for anything that needs direct access to your machine: a database client, a filesystem server, a local script.
- HTTP (Streamable HTTP) connects to a remote server over the network. This is the recommended transport for cloud services like Sentry, Notion, or GitHub's hosted server, and it's the only one that supports OAuth.
- SSE is the older two-endpoint remote transport. It's deprecated. Reach for it only when a vendor still offers nothing but an SSE endpoint. (Claude Code MCP docs)
In .mcp.json and in claude mcp add-json, the type field accepts streamable-http as an alias for http, so a config block copied straight from a vendor's docs works without renaming the transport. (Claude Code MCP docs)
Adding a remote HTTP server
This is the common case in 2026, because most hosted MCP servers are reachable over HTTP. The syntax is the server name followed by its URL.
$claude mcp add --transport http notion https://mcp.notion.com/mcp
If the server authenticates with a static token rather than OAuth, pass it with --header:
$claude mcp add --transport http secure-api https://api.example.com/mcp \$ --header "Authorization: Bearer your-token"
For servers that use OAuth (most of the well-known ones), add the server without a header, then authenticate interactively, covered below. (Claude Code MCP docs)
Adding a local stdio server
A stdio server is a command Claude Code launches and supervises. The important detail is the -- separator: everything before it is a flag for Claude Code, and everything after it is the command line that runs your server, passed through untouched.
$claude mcp add --env AIRTABLE_API_KEY=YOUR_KEY --transport stdio airtable \$ -- npx -y airtable-mcp-server
Without the --, Claude Code would try to interpret your server's own flags (a --port, say) as its own options and reject them. Pass secrets and configuration into the subprocess with one or more --env KEY=value flags. One quirk: if the server name comes immediately after --env, the CLI reads the name as another KEY=value pair, so keep at least one other flag (like --transport stdio) between --env and the name. (Claude Code MCP docs)
A real example, a read-only PostgreSQL server:
$claude mcp add --transport stdio db -- npx -y @bytebase/dbhub \$ --dsn "postgresql://readonly:pass@prod.db.com:5432/analytics"
Inside the spawned process Claude Code sets CLAUDE_PROJECT_DIR to the project root, so a server can resolve project-relative paths without depending on the working directory it happened to be launched from. (Claude Code MCP docs)
Scopes: where the server lives and who sees it
Every claude mcp add writes the server into one of three scopes. The scope decides which projects the server loads in and whether it travels with your repository. (Claude Code MCP docs)
| Scope | Loads in | Shared with team | Stored in |
|---|---|---|---|
local (default) | Current project only | No | ~/.claude.json |
project | Current project only | Yes, via version control | .mcp.json in project root |
user | All your projects | No | ~/.claude.json |
Set the scope with --scope:
# Default: private to you, this project only$claude mcp add --transport http stripe https://mcp.stripe.com# Across every project you work on$claude mcp add --transport http hubspot --scope user https://mcp.hubspot.com/anthropic# Checked into the repo for the whole team$claude mcp add --transport http paypal --scope project https://mcp.paypal.com/mcp
A few things worth internalizing about scope:
localanduserboth live in~/.claude.json. The difference is not the file, it's where inside it. A local server is nested under your current project's path so it only loads there; a user server is stored globally so it loads everywhere. (Claude Code MCP docs)- MCP "local scope" is not the same as
settings.local.json. MCP local-scoped servers go in~/.claude.json; the general.claude/settings.local.jsonfile in your project is unrelated. The reused word "local" trips people up. (Claude Code MCP docs) projectscope writes.mcp.jsonat the repo root, the one file here meant to be committed. When a teammate first runs Claude Code in a repo that ships project-scoped servers, Claude Code prompts before trusting them, since the config can launch arbitrary commands. To reset those approval choices, runclaude mcp reset-project-choices. (Claude Code MCP docs)
When the same server name is defined in more than one scope, Claude Code uses the highest-precedence definition (local, then project, then user) and takes that entry whole. Fields are not merged across scopes. (Claude Code MCP docs)
Authenticating a remote server with OAuth
Most hosted servers require a sign-in. Claude Code handles OAuth 2.0 for you, but the flow is interactive, so it's a two-step move: add the server, then authenticate.
$claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
Then, inside a Claude Code session, open the panel and follow the browser prompt:
/mcpClaude Code marks a remote server as needing authentication when it responds with 401 Unauthorized or 403 Forbidden, which surfaces it in /mcp with an option to sign in. Tokens are stored in your system keychain (or a credentials file) and refreshed automatically, and you can revoke access from the same panel with "Clear authentication." (Claude Code MCP docs)
If you'd rather not drop into a session to do it, recent Claude Code versions can run the OAuth flow straight from your shell:
$claude mcp login sentry
On a headless box (an SSH session, or Linux with no display) the command prints the authorization URL instead of trying to open a browser; open it locally and paste the redirect URL back at the prompt. Force that behavior anywhere with --no-browser. Clear stored credentials later with claude mcp logout sentry. (Claude Code MCP docs)
A note on servers that predate automatic OAuth: if adding one fails with "Incompatible auth server: does not support dynamic client registration," register an OAuth app in the vendor's developer portal, then pass the credentials with --client-id and --client-secret (the latter prompts with masked input). If the vendor requires a fixed redirect URI, pin the callback port with --callback-port to match it. (Claude Code MCP docs)
Two worked examples
GitHub for code review
GitHub's hosted MCP server lives at https://api.githubcopilot.com/mcp/ and authenticates with a fine-grained personal access token passed as a header. Generate a token scoped to the repositories you want Claude to touch, then add it. The older @modelcontextprotocol/server-github npm package is archived, so prefer the remote server.
$claude mcp add --transport http github https://api.githubcopilot.com/mcp/ \$ --header "Authorization: Bearer YOUR_GITHUB_PAT"
After it connects you can ask for things like "Review PR #456 and suggest improvements" or "Show me all open PRs assigned to me," and Claude works against the live repo instead of whatever you paste. (Claude Code MCP docs, reference server archive)
Context7 for up-to-date library docs
Context7 serves version-specific documentation so Claude isn't guessing at an API from training data. Its remote endpoint is https://mcp.context7.com/mcp, and an API key (free, from the Context7 dashboard) raises your rate limit.
$claude mcp add --transport http --scope user context7 https://mcp.context7.com/mcp \$ --header "CONTEXT7_API_KEY: YOUR_API_KEY"
If you'd rather run it locally instead of hitting the hosted endpoint, the package is published on npm and runs over stdio:
$claude mcp add --transport stdio --scope user context7 \$ -- npx -y @upstash/context7-mcp --api-key YOUR_API_KEY
(Context7 client docs, upstash/context7)
Adding from JSON, and from Claude Desktop
When a vendor hands you a ready-made config block, claude mcp add-json takes the JSON directly rather than making you translate it into flags. The server name comes first, then the JSON string:
$claude mcp add-json weather-api '{"type":"http","url":"https://api.weather.com/mcp","headers":{"Authorization":"Bearer token"}}'
It works for stdio servers too, with "type":"stdio", a command, args, and env. Add --scope user to install it across all projects, and verify with claude mcp get weather-api. (Claude Code MCP docs)
Already have servers set up in Claude Desktop? Import them rather than retyping. This is also the correct way to "move" a claude_desktop_config.json setup into Claude Code: not by pointing Claude Code at that file, but by importing its contents into the files Claude Code does read.
$claude mcp add-from-claude-desktop
The command shows an interactive picker of the servers in your Claude Desktop config and copies the ones you select. It works on macOS and Windows Subsystem for Linux, reads the Desktop config from its standard location, and pass --scope user to land the imports in your user config. (Claude Code MCP docs)
Environment variables in .mcp.json
The point of committing .mcp.json is that the whole team gets the same servers, but you can't commit a teammate's API key or a machine-specific path. Claude Code expands environment variables inside .mcp.json to bridge that gap. It supports ${VAR} and ${VAR:-default}, in the command, args, env, url, and headers fields.
{
"mcpServers": {
"api-server": {
"type": "http",
"url": "${API_BASE_URL:-https://api.example.com}/mcp",
"headers": {
"Authorization": "Bearer ${API_KEY}"
}
}
}
}So the committed file references ${API_KEY}, and each developer supplies the real value in their own shell. If a referenced variable is unset and has no default, Claude Code fails to parse the config rather than connecting with a blank value. (Claude Code MCP docs)
Managing and checking servers
Once servers exist, four commands cover day-to-day management:
$claude mcp list # every configured server and its status$claude mcp get github # the full config for one server$claude mcp remove github # delete a server
/mcp # inside a session: live status, tool counts, OAuthThe /mcp panel is the one to keep open while debugging. It shows the tool count next to each connected server and flags servers that claim a tools capability but expose none, which usually means the server started but failed to initialize properly. Project-scoped servers from a .mcp.json you haven't approved yet show up as ⏸ Pending approval in both claude mcp list and /mcp until you accept them in an interactive session. (Claude Code MCP docs)
When a server won't connect
A handful of failure modes account for most "it's not showing up" reports.
- stdio server fails immediately. The command in your
--clause has to run on its own first. Try it in a plain terminal. Ifnpx -y some-servererrors there, it'll error the same way under Claude Code. A chatty server that writes to stdout instead of stderr also breaks stdio, since stdout is the protocol channel. - Remote server stuck on auth. A
401/403means it wants OAuth: open/mcpand sign in, or runclaude mcp login <name>. Note that if you set anAuthorizationheader and the server rejects it, Claude Code reports a hard failure rather than falling back to OAuth, so an invalid static token looks like a broken server. Drop the header to use the OAuth flow instead. (Claude Code MCP docs) - Server is there but Claude isn't using its tools. With MCP Tool Search on (the default in 2026), tool definitions are deferred and discovered on demand rather than all loaded up front, which keeps your context window free as you add servers. From your side the tools work as before. If you want a specific server's tools always visible without a search step, set
"alwaysLoad": trueon its entry. (Claude Code MCP docs) - Wrong server is winning. If a name is defined in two scopes, remember the precedence order (local over project over user) and that the entry is taken whole, not merged.
claude mcp get <name>shows you which definition is actually in effect.
Where to go next
With servers connected, point Claude at them in plain language ("check Sentry for the top errors today," "open a GitHub issue for this bug") and it calls the right tools. Two things make the setup durable: put servers your whole team needs in project scope so they ride along in .mcp.json, and put your personal utilities in user scope so they follow you between repos. Keep /mcp handy for the moments a server drops or needs re-authentication.
Once your own MCP server is running against real clients, the next question is operational: which tools actually get called, what arguments come in, and where calls error or stall. That visibility is what AgentCat provides for production MCP servers.
Related Guides
Quickstart with Claude Code
Get started with Claude Code in minutes. Learn essential commands and features to boost your development workflow.
Using OpenAI's Codex Plugin in Claude Code
Install OpenAI's Codex plugin in Claude Code, run second-opinion reviews, delegate tasks to Codex, and know which auth each side needs.
Which plan to choose: Pro, Max 5x, Max 20x
Compare Claude Code subscription plans to find the perfect fit for your development needs and usage patterns.