Claude Code Learning Hub
中文 Mingyu's Library

Hub / Course / D9

D9 · MCP

Wire external tools into Claude Code with the Model Context Protocol: the three transports, the claude mcp command, scopes and authentication — and how much context these tools cost.

Everything Claude does happens through tools, but the built-in set only covers local files, the shell, and the web. MCP lets you turn issue trackers, databases, browsers, and monitoring systems into tools Claude can call directly. This lesson covers the protocol itself, connecting and managing servers, and the price you pay.

Why this lesson comes today

As D1 explained, at every step of the agentic loop the model is picking a tool from the tool list to execute. The longer that list, the larger Claude's radius of action. The last two lessons — Skills and Hooks — solved knowledge injection and workflow interception respectively, but neither gave Claude any new ability to act. That is exactly the gap MCP fills: wrap an external system as new tools and plug them into that list.

With this lesson done, assigning tools to subagents in D10 Subagents and plugins bundling MCP servers for distribution in D14 Plugins have a foundation to stand on. Skip it, and every tool name prefixed mcp__... that shows up later will leave you wondering where it came from.

Core concepts, explained

What MCP is

OfficialMCP (Model Context Protocol) is an open standard that specifies how AI applications connect to external tools. Tools are provided by an MCP server — a server can be a process running on your machine or a service hosted in the cloud; Claude Code connects to them as a client, and once connected, the server's tools, resources, and prompts all become available in your session.

Our takeAn analogy: MCP is to AI tools what USB-C is to peripherals. Claude Code only has to implement one "port" (the protocol); any server that speaks the protocol plugs in and just works — no bespoke integration per service. When should you connect a server? The official heuristic is genuinely useful: Officialwhen you catch yourself repeatedly copy-pasting data from another tool (issue contents, monitoring dashboard numbers, database query results) into the conversation, it's time to wire that system up as a server and let Claude read and write it directly.

Transports: stdio, HTTP, SSE (and WebSocket)

OfficialServers come in several transports, grouped by where they run and how they communicate:

transportWhere it runsHow to add itWhen to use it
stdioLocal subprocess, launched by Claude CodeDefault transport, claude mcp add <name> -- <command>Needs local resources: browsers, the filesystem, database sockets
httpRemote URL, hosted in the cloud--transport http, supports OAuth loginRecommended for remote services (Notion, Sentry, GitHub, ...)
sseRemote URL--transport sseDeprecated; only for legacy services that expose SSE endpoints only
wsRemote URL, persistent bidirectional connectionOnly configurable via .mcp.json or add-json; no OAuthWhen the server needs to push events to Claude

OfficialThe -- separator in stdio commands matters: everything before it is Claude Code's own options (--transport, --env, --scope); everything after it is passed through verbatim as the server's launch command. Drop the -- and the server's own flags get misparsed as Claude Code options.

Claude Code agentic loop (client) tool list: built-in tools + mcp__server__tool stdio server local subprocess (command + args) HTTP server remote URL, OAuth supported SSE (deprecated) / WebSocket legacy compatibility / event push tools / resources / prompts which servers connect: ~/.claude.json (local / user) and repo-root .mcp.json (project)
Claude Code, as an MCP client, connects to several servers at once; each server's tools join the tool list under the name mcp__<server>__<tool>.

claude mcp: add, manage, remove

OfficialServer management lives under claude mcp, run in your terminal (not inside a claude session); inside a session, use the /mcp panel to check status, authenticate, and temporarily toggle a server on or off:

# Add a remote HTTP server
claude mcp add --transport http notion https://mcp.notion.com/mcp

# Add a local stdio server (everything after -- is the launch command)
claude mcp add playwright -- npx -y @playwright/mcp@latest

# With env vars / with a static token
claude mcp add --env AIRTABLE_API_KEY=YOUR_KEY --transport stdio airtable -- npx -y airtable-mcp-server
claude mcp add --transport http github https://api.githubcopilot.com/mcp/ --header "Authorization: Bearer <token>"

# List, inspect, remove
claude mcp list          # list every server with its connection status
claude mcp get notion    # details and scope for a single server
claude mcp remove notion

OfficialWhen claude mcp add prints Added ..., that only means the config was written — not that the connection works. Check the real status with claude mcp list: ✔ Connected, ! Needs authentication, ✘ Failed to connect, and so on. A stdio server may show as failed on its first check while npx is still downloading — wait a moment and retry.

Scope: where the config lives, who gets it

OfficialWhen adding a server, --scope decides where the configuration belongs — three levels:

scopeStored inApplies toTeam-shared
local (default)Under the current project's entry in ~/.claude.jsonJust you, this project onlyNo
project.mcp.json at the repo rootEveryone on this projectYes — committed to the repo
userTop-level mcpServers in ~/.claude.jsonJust you, every projectNo

OfficialTwo rules that trip people up. One: project-scope servers prompt for approval before first use, for safety (a cloned repo must not get to start processes on your machine without your consent); if you declined once and want another chance, run claude mcp reset-project-choices. Two: when the same server name is defined in multiple scopes, the entire definition is taken from the highest-priority scope — local > project > user > plugins > claude.ai connectors — fields are never merged across scopes. A server's scope is fixed once added; to change it, remove and re-add.

Authentication: OAuth and tokens

OfficialMany cloud servers (Sentry, Linear, Notion, ...) use OAuth 2.0: first claude mcp add it — at this point list shows ! Needs authentication — then run /mcp inside a session, select the server, and choose Authenticate to complete login in the browser; or run claude mcp login <name> straight from the terminal (since v2.1.186). Tokens are stored securely and refreshed automatically; claude mcp logout <name> clears them. Services that authenticate with a static token (like a GitHub PAT) take --header "Authorization: Bearer <token>" at add time. Also, connectors you added and logged into on the claude.ai web app appear automatically in the /mcp list when you log into Claude Code with the same subscription account.

How tools enter the tool list, and what they cost in context

OfficialOnce a server connects, each of its tools joins Claude's tool list under the name mcp__<server>__<tool> (for example mcp__github__get_issue); permission rules, hooks, and subagent tool configs all reference this full name. The first time Claude calls a new tool, it asks for your authorization.

OfficialOn cost: every connected server's tool names and server instructions are loaded into the context window of every single session. The good news is that tool search is on by default — full tool definitions are deferred and loaded on demand via search, so connecting several servers hits your context far less than it used to; on top of that, a single MCP tool output over 10,000 tokens triggers a warning, with a default cap of 25,000 tokens (tunable via MAX_MCP_OUTPUT_TOKENS). Our takeBut "smaller impact" is not "free": tool names, instructions, and the output of every real call keep occupying the same finite window D2 described. For diagnosing and pruning a session made slow and dumb by a pile of servers, see the tip "What happens when you install too many MCP servers".

Hands-on: doable today

Use the auth-free docs-search server from the official tutorial to walk the full add → verify → use → remove loop; it fits in 30 minutes:

  1. Register the server in your terminal (not inside a claude session): expect it to print Added HTTP MCP server claude-code-docs ... plus a File modified: line naming the config file it wrote.
  2. Run claude mcp list: expect the server to show ✔ Connected.
  3. Run claude to start a session and paste the prompt below. Expected: the first call pops a tool-authorization prompt; after you approve, the tool calls in the answer carry the claude-code-docs server name — that is your evidence the answer came from the MCP server rather than model memory.
  4. Run claude mcp get claude-code-docs: expect to see it registered in local scope. To make it available across all your projects, remove it and re-add with --scope user.
  5. Clean up (optional): claude mcp remove claude-code-docs; expect a Removed ... confirmation.
claude mcp add --transport http claude-code-docs https://code.claude.com/docs/mcp
claude mcp list
claude
# ...after experimenting in the session...
claude mcp remove claude-code-docs
Use the claude-code-docs MCP server to look up what the MCP_TIMEOUT environment
variable does, and tell me which tool call you used to get the answer.

How to know you've learned it

  • Without notes, you can explain what kind of protocol MCP is, what "server" and "client" each refer to, and the three kinds of things a server can provide (tools / resources / prompts).
  • You can state the essential difference between the stdio and HTTP transports (local subprocess vs remote URL), and the current status of SSE (deprecated).
  • You can sketch where each of the three scopes is stored and who it applies to, and explain why project scope prompts for approval.
  • All five hands-on steps ran end to end, and you can point at the exact spot in the session output that proves the answer came from the MCP server.
  • Self-check: the same server name is defined both in your local scope and in the repo's .mcp.json — which config do you connect to? What about a teammate who clones the repo? (Answer: you get the local one — local outranks project, the whole definition wins, fields don't merge; your teammate's machine has no entry in their ~/.claude.json, so they connect to the .mcp.json one — and must approve it before first use.)