04 / 20Tools7 MIN READ

MCP

The Model Context Protocol is an open standard that lets Claude Code act as a client to external servers, which expose tools, resources, and prompts that Claude can call directly.

Claude Code wired to three MCP serversA Claude Code client on the left connects over the Model Context Protocol to three servers on the right — GitHub, Figma, and Postgres — with traffic pulsing along each connection.CLAUDECODEclientGITHUBmcp serverFIGMAmcp serverPOSTGRESmcp servertools · resources · prompts

What it is

MCP is a client/server protocol. Claude Code is the client. A server is a process or an HTTP endpoint that advertises three kinds of capability: tools Claude can call, resources Claude can read by URI, and prompts that appear in your session as /mcp__<server>__<prompt> commands. Tools are the part you will use most; resources and prompts are reached through ListMcpResourcesTool, ReadMcpResourceTool, and the command menu.

Servers connect over one of four transports. http is the recommended remote transport and the only one that supports OAuth. sse still works but is deprecated. stdio runs a local process and talks to it over standard input and output, which suits anything needing direct system access. ws holds a persistent bidirectional socket for servers that push events unprompted.

Configuration lives at three scopes. Local scope, the default, stores the server in ~/.claude.json under your current project path and keeps it private to you. Project scope writes .mcp.json at the repository root so the whole team gets it. User scope stores it in ~/.claude.json for every project on your machine. When the same name appears in more than one, local wins, then project, then user, then plugin servers, then claude.ai connectors — and the whole entry from the winning source is used, with no field merging.

What it does for you

  • It ends the copy-paste loop between Claude Code and your other tools. Instead of pasting a Jira ticket into chat, Claude reads it, and instead of describing a query result, Claude runs the query.
  • It puts external state behind the same permission system as everything else. mcp__github__* in permissions.allow pre-approves one server; mcp__* in permissions.deny removes every MCP tool from Claude’s context.
  • It scales past the context budget. Tool definitions are deferred by default, so a server with sixty tools contributes its names, not sixty full schemas, and Claude loads the ones it needs through tool search.

How it works

  1. 01Claude Code reads your MCP configuration at startup

    It merges local, project, user, plugin, and connector sources, resolves duplicates by the precedence order above, and begins connecting each server.

  2. 02Project servers wait for approval

    A server defined in .mcp.json prompts in interactive sessions before it is used, and shows as ⏸ Pending approval in claude mcp list until you accept. claude -p runs, SDK sessions, and cloud sessions cannot show that prompt, so they load project servers without asking.

  3. 03Each server advertises its capabilities

    After connecting, Claude Code issues tools/list, prompts/list, and resources/list. Tool names become mcp__<server>__<tool>; a plugin-bundled server becomes mcp__plugin_<plugin>_<server>__<tool>.

  4. 04Tool definitions stay deferred by default

    Only the names enter the prompt. Claude calls ToolSearch to load the full schema of a tool it wants. Because deferred definitions sit after the cache breakpoint, a server connecting or disconnecting mid-session does not invalidate the prompt cache.

  5. 05Calls run under timeouts, then move to the background

    A main-conversation call still running after two minutes becomes a background task so the session is not blocked. A call that sends nothing for the idle window — five minutes for remote servers, thirty for stdio — aborts with an error.

  6. 06Remote servers reconnect on their own

    An HTTP or SSE server that drops mid-session is retried up to five times with exponential backoff starting at one second. Stdio servers are local processes and are not reconnected automatically.

How to implement it

  1. 01Add the server at the right scope

    Run claude mcp add --transport http <name> <url> for a personal server, add --scope project to write .mcp.json for the team, or --scope user to get it in every project.

  2. 02Pass credentials as headers or environment variables

    Use --header "Authorization: Bearer $TOKEN" for remote servers and --env KEY=value for stdio ones. In a committed .mcp.json, reference secrets as ${GITHUB_TOKEN} so the value stays out of git.

  3. 03Verify the connection

    Run claude mcp list and look for ✔ Connected. A ✘ Failed to connect line carries the HTTP status and the server’s own error text. Run /mcp inside a session to authenticate an OAuth server.

  4. 04Scope what the server may do

    Add mcp__<server>__<tool> entries to permissions.allow for the calls you want unprompted, and deny entries for anything destructive. Rules follow the same deny-then-ask-then-allow order as every other tool.

  5. 05Commit .mcp.json and document the environment variables

    Teammates get the server definition from git and supply their own credentials. Note the required variables in CLAUDE.md so a fresh clone does not fail silently.

Examples

.mcp.jsonjson
{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/",
      "headers": {
        "Authorization": "Bearer ${GITHUB_MCP_TOKEN}"
      }
    },
    "figma": {
      "type": "http",
      "url": "https://mcp.figma.com/mcp"
    },
    "postgres": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "DATABASE_URL": "${DATABASE_URL:-postgres://localhost:5432/app_dev}"
      },
      "timeout": 60000
    }
  }
}
A project-scoped configuration wiring GitHub, Figma, and Postgres. Secrets come from the environment, never from the file.
.claude/settings.jsonjson
{
  "enabledMcpjsonServers": ["github", "figma", "postgres"],
  "permissions": {
    "allow": [
      "mcp__github__get_*",
      "mcp__github__list_*",
      "mcp__figma__*",
      "mcp__postgres__query"
    ],
    "deny": [
      "mcp__postgres__execute"
    ]
  }
}
Approve the project servers for the team and draw the trust boundary: reads are free, writes still prompt, and the destructive call is blocked outright.

Use it when

  • Implementing a ticket end to end: Claude reads the issue from your tracker and opens the pull request without you pasting either.
  • Answering questions against a real database instead of guessing from the schema file.
  • Turning a Figma frame into components, with the design read directly rather than described.
  • Checking a monitoring dashboard mid-debug so the error rate in the conversation is the live one.
  • Letting a server push events into your session as a channel, so Claude reacts to CI results while you are away.

Avoid it when

  • A CLI already does the job. gh, psql, and aws are one Bash permission rule away and cost no tool definitions, no connection, and no failure mode.
  • You do not trust the server. An MCP server that fetches external content can feed prompt-injection payloads straight into your session, and its tools run with your credentials.
  • The server exposes dozens of tools you will never call and tool search is unavailable in your configuration, because then every definition sits in the cached prefix and every reconnect invalidates it.
  • You need the connection to be reliable in CI. Project servers load without approval under -p, stdio servers are not auto-reconnected, and a failed connection is reported in the init event rather than failing the run.

Common mistakes

  • SYMPTOMA server in .mcp.json never connects and Claude behaves as if its tools do not exist.

    FIXRun claude mcp list. ⏸ Pending approval means you have not approved the project server yet; start claude interactively and accept. ✘ Failed to connect now carries the status code and the server’s error text.

  • SYMPTOMA remote entry fails with command: expected string, received undefined or a message about a missing type.

    FIXAn entry with a url but no type is read as a stdio server. Add "type": "http" — or "sse"/"ws" — to the entry.

  • SYMPTOMAuthentication fails intermittently after you paste a token into the config.

    FIXA pasted token often carries a trailing newline. Claude Code warns about Leading or trailing whitespace in: headers.Authorization in /mcp and claude mcp list, but it does not trim it — edit the file.

  • SYMPTOMAdding a stdio server on the command line fails to parse the server’s own flags.

    FIXPut -- before the command: claude mcp add --env KEY=v --transport stdio db -- python server.py --port 8080. Everything after -- is passed through untouched.

  • SYMPTOMEvery session starts with an expensive uncached turn after you add a server.

    FIXThat happens when tool definitions load into the prompt instead of being deferred. Check whether tool search is disabled by a custom ANTHROPIC_BASE_URL, ENABLE_TOOL_SEARCH=false, or an alwaysLoad marker on the server.

Best practices

  • Prefer http for remote servers; SSE is deprecated and WebSocket supports neither OAuth nor the --transport flag.
  • Keep credentials in environment variables referenced as ${VAR} from .mcp.json, never as literals in a committed file.
  • Read the server’s source or its Directory listing before connecting it, and treat everything it returns as untrusted input.
  • Write allow rules per tool rather than per server, so read calls are frictionless and writes still stop for approval.
  • Set a per-server timeout on anything slow, and remember it is a hard wall-clock limit that progress notifications do not extend.
  • Run /mcp when something behaves oddly: it shows connection state, tool counts, and the server’s own error text.

Try it in five minutes

Connect a stdio MCP server, see its tools appear, and watch a deny rule remove one.

  1. 1.Run claude mcp add --transport stdio memory -- npx -y @modelcontextprotocol/server-memory in any project.
  2. 2.Run claude mcp list and confirm the server shows ✔ Connected.
  3. 3.Start claude, run /mcp, and note the tool count next to the server.
  4. 4.Ask Claude to store and then recall a fact, and watch the mcp__memory__* tool calls in the transcript.
  5. 5.Add "deny": ["mcp__memory__*"] under permissions in .claude/settings.json, start a new session, and confirm in /mcp that the tools are gone from Claude’s context.

Verified against code.claude.com/docs/en/mcp on 2026-08-09. See content/SOURCES.md for the full table.

← / → MOVE BETWEEN CONCEPTS