Home / Blog / Claude Code

How to add an MCP server to Claude Code

Connecting an MCP server to Claude Code is one command. The part that actually matters is the choice that command hides: which of three scopes the server lands at, and therefore whether it's a private convenience or a tool your whole team gets on clone. Get the scope right and your tooling becomes a reviewable part of the codebase, not a thing someone toggled on their laptop. Here's the mechanic, with the real config we ship to clients.

The short answer

You add an MCP server to Claude Code with claude mcp add. The minimal form for a local server is claude mcp add --transport stdio <name> -- <command>, and for a remote one it's claude mcp add --transport http <name> <url>. Where that configuration gets written depends on the scope you pick, and that scope decision is the part that actually matters, because it's the difference between a server only you can use and one your whole team gets on clone.

That's the whole mechanic. The rest of this guide is about the choice the command hides: which of three scopes you add the server at, what file each one writes to, and how a server a teammate committed gets trusted before Claude Code will run it. If you're still deciding whether you even need a server, our explainer on what an MCP server is covers that first; this is the how-to once you've decided you do.

Adding a server: the command

The shape is claude mcp add [options] <name> -- <command> [args...] for a local stdio server, where everything after the -- is the command Claude Code runs to launch the server. For a remote server you swap the command for a URL and set the transport: claude mcp add --transport http <name> <url>.

A stdio server is a local process Claude Code starts and talks to over standard input and output. Adding the Shopify server we wrote, which runs as a Python process, looks like this:

claude mcp add --transport stdio shopify -- python /path/to/shopify_server.py

The -- matters. It separates Claude Code's own flags, like --transport, --env, and --scope, from the command that runs the server. Everything to the right of -- is passed through untouched, so claude mcp add --transport stdio db -- npx -y @some/db-server --port 8080 runs npx -y @some/db-server --port 8080 as the server. If your server needs a secret, pass it with --env:

claude mcp add --env SHOPIFY_TOKEN=shpat_xxx --transport stdio shopify -- python /path/to/shopify_server.py

One quirk worth knowing: --env reads pairs greedily, so if the server name comes right after it, the CLI tries to parse the name as another KEY=value and errors. Put another flag between --env and the name, like --transport above, and it's fine.

A remote server is even shorter, because there's no command to launch, just a URL to connect to:

claude mcp add --transport http notion https://mcp.notion.com/mcp

Once a server is added, claude mcp list shows everything configured, claude mcp get <name> shows one server's details, and claude mcp remove <name> deletes it. Inside a session, /mcp opens a panel that shows each connected server, its tool count, and lets you authenticate remote servers that need OAuth.

The three scopes, and why the choice matters

Every server you add lands at one of three scopes: local (the default, private to you, current project only), project (shared with your team via a committed .mcp.json file), or user (private to you, but available across all your projects). You pick with --scope, and the choice decides both who else gets the server and which file it's written to.

This is the decision the add command quietly makes for you, and getting it wrong is how a server ends up in the wrong place. Here's what each scope does:

ScopeLoads inShared with team?Stored in
local (default)Current project onlyNo~/.claude.json
projectCurrent project onlyYes, via version control.mcp.json in project root
userAll your projectsNo~/.claude.json

Local is the default, and it's right for a server you're experimenting with or one whose credentials you don't want anywhere near version control. It loads only in the project where you added it and stays on your machine.

User scope is for your personal toolkit, a server you want in every project you open, like a scratch database or a utility you reach for constantly. Still private to you, just not pinned to one repo.

Project scope is the one that does real work on a team, and it's the reason this post exists.

Project scope: the .mcp.json your team commits

A project-scoped server is written to a .mcp.json file at the repo root, which you commit. Anyone who clones the repo gets the same server, so the tools travel with the code instead of living in a setup doc. You add one with claude mcp add --scope project, and Claude Code creates or updates the .mcp.json for you.

Run this and Claude Code writes the server into .mcp.json:

claude mcp add --scope project shopify -- python ./mcp/shopify_server.py

The resulting file is the standard MCP format, an mcpServers object keyed by name, each with a command, its args, and an env block:

{
  "mcpServers": {
    "shopify": {
      "command": "python",
      "args": ["./mcp/shopify_server.py"],
      "env": {}
    }
  }
}

You can hand-edit this file directly, it's just JSON, and for anything beyond a one-liner I usually do. Keep secrets out of it: reference an environment variable with ${VAR} expansion in the command or args rather than pasting a token into the committed file. Anything secret belongs in the environment, which ties back to the env key in settings.json covered in the Claude Code settings.json guide, not in a file you push to GitHub.

This is the weld between building a server and using it. Our Python MCP server walkthrough ends with a working shopify_server.py; the .mcp.json above is how that server gets in front of Claude Code for the whole team, committed once, trusted on clone.

Why a committed server still asks before it runs

Claude Code does not automatically trust project-scoped servers from a .mcp.json you cloned. The first time it sees one, it prompts you to approve it, because an .mcp.json can launch an arbitrary process and a repo you cloned is not automatically safe. You approve interactively, and if you ever need to re-decide, claude mcp reset-project-choices clears your approvals so you're asked again.

This is the right default, and it's worth understanding rather than clicking through. The .mcp.json file says "run this command," and that command is real code with your permissions. A malicious or careless repo could ship an .mcp.json that launches something you didn't intend. So Claude Code treats a freshly cloned project server as untrusted until you say otherwise, the same default-deny posture that runs through the whole permissions model.

A server awaiting your decision shows up in claude mcp list as pending approval, so you can see what's waiting before you run a session. For automated or non-interactive setups where there's no one to click a prompt, the approval moves into settings.json: the enabledMcpjsonServers key approves specific project servers by name, and enableAllProjectMcpServers trusts all of them. That's the same gate we lean on in production, and it's covered in detail in the settings.json guide linked above. The interactive prompt and the settings keys are two doors to the same room: deliberately deciding which committed servers are allowed to run.

How we run this across client projects

In our setup, every client repo carries its own committed .mcp.json with exactly the servers that client's work needs, and which servers are trusted is pinned in settings.json by name, never left to enableAllProjectMcpServers. A new server doesn't run because it showed up in a repo; it runs because someone added it to the allowlist in a file we review.

Running Claude agents across client projects, the .mcp.json is per client and committed with that client's code, so the agent that works on a client gets exactly that client's tools and nothing else. The read-only Shopify server is approved by name in the clients that sell on Shopify and absent everywhere else. We don't use enableAllProjectMcpServers, because "trust whatever appears" is the opposite of what a multi-tenant boundary needs. Each server earns its place in the allowlist explicitly, reviewed like any other change.

The payoff is that adding a tool to a client is a committed, reviewable diff, not a setting someone toggled on their laptop. The server definition lives in .mcp.json, the decision to trust it lives in settings.json, both are in version control, and both travel with the repo. The tools an agent can reach are part of the codebase, not a property of whose machine is running it.

The mistakes worth skipping

  1. Adding at the wrong scope. The default is local, so a server you meant to share with the team ends up private in ~/.claude.json and your teammates wonder why their Claude can't see it. If it's for the team, say --scope project.
  2. Pasting secrets into .mcp.json. That file gets committed. Use ${VAR} expansion and keep the actual value in the environment, or the token is in your git history forever.
  3. Forgetting the -- on a stdio server. Without it, the command and its args get parsed as Claude Code's own flags and the add fails or misbehaves. Everything that launches the server goes after --.
  4. Expecting a cloned server to just work. It won't run until you approve it, by design. If a teammate's server isn't showing up, check claude mcp list for a pending-approval state, or set the server in enabledMcpjsonServers for a non-interactive environment.
  5. Assuming approval scopes to individual tools. Approving a project server trusts the process it launches, not the individual tools. Scope what a server can reach the same way you'd scope any code running with your permissions.

Connecting an MCP server to Claude Code is one command. Deciding which scope it lives at, and which committed servers you actually trust, is the part that determines whether your tooling is a private convenience or a reviewable part of the codebase your whole team and every agent inherits.

Frequently asked questions

How do I add an MCP server to Claude Code?

Use claude mcp add. For a local server the form is claude mcp add --transport stdio <name> -- <command>, where everything after the -- is the command that launches the server. For a remote server it's claude mcp add --transport http <name> <url>. Pass secrets with --env KEY=value.

Where does Claude Code store MCP server config?

It depends on the scope. Local-scoped servers (the default) and user-scoped servers are stored in ~/.claude.json. Project-scoped servers are written to a .mcp.json file at the repo root, which you commit so the whole team gets them on clone.

What's the difference between local, project, and user scope?

Local scope (the default) is private to you and loads only in the current project. User scope is also private to you but loads in all your projects. Project scope is shared with your team through a committed .mcp.json file and loads in that project for everyone who clones it.

Why won't Claude Code use an MCP server from a cloned repo?

Because project-scoped servers from .mcp.json are not trusted automatically. Claude Code prompts you to approve a server the first time it sees it, since an .mcp.json can launch an arbitrary process. Approve it interactively, or for non-interactive setups list it in enabledMcpjsonServers in settings.json. Run claude mcp reset-project-choices to clear your approvals.

P

Pavle Lazic is the founder of Scalably, where he builds and runs multi-tenant Claude agent platforms in production for real businesses. He writes about the Claude Agent SDK, MCP servers, and what it actually takes to put AI agents to work. See the platform.