mdskills
guides

How to Use MCP Servers with Claude Code (Full Setup Guide)

person using MacBook Pro
Photo by Glenn Carstens-Peters on Unsplash

Out of the box, Claude Code can't touch your GitHub repo, your Postgres instance, or any REST API you haven't pasted into the chat. MCP servers close that gap. You point Claude at a running server (local process or remote endpoint) and it starts reading and acting on those systems directly.

The catch: local and remote servers are configured differently, and getting the transport type wrong is the usual reason a setup silently fails to connect. This guide walks you through a working install, the stdio-vs-HTTP decision, project vs. global scoping, and the errors you'll actually hit.

Prerequisites

You need Claude Code installed and working from your terminal, so claude mcp add and claude mcp list resolve. If you plan to run a local stdio server, you also need whatever runtime that server ships in: Node for anything installed via npx, Python for uvx or python -m servers. Remote servers only need a reachable URL and, usually, an auth token.

You should also be comfortable hand-editing JSON. The CLI writes config for you, but every real troubleshooting session ends in .mcp.json or ~/.claude.json anyway.

Stdio or HTTP?

MCP defines four transports and Claude Code supports all of them, but in practice the choice is binary: HTTP for cloud-hosted services, stdio for anything on your own machine. The other two (SSE and WebSocket) exist for edge cases.

  • HTTP (streamable-http) is the most widely supported transport for cloud-based services. It's the only remote transport that supports OAuth, and it's the only one the claude mcp add --transport flag accepts alongside sse. If a vendor gives you a URL, this is almost always what you want.
  • Stdio runs the server as a local process that Claude Code spawns and talks to over standard input and output. It's the right choice for tools that need direct filesystem or system access, custom scripts, or anything you've written yourself.
  • SSE is a legacy remote transport. It works, but HTTP is better if the server offers both.
  • WebSocket (ws) holds a persistent bidirectional connection, useful when the server needs to push events unprompted. It doesn't support OAuth, authentication is header-only, and claude mcp add --transport doesn't accept ws. You configure it by hand in JSON.

Remote URL from a vendor: HTTP. Local binary or script: stdio. Only reach for SSE or WebSocket when the server documentation specifically demands them.

Remote HTTP servers

The CLI form is:

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

Claude Code writes the entry and tries to connect on the next session start. Any server in the Anthropic Directory uses the same MCP infrastructure as Claude Code, so you can point claude mcp add at a directory server's URL and it will work.

Editing config directly instead? The equivalent entry in .mcp.json or ~/.claude.json:

{
  "mcpServers": {
    "linear": {
      "type": "http",
      "url": "https://mcp.linear.app/mcp"
    }
  }
}

A note on the type field. First, streamable-http is a valid alias for http. The MCP spec uses streamable-http as the transport name, so if you copy a config snippet from a vendor's docs and see "type": "streamable-http", leave it alone. Second, and this is the failure mode that catches everyone: an entry with a url and no type is broken. More on that in a moment.

HTTP servers authenticate via a static token in the headers field, or a dynamic one generated at connect time by headersHelper. The headersHelper runs a command you specify and uses its output as the header value, which is how you plug in short-lived OAuth tokens or credentials from a secrets manager instead of pasting a long-lived token into a config file.

Local stdio servers

The CLI form uses -- to separate the server name from the command Claude Code should spawn:

claude mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem /path/to/project

In JSON, omit type. Stdio is the default when there's a command:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"]
    }
  }
}

Claude Code sets CLAUDE_PROJECT_DIR in the spawned server's environment to the project root. Read it as process.env.CLAUDE_PROJECT_DIR in Node or os.environ["CLAUDE_PROJECT_DIR"] in Python. It's the stable project root and doesn't change when you add or remove working directories mid-session, which matters for servers that resolve project-relative paths.

One gotcha with ${VAR} expansion in command or args. CLAUDE_PROJECT_DIR is set in the server's environment, not Claude Code's, so if you reference ${CLAUDE_PROJECT_DIR} in a .mcp.json command line, it won't expand. Use a default like ${CLAUDE_PROJECT_DIR:-.} for project- or user-scoped entries. Plugin-provided MCP configurations are the exception: they substitute ${CLAUDE_PROJECT_DIR} directly.

To limit a stdio server's filesystem access, don't hardcode paths. Implement the MCP roots/list request instead. Claude Code answers roots/list with the session's launch directory plus every additional working directory granted with --add-dir, /add-dir, or the additionalDirectories setting, and it sends notifications/roots/list_changed when that set changes (as of v2.1.203).

Project scope vs. user scope

claude mcp add writes to one of two config files. Project scope (--scope project) writes to .mcp.json at the repo root; check it in and every collaborator gets the same server list. User scope (--scope user) writes to ~/.claude.json and applies to every project on your machine.

Project scope has one twist: a .mcp.json in a cloned repo can't auto-approve its own servers. That would let anyone with commit access run arbitrary code on your machine the first time you opened their repo. So Claude Code gates project servers behind a workspace trust dialog.

As of v2.1.196, claude mcp list and claude mcp get read .mcp.json approvals from checked-in settings files only after you run claude interactively in the workspace and accept the trust dialog. Until then, enableAllProjectMcpServers and enabledMcpjsonServers values committed to the project's .claude/settings.json are ignored, and every project server sits at ⏸ Pending approval instead of connecting.

Approvals from these sources still apply in an untrusted folder:

  • your user ~/.claude/settings.json
  • managed settings
  • settings passed with --settings

Approvals in an untracked .claude/settings.local.json also apply, but Claude Code needs to run git to confirm the file isn't tracked, and it only runs git in a trusted folder. So in a folder you've never trusted, .claude/settings.local.json approvals wait for the trust dialog too, unless the folder is your configuration home (your home directory, or a directory whose .claude you've set as CLAUDE_CONFIG_DIR).

A disabledMcpjsonServers entry, wherever it lives, overrides everything. If a server name shows up in that list in any settings file, it stays rejected.

The missing type field

This one config mistake eats hours of debugging time. Consider:

{
  "mcpServers": {
    "my-api": {
      "url": "https://api.example.com/mcp"
    }
  }
}

Looks fine. It's broken. Claude Code reads any entry with no type as a stdio server, then tries to find a command, finds none, and drops the entry. As of v2.1.202 the error is at least legible: MCP server "<name>" has a "url" but no "type"; add "type": "http" (or "sse" / "ws") to this entry. Before v2.1.202 the same misconfiguration reported command: expected string, received undefined, with no hint that type was the culprit.

Add "type": "http" (or "sse", or "ws") and reconnect from /mcp.

Two other silent failures to watch for:

  • Reserved names. workspace, claude-in-chrome, computer-use, Claude Preview, and Claude Browser belong to Claude Code's built-in servers. Define one of these yourself and claude mcp add rejects it upfront; if it slipped into a hand-edited config, Claude Code skips the entry at load time with a warning to rename it. Watch out on older installs: before v2.1.205, Claude Browser wasn't reserved, and a pre-existing user config with that name will now collide with the desktop app's preview pane server.
  • Empty url. A remote server with an empty url shows as not configured everywhere (/mcp, claude mcp list, /plugin) and Claude Code doesn't try to connect. This is deliberate, so a plugin can ship a placeholder entry for a connector you'll fill in later.

On retries: HTTP and SSE servers reconnect with exponential backoff, up to five attempts starting at one second and doubling. Stdio servers do not. If a stdio server crashes, Claude Code will not restart it for you.

Security

Every server you add is code Claude can invoke with your credentials against systems you care about. Treat the install list the way you'd treat production SSH keys.

What works in practice:

  • Vet the maintainer. Prefer servers listed in the Anthropic Directory, since those are reviewed connectors running on the same MCP infrastructure as Claude Code. For anything else, read the source before you add it.
  • Scope filesystem access. For servers that touch files, have them implement roots/list and use Claude Code's working-directory model instead of granting broad read/write to your home directory.
  • Separate dev and prod credentials. Different server entries, different tokens. Don't reuse a production database URL in the same server config you use for local hacking.
  • Uninstall stale servers. A server you added six months ago for a one-off task is still running with your credentials. It's a liability, not a convenience.

Team deployments are harder. Individual .mcp.json files in per-developer repos won't give you auth rotation, audit logs, or scoped per-user credentials. That's the case for an MCP gateway sitting between your team and the servers themselves, giving you a single governed front door instead of N unmanaged direct connections.

Verifying the connection

Two CLI commands and the in-session /mcp panel.

claude mcp list

That prints every configured server with a status marker. Three statuses are worth knowing. ⏸ Pending approval (run claude to approve): you added a project-scoped server but haven't accepted the trust dialog for that workspace yet. ✘ Rejected: some settings file has this server in its disabledMcpjsonServers list. not configured: the url is empty.

claude mcp get <name>

That shows the full status for one server, including its connection error if the server failed to connect. This is your first stop when something isn't working.

In an active session, /mcp opens the server panel. It shows the tool count next to each connected server and flags any server that advertises the tools capability but exposes zero tools (usually a sign the server started up but its tool registration failed).

After five failed reconnects, a server moves to failed and stays there. Fix the config and reconnect it from /mcp manually.

When servers won't connect

Roughly in the order you'll hit them:

Authentication errors. Claude Code does not retry these, because they need a config change to fix. A 401 or 403 in claude mcp get means your token is bad in some way (usually expired, sometimes missing a required scope). Fix it in the headers field (or update whatever headersHelper returns) and reconnect.

Initial connection failures. As of v2.1.121, Claude Code retries the initial connection up to three times on transient errors (5xx responses, connection refused, timeouts). Not-found errors are not retried. After three misses it marks the server failed.

Mid-session disconnects. HTTP and SSE servers reconnect automatically with exponential backoff up to five attempts. Stdio servers do not reconnect. If a stdio server dies, you restart it manually (usually by exiting and restarting Claude Code, since the process was spawned as a child).

Idle timeouts. A tool call that goes quiet (no response, no progress notification) for the idle window gets aborted. Default is five minutes for remote transports and claude.ai connector servers. Stdio gets 30 minutes as of v2.1.203; earlier versions exempted it entirely. For legitimate long-running calls, set CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT in milliseconds (or 0 to disable). A per-server timeout of at least 1000 floors the idle timeout as well.

"Which server failed?" With tool search enabled (the default), Claude Code passes connection errors to Claude, and Claude names the failed server in its reply. Without tool search, Claude sees nothing and answers as if the server's tools never existed. Tool search is off with custom ANTHROPIC_BASE_URL, ENABLE_TOOL_SEARCH=false, Amazon Bedrock, Google Cloud's Agent Platform, and Microsoft Foundry. In those setups, check claude mcp list directly.

Next steps

Start with Filesystem and GitHub. That's enough to cover the core dev loop: structured file access on one side, repo/issue/PR operations on the other. Add PostgreSQL the first time you're debugging against real data. Add Playwright when you need browser automation.

Once you're past the basics, browse the Anthropic Directory for reviewed connectors, and consider building your own with the mcp-server-dev plugin or by having Claude scaffold one for you. If you're rolling this out to a team, plan the auth, audit, and credential story before you hand out .mcp.json files: an MCP gateway is the cleanest way to keep the number of ungoverned direct connections at zero.

Frequently asked questions

How do I add an MCP server to Claude Code?

Run claude mcp add --transport http <name> <url> for a remote HTTP server, or claude mcp add <name> -- <command> [args] for a local stdio server. Both write the entry to your config automatically. The remote form defaults to project scope; pass --scope user for a global install.

What is the difference between a local and remote MCP server in Claude Code?

Local stdio servers run as processes on your machine that Claude Code spawns and talks to over standard I/O. They're the right choice for direct system access or custom scripts. Remote servers are cloud-hosted endpoints reached over HTTP, SSE, or WebSocket. HTTP is the recommended remote transport and the only one that supports OAuth.

Which MCP servers should I install first for Claude Code?

Filesystem and GitHub cover the core dev workflow. Add PostgreSQL for backend and data debugging, and Playwright for browser automation. Everything else depends on the systems your team actually touches.

How do I configure MCP servers per project vs. globally in Claude Code?

Use claude mcp add --scope project to write to .mcp.json at the repo root so collaborators pick up the config. Use --scope user to write to ~/.claude.json so the server applies to every project on your machine.

Can Claude Code use MCP servers that require authentication?

Yes. HTTP servers support OAuth and static headers. Pass tokens via the headers field or generate them at connect time with headersHelper. WebSocket servers are header-only with no OAuth support. Stdio servers get credentials through their spawned process environment.

How do I troubleshoot an MCP server that isn't connecting in Claude Code?

Run claude mcp get <name> to see the connection error. If the server has a url but no type in JSON, add "type": "http". For authentication failures, fix credentials, since Claude Code doesn't retry auth errors. Stdio servers don't auto-reconnect after a crash, so restart them manually. HTTP and SSE servers retry initial connections three times and reconnects five times before marking themselves failed.

Are MCP servers safe to use with Claude Code?

Every server adds attack surface. Prefer reviewed connectors in the Anthropic Directory, read the source before adding third-party servers, scope filesystem access with roots/list instead of broad grants, and keep dev and prod credentials in separate server entries. Uninstall servers you no longer use.

What is the MCP Connector and how is it different from self-hosted MCP servers?

The MCP Connector is Anthropic's platform-native remote MCP feature, referenced in the Claude platform docs at platform.claude.com/docs/en/agents-and-tools/mcp-connector. Self-hosted MCP servers are your own process or endpoint, configured via .mcp.json or ~/.claude.json and managed with claude mcp add.

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "HowTo", "headline": "How to Use MCP Servers with Claude Code (Full Setup Guide)", "description": "Exact CLI commands and config syntax to add local and remote MCP servers to Claude Code, plus scoping, trust, and troubleshooting." } </script> <!-- rankwright-verify: 12 numeric claims, 5 unsupported (0 high-severity) -->
how to use mcp servers with claude code

Related Articles