Add an MCP Server to Claude Code

Claude Code can read your files and run commands. It cannot see your issue tracker, your database, or a reference it was not trained on unless you connect one, and MCP is how. A server is a program, local or remote, that exposes tools Claude can call, and adding one is a single claude mcp add line. The part people get wrong is which scope they added it to and why Claude then asks permission for every call.

This post covers the add command for the 2 kinds of server, the 3 scopes and the file each one writes to, the team-shared .mcp.json, checking and signing in with /mcp, and the permission rule that lets the tools run without prompting. Commands are from the current docs, linked at the end. Claude Code itself needs to be installed first: Install Claude Code on Windows, Native and in WSL.

Add a Remote Server

HTTP is the recommended transport for anything hosted. The command takes a name you choose and the server’s URL:

claude mcp add --transport http <name> <url>

# with a bearer token or API key in a header
claude mcp add --transport http my-api https://api.example.com/mcp --header "Authorization: Bearer <token>"

If a service only publishes an SSE endpoint, the same --transport http command works: Claude Code tries HTTP first and switches to SSE when the server does not accept it (from version 2.1.265). Servers that use OAuth have no header to pass; you add them and then sign in, which is the /mcp section below.

Add a Local Server

A stdio server is a process Claude Code starts on your machine and talks to over stdin and stdout. The command that launches it goes after a double dash, and everything after the -- is passed to the server untouched, so its own flags are not mistaken for Claude’s:

claude mcp add <name> -- <command> [args...]

# a server published on npm, with an environment variable it needs
claude mcp add example --env API_KEY=<your-key> -- npx -y @example/mcp-server

# a server you wrote in Python, with its own --port flag
claude mcp add --transport stdio myserver -- python server.py --port 8080

One ordering trap from the docs: --env takes several KEY=value pairs, so if the server name comes straight after it the CLI reads the name as another pair and rejects it. Put another option such as --transport stdio between them, or put --env after the name as in the first example. A stdio server that needs Node needs Node on this machine; the native Claude Code install does not bring it.

A concrete one, if SQL Server is your work: the sqldba MCP server is a Python package that runs locally and gives Claude a hand-checked error, wait type and build reference. After pip install, the add line is claude mcp add sqldba -- sqldba-mcp; that page has the full steps.

Claude Code sets CLAUDE_PROJECT_DIR in the server’s environment to the project root, so a server you write yourself can find project files without caring about the working directory.

Scopes: Where the Server Is Saved

--scope (or -s) decides who sees the server and which file it lands in:

  • local, the default: this project only, just you. Stored in ~\.claude.json under the project path.
  • user: every project on this machine, just you. Also stored in ~\.claude.json. The right scope for a reference server you want everywhere.
  • project: everyone who clones the repo. Stored in .mcp.json at the project root, committed.
# available in every project
claude mcp add --scope user sqldba -- sqldba-mcp

# shared with the team through .mcp.json
claude mcp add --transport http shared-server --scope project https://example.com/mcp

Note the file: ~\.claude.json at the top of your profile, not ~\.claude\settings.json. That is the same file that holds your account and per-project trust, and it is where a server you cannot find in settings has gone. If the same name is defined in more than 1 scope, local wins over project, which wins over user, and claude mcp list warns about the clash.

A .mcp.json is plain JSON, and you can write it by hand. Values can reference environment variables so a team file never holds a key:

{
  "mcpServers": {
    "api-server": {
      "type": "http",
      "url": "${API_BASE_URL:-https://api.example.com}/mcp",
      "headers": {
        "Authorization": "Bearer ${API_KEY}"
      }
    }
  }
}

${VAR} expands to the variable and ${VAR:-default} falls back when it is unset. A url entry with no type is an error, because Claude Code reads a typeless entry as stdio. For safety, Claude Code asks you to approve a project’s .mcp.json servers the first time you start in that folder; claude mcp reset-project-choices clears those answers.

Check It: claude mcp list and /mcp

claude mcp list          # every configured server with a health status
claude mcp get <name>    # one server: scope, transport, and an Issue: line if it failed
claude mcp remove <name> # take it out again (add --scope if it is defined in more than 1)

Inside a session, /mcp shows the same list with the tool count per server, lets you reconnect one that dropped, disable one without deleting its configuration, and sign in to a server that uses OAuth. From the shell the sign-in is claude mcp login <name>. The statuses you will see: Connected, Needs authentication, Failed to connect with the HTTP status appended, and Pending approval for a .mcp.json server you have not approved yet.

A server that connects but shows no tools, or whose tools Claude will not call, is worth a claude mcp get. A 401 on the Issue line is a bad or missing token; claude mcp add saves whatever you gave it without checking.

Stop the Permission Prompt for Its Tools

MCP tools go through the same permission system as everything else, and their names are mcp__<server>__<tool>. Allow a whole server, or single tools, in settings.json:

{
  "permissions": {
    "allow": [
      "mcp__sqldba__*",
      "mcp__github__get_*"
    ],
    "deny": [
      "mcp__github__delete_repository"
    ]
  }
}

An allow glob only works after a literal mcp__server__ prefix, so mcp__* in allow does nothing, while mcp__* in deny blocks every MCP tool. The permissions post has the rest of the rule syntax.

Other Considerations

Only connect servers you trust. A server that fetches outside content can carry prompt injection back into your session. The docs say it; it bears repeating for a server found on a random README.

Tool output is capped. Results over 10,000 tokens show a warning and the hard limit is 25,000 by default, set with MAX_MCP_OUTPUT_TOKENS in the env block. A tool that returns a whole table is where you hit it.

Slow tools move to the background. A call still running after 2 minutes in the main conversation becomes a background task and Claude carries on; MCP_TOOL_TIMEOUT or a per-server timeout field changes the limit, and MCP_TIMEOUT is the startup timeout.

Importing from Claude Desktop with claude mcp add-from-claude-desktop is Mac and WSL only, per the help text. On native Windows, open claude_desktop_config.json and add the servers with claude mcp add-json <name> '{...}', which takes the same JSON shape.

Resources and prompts come along too. A server’s resources can be referenced as @server:protocol://path in a prompt, and its prompts appear in the / menu as /servername:promptname (MCP).

Frequently Asked Questions

Which scope should I use?

user for a reference you want in every project, project for something the whole team needs committed with the repo, and the default local for a one-off in one folder. All 3 can coexist with different servers.

I added a server and Claude does not use it.

Run /mcp. If it shows Needs authentication, sign in there. If it shows connected with 0 tools, the server exposes nothing to Claude. If it is fine, ask Claude for the task plainly; it picks tools from their descriptions.

Where is the server I added saved?

local and user scope go into C:\Users\<you>\.claude.json. project scope goes into .mcp.json in the project root. claude mcp get <name> tells you which.

Can Claude Code be an MCP server for something else?

Yes. claude mcp serve starts it as a stdio server, and the docs show the claude_desktop_config.json entry for using it from Claude Desktop. It prints nothing when it starts; silence means it is waiting for a client.

How do I pass a secret without putting it in a committed file?

Reference it as ${API_KEY} in .mcp.json and set the variable in your environment. Claude Code warns in claude mcp list when a referenced variable is missing and has no default.


Related

If SQL Server is part of your day job, my current work lives over at sqldba.blog: production DBA scripts, an error library and the SSMS guide.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Looking for SQL Server?

This site started as a SQL Server blog in 2017 and the archive is still here. The new SQL Server writing, and all the scripts, moved to a site of their own.

sqldba.blogScripts, error library, wait types, SSMS
Browse by topic