How do you add an MCP server to Claude Code?
You add one withclaude mcp add, and the exact form depends on the transport: claude mcp add --transport http <name> <url> for a remote server, or claude mcp add <name> -- <command> [args...] for a local process over stdio. That's the whole setup. The interesting question isn't how to connect a server — it's what connecting it costs you afterwards, which is the part the quickstarts skip.
I build token-reduction tooling, so I look at MCP from an angle most setup guides don't: every server you connect advertises its tool definitions to the model, and it does that on every turn, whether you invoke a single tool or none at all. Setup is a one-time act. The bill is recurring. This article covers both halves — the mechanics first, honestly and completely, then the accounting nobody publishes.
Here are the three forms you'll actually use:
# Remote server over HTTP
claude mcp add --transport http notion https://mcp.notion.com/mcp
# Local server over stdio (the -- separator is required)
claude mcp add airtable -- npx -y airtable-mcp-server
# With an environment variable
claude mcp add --env AIRTABLE_API_KEY=key airtable -- npx -y airtable-mcp-server
claude mcp add --transport http notion https://mcp.notion.com/mcp
# Local server over stdio (the -- separator is required)
claude mcp add airtable -- npx -y airtable-mcp-server
# With an environment variable
claude mcp add --env AIRTABLE_API_KEY=key airtable -- npx -y airtable-mcp-server
-- separator matters: it tells Claude Code where its own options end and the server's command begins. Leave it out and your server's flags get parsed as Claude's.
Two notes on transports. SSE still works but HTTP is the preferred form for remote servers now. And WebSocket has no CLI flag at all — if you need type: "ws", you go through claude mcp add-json with a raw JSON string.
Which scope should you use — local, project, or user?
Use--scope project for anything your teammates also need, --scope user for tools you want in every project, and the default local for everything else. The scope decides which file the entry lands in, and that decides who else gets it.
| Scope | Flag | Written to | Who sees it |
|---|---|---|---|
| Local (default) | --scope local | ~/.claude.json, under the current project | Just you, just here |
| Project | --scope project | .mcp.json in the project root | The team, via version control |
| User | --scope user | ~/.claude.json, top level | Just you, everywhere |
user. It's convenient — connect once, available in every repo — and it's also the fastest way to end up paying for a server's manifest inside projects that have no use for it. A database MCP loaded into a static-site repo is pure overhead on every turn you take there. I keep user scope for genuinely universal tools and push everything else down to project.
On Windows, ~/.claude.json resolves to %USERPROFILE%\.claude.json. If you've set CLAUDE_CONFIG_DIR, that wins.
What does .mcp.json actually look like?
.mcp.json lives in your project root, gets committed to version control, and holds a single top-level mcpServers object keyed by server name.
{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": { "Authorization": "Bearer ${GITHUB_TOKEN}" }
},
"postgres": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": { "DATABASE_URL": "${DATABASE_URL}" }
}
}
}
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": { "Authorization": "Bearer ${GITHUB_TOKEN}" }
},
"postgres": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": { "DATABASE_URL": "${DATABASE_URL}" }
}
}
}
url, headers, and optionally timeout (milliseconds), oauth and headersHelper. Stdio entries take command, args and env.
One trap worth knowing: an entry with no type field is treated as stdio. Pair that omission with a url and you get a configuration error rather than a working server, which is a confusing failure the first time you meet it. Set type explicitly and the problem never occurs.
Because .mcp.json is committed, Claude Code asks for approval before trusting project-scoped servers — a sensible guard, since a pulled branch could otherwise wire a new server into your session silently. claude mcp reset-project-choices clears those approvals if you need to re-decide.
How do you pass secrets without committing them?
Use${VAR} expansion in .mcp.json so the file holds the name of the secret, never its value.
The syntax works in url, headers, command, args and env, and it supports defaults:
"url": "${API_BASE_URL:-https://api.example.com}/mcp",
"headers": { "Authorization": "Bearer ${API_TOKEN}" }
"headers": { "Authorization": "Bearer ${API_TOKEN}" }
${VAR} substitutes the environment variable; ${VAR:-default} falls back when it's unset. That's what makes a committed .mcp.json safe: the token lives in your shell or your secret manager, and the repo carries only the reference.
For credentials that have to be minted at connect time — short-lived tokens, signed requests — there's headersHelper. You point it at an executable, it runs fresh on every connection with a 10-second budget, and it prints a JSON object of headers to stdout. Claude Code hands it CLAUDE_CODE_MCP_SERVER_NAME and CLAUDE_CODE_MCP_SERVER_URL in its environment so one script can serve several servers.
For OAuth servers you usually need nothing at all: HTTP and SSE servers negotiate OAuth 2.0 automatically, and the /mcp panel walks you through the browser sign-in. claude mcp login <name> and claude mcp logout <name> handle it from the CLI when you'd rather not leave the terminal.
How do you check a server is actually connected?
Runclaude mcp list from the shell, or /mcp inside a session — both show every configured server with its live status.
The statuses you'll see are worth learning, because they fail in genuinely different ways:
✔ Connected— working.! Connected · tools fetch failed— the transport is up but the tool list didn't come back. The server is reachable and useless.! Needs authentication— runclaude mcp login <name>, or authenticate from the/mcppanel.✘ Failed to connect— unreachable. Usually a wrong URL, a dead local command, or a missing environment variable.⏸ Pending approval— a project-scoped server waiting on your trust decision.
claude mcp get <name> prints the full resolved config for one server, which is the fastest way to find out that your ${API_TOKEN} expanded to nothing.
The /mcp panel has one more number on it that matters more than people realise: the tool count per server. That number is the closest thing you get to a price tag, and the next section is about why.
What does each connected server cost you per turn?
Every connected server's tool definitions are sent to the model on every turn, so a server you never invoke still bills you for as long as it stays connected. This is the single most important fact about MCP that setup guides omit, and it's structural, not a bug — the model can't call a tool it hasn't been told about. Here's where I have to be straight with you, because this is where most articles start inventing numbers: almost nobody publishes what their manifest costs. I went looking. Third-party estimates for popular servers circulate widely and contradict each other by tens of thousands of tokens, which tells you they're measurements of different versions under different conditions rather than facts. I'm not going to repeat them as if they were. What you can get is scale, from what vendors actually publish. GitHub's official MCP server ships 20 toolsets and exposes 56 read-only tools before the write ones are counted — every schema advertised to the model on every turn unless you narrow the set. You don't need a token figure to see that a manifest that size, re-sent across a thirty-turn session, is not a rounding error. So measure rather than guess. Two readings tell you nearly everything:- Tool count in
/mcp. Manifest size scales with the number of tools and the verbosity of their schemas. A server exposing 40 tools is not in the same weight class as one exposing 4. /contextat the start of a session, before you type anything. Whatever is already occupying your context window on turn zero is your standing overhead. Connect a server, restart, look again, and the difference is that server's real price on your setup.
How do you keep the tools without paying for the idle ones?
You defer the manifest — send a server's tool definitions when a tool is actually called rather than pre-loading them on every turn. That's lazy MCP loading, and it's the structural fix rather than a discipline you have to remember. The manual version is simply hygiene: connect what this session needs, disconnect the rest, and preferproject scope over user so servers don't follow you into repos that don't want them. That works. It also depends on you doing it every day, which is exactly the kind of consistency that erodes under a deadline.
Tokenade closes that gap by loading MCP tool definitions lazily inside Claude Code — and Cursor, Codex, Copilot and Windsurf, since the manifest problem is identical everywhere — so idle servers stop riding along on every turn. It also compresses what noisy tools return, which is the other half of the MCP bill. It's source-available under MIT, so you can read exactly what it does to your context before trusting it with a session, and the free tier is enough to see whether the numbers move on your own setup.
Whichever route you take, the principle is the same: connecting a server should be a decision you make per project, not a default you inherit. Which MCP servers earn their place works through that trade-off server by server.
Can servers give you more than tools?
Yes — servers can also expose resources you reference with@ and prompts that appear as slash commands, though support varies because each server chooses what to implement.
Resources autocomplete when you type @, using the form @servername:protocol://resource/path — @github:issue://123, say, or @postgres:schema://users. Claude Code fetches and attaches the resource when you reference it. This is a genuinely cheaper pattern than a tool call for read-only lookups: you pull one specific thing instead of describing a search.
Prompts show up when you type /, as /mcp__servername__promptname — /mcp__github__list_prs, for instance, with arguments space-separated after it. They're discovered dynamically from whatever is connected.
What goes wrong (anti-patterns)
Installing servers atuser scope by default. It's the convenient flag and the expensive one. Every project you open pays for every tool you've ever connected, including the ones irrelevant to that repo.
Connecting a server "to try it" and never disconnecting. The trial costs nothing. The forgetting costs on every turn, forever, silently.
Trusting third-party manifest-size numbers. They contradict each other because they measure different versions. Measure your own with /context; it takes two minutes.
Omitting type in .mcp.json. No type means stdio. With a url present, that's a configuration error and a confusing first debugging session.
Committing secrets into .mcp.json. The file is designed to be committed. Use ${VAR} expansion — the repo should carry the name of the secret, never the value.
Judging a server by its tool count alone. Ten terse tools can cost less than four with sprawling schemas. The count is a proxy, /context is the measurement.
Frequently asked questions
What's the difference between .mcp.json and ~/.claude.json?
.mcp.json sits in your project root and is meant to be committed — it's how a team shares the same servers. ~/.claude.json is your personal file: --scope local writes there under the current project, --scope user writes there at the top level for all projects. Rule of thumb: if a teammate cloning the repo would need the server, it belongs in .mcp.json.
Does an MCP server cost tokens if I never call its tools?
Yes. Tool definitions are advertised to the model on every turn regardless of use — that's how the model knows the tools exist. An idle server is a standing per-turn cost, which is why disconnecting unused servers is one of the cheapest wins available. Token-efficient MCP tool use covers the schema and output sides in depth.How do I find out what a specific server costs me?
Run/context in a fresh session before typing anything, note the figure, connect the server, restart, and compare. The difference is that server's real per-turn overhead on your machine at its current version — which is more reliable than any published estimate, since manifests change between releases.
Why does my project-scoped server show "pending approval"?
Because.mcp.json is version-controlled, Claude Code asks before trusting servers it finds there — otherwise pulling a branch could wire a new server into your session without you noticing. Approve it in the /mcp panel; claude mcp reset-project-choices clears past decisions if you want to re-approve from scratch.
Can I use the same MCP servers in Cursor or Codex?
Largely yes — MCP is a shared protocol, so a server written for one agent generally works in another, though each host differs in configuration format and in which parts of the spec it implements. The per-turn manifest cost carries over unchanged, which is why the levers in how to reduce AI coding agent token usage are agent-agnostic.See also:
- Best Claude Code MCP servers, ranked by real cost — which ones earn their standing overhead.
- Lazy MCP loading — the structural fix for idle manifests.
- Token-efficient MCP tool use — cutting schema and output cost.
- MCP servers: what they are and what they cost — the agent-agnostic overview.
- GitHub MCP server: setup and what it costs — toolsets, read-only mode, and trimming the manifest.
- MCP (Model Context Protocol) — what the protocol is, in one page.
- How to reduce Claude Code token usage — the pillar this branches from.
Ranked #1 on the Token-Harness Optimizer Leaderboard.
Tokenade ranks #1 in the Token-Harness Optimizer Leaderboard — an end-to-end benchmark of agent token optimizers measured on real coding sessions. Set it up once, it works on every prompt. Works with Claude Code, Cursor, Codex, Copilot & more.