MCP is an open standard for wiring tools into AI applications, and Claude Code speaks it out of the box. Compare it to a memory file: memory holds fixed context, an MCP server hands over the current state — open issues, rows from the production database, the latest monitoring alert. The docs offer a simple rule of thumb: if you keep copying data from another window into the chat, that system belongs behind a server. This module walks through the transports, then storage locations and precedence, tool search, a few patterns from real use — and finally channels, where the server sends something on its own.
Connecting servers
There are four transports. http is the recommended route to remote servers, stdio launches a local process, sse is deprecated and only worth it for servers without an HTTP endpoint, and ws holds a persistent two-way connection. Two things trip people up in the JSON form: streamable-http is an accepted alias for http there, so examples copied from a server vendor work unchanged — and an entry with a url but no type is a configuration error, because without type Claude Code reads it as a stdio server and skips it with a message. ws supports header authentication only and cannot be added through --transport.
# Add a remote HTTP server
claude mcp add --transport http notion https://mcp.notion.com/mcp
# Add a local Node.js server via stdio
claude mcp add --transport stdio github -- npx @modelcontextprotocol/server-github
# Add with an auth header
claude mcp add --transport http my-api https://api.example.com/mcp \
--header "Authorization: Bearer $MY_TOKEN"
Management runs through claude mcp list, claude mcp get and claude mcp remove; inside a session /mcp shows status, the tool count per server, and sign-in. Since v2.1.186 OAuth no longer needs a session: claude mcp login runs the flow in your shell, claude mcp logout clears the stored credentials. With no local browser — over SSH, say — the command prints the authorization URL, you open it on your own machine and paste the full redirect URL at the prompt; --no-browser forces that path. Add to that claude mcp reset-project-choices for approvals you already gave, claude mcp add-from-claude-desktop for moving over from Claude Desktop, and claude mcp serve when Claude Code should act as a server itself. Names like workspace or computer-use are reserved for built-in servers and get rejected.
Two files hold the configuration: ~/.claude.json for everything that concerns only you, and .mcp.json in the project root for everything the team shares. The project file goes into version control, and whoever opens it first is asked to approve it. Both forms expand environment variables — in command, args, env, url and headers, written as ${VAR} or ${VAR:-default} for a fallback. If a variable is unset and has no default, the configuration still loads: claude mcp list warns, and the text stays unexpanded — so the server fails when connecting, not when loading:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}
}
}
For a single session — an experiment, a CI run, a reproduction for a bug report — --mcp-config loads servers from JSON files without touching your saved configuration. The flag takes one path or several, space-separated, so a shared base and local deviations can be layered. --strict-mcp-config hides every other source alongside it; together they are the shortest route to a failure someone else can reproduce:
# Load a single config file for this session only
claude --mcp-config ./ci-servers.json
# Combine multiple files (space-separated)
claude --mcp-config "./shared-servers.json ./local-overrides.json"
# Reproduce a bug against exactly one server, ignoring user/project config
claude --strict-mcp-config --mcp-config ./repro.json
At startup Claude Code no longer waits for servers: since v2.1.142 they connect in the background and their tools appear as they finish — MCP_CONNECTION_NONBLOCKING set to 0 brings back the old blocking behaviour with its five-second wait. It happens in batches: up to 20 remote servers at once, up to 3 local stdio processes, adjustable through MCP_REMOTE_SERVER_CONNECTION_BATCH_SIZE and MCP_SERVER_CONNECTION_BATCH_SIZE. If your request needs a tool from a server that is still connecting, Claude waits at that point instead of answering without the tool.
Several dials control time limits, and they bite at different places. MCP_TIMEOUT caps the connection attempt at startup. A timeout field in milliseconds on the server entry caps a single tool call — hard wall-clock, progress notifications do not extend it, and values below 1000 are ignored; MCP_TOOL_TIMEOUT applies instead, whose default sits at roughly 28 hours. For HTTP, SSE and connector servers there is also a 60-second window until the first response byte. A server that sends nothing at all runs into the idle abort: five minutes for HTTP, SSE, WebSocket and connectors, 30 minutes for stdio, adjustable through CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT. And a call in the main conversation that runs longer than two minutes moves into a background task as of v2.1.212 instead of blocking the session.
Sign in with a claude.ai account and the connectors you set up there show up in Claude Code without further work — but they are only loaded while exactly that sign-in is active; an ANTHROPIC_API_KEY, an apiKeyHelper or a third-party provider switches them off. If a server you added yourself points at the same URL as a connector, your own entry wins, and /mcp lists the connector as hidden. Organizations can set an individual connector tool to ask — then Claude Code prompts on every call and deliberately does not remember your answer — or to blocked, in which case Claude never sees the tool. The whole source can be switched off through disableClaudeAiConnectors.
Scopes, precedence, and tool search
Three scopes decide where a server lives and who sees it. Local scope is the default: the entry lands in ~/.claude.json under your project path, applies only there, and stays private to you. Project scope writes to .mcp.json and shares the server with the team through version control. User scope also lives in ~/.claude.json, but across projects — good for tools you need in every project. Only the name is confusing: for MCP servers, "local" does not mean .claude/settings.local.json, it means the file in your home directory.
When the same server appears in more than one place, Claude Code connects it once — using the entry from the strongest source, and using all of it: fields are not merged across scopes. The order is local, project, user, plugin servers, claude.ai connectors. The three scopes match duplicates by name, plugins and connectors by endpoint — so anything pointing at the same URL or the same command counts as the same server. In practice: you can override the team version of a server locally without anyone else noticing.
A server’s prompts show up as slash commands in the form /mcp__servername__promptname, and its resources go inline mid-sentence as @server:protocol://resource/path. The tool definitions themselves are held back by default: only names and the server instructions load at startup, and Claude searches for the rest when a task needs it — which is why an extra server barely costs context. ENABLE_TOOL_SEARCH changes that: true forces deferral, false loads everything at session start, auto loads upfront as long as the definitions stay under 10% of the context window, and auto:N sets that bound yourself. Two defaults differ: on Google Cloud’s Agent Platform, and with an ANTHROPIC_BASE_URL that does not point at Anthropic, deferral is off. Server authors should note that tool descriptions and server instructions are truncated at 2KB each. On output, Claude Code warns above 10,000 tokens and caps at 25,000, which MAX_MCP_OUTPUT_TOKENS raises.
To exempt a server from deferral, set alwaysLoad to true in its entry; all of its tools then sit in context from session start, whatever ENABLE_TOOL_SEARCH says. A server can declare the same for one tool through anthropic/alwaysLoad in that tool’s _meta object. The price is twofold: every upfront tool occupies context, and this one server blocks startup until it connects — at most five seconds, while the others keep connecting in the background. Use it sparingly, for tools Claude needs on every turn.
A server does not have to belong to the whole session. In a subagent’s frontmatter, mcpServers names either an already-configured server — the subagent then shares that connection — or a full definition that applies to it alone: connected when it starts, disconnected when it finishes. That is the clean way to keep a specialist server’s tool descriptions out of the main conversation. The main session’s restrictions come along, since v2.1.153 here too: --strict-mcp-config, managed configuration and the allow and deny lists all apply, and a blocked server is skipped with a warning:
---
name: data-analyst
description: Analyze production data
mcpServers:
- database
- playwright:
type: stdio
command: npx
args: ["-y", "@playwright/mcp@latest"]
---
Patterns from real use
With the GitHub server attached, you talk about pull requests, issues and commits in ordinary sentences, and Claude fetches the answer live from the server instead of from your quoted paste. The third line below is not prose but one of the server’s prompts — invoked like a slash command, with the PR number as its argument:
List all open PRs that haven't been reviewed in more than 3 days.
Create an issue for the login timeout bug with medium priority.
/mcp__github__pr_review 456
A database server moves the line a little further: you ask for numbers, not for SQL. Starting with read-only access pays off — a misread question then produces at most a wrong report, not a changed row:
Find all users who placed more than 5 orders in the last 30 days.
What's the average order value by country for Q1 2026?
Several servers can be combined in one session, and that is where MCP gets interesting. A weekly report, for instance: pull request metrics from the GitHub server, revenue from the database, the finished text into the repository through the filesystem server, the summary to the team through the chat server — one assignment, four systems, no copying between windows.
Some servers ask you something in the middle of a task. MCP calls this elicitation, and Claude Code shows it in two forms: a form with the fields the server describes, or a browser URL you confirm — after which the server picks up where it left off. Nothing needs configuring. If you want those questions answered automatically, the Elicitation hook steps in beforehand; the ElicitationResult hook sees your answer before it goes back to the server. A call waiting on an open dialog is not moved to the background, incidentally — it is not slow, it is waiting for you.
Securing this is mostly the obvious, done consistently: credentials come from environment variables, no token goes into version control, read access is usually enough, and a server gets only the area it truly needs. Two points are easy to miss. A server that fetches external content also brings external instructions into the conversation — decide who you trust with that. And in organizations, managed-mcp.json fixes the permitted set of servers centrally, with allowedMcpServers and deniedMcpServers as allow and deny lists.
Four behaviours become noticeable in daily use if you do not know them. A server can change its list of tools, prompts and resources at runtime through list_changed, with nothing to reconnect; if that refresh fails, Claude Code keeps the list it already knew. If an HTTP or SSE connection drops mid-session, it is retried up to five times, starting at one second and doubling each time; the first connection attempt at startup follows the same pattern with three tries since v2.1.121, but only for transient failures — a rejected sign-in is not retried, since it will not change without you. Local stdio servers are not restarted automatically. And a server can require confirmation for every call to one specific tool through anthropic/requiresUserInteraction — meant for steps where the prompt is the whole point.
Channels: when the server speaks first
A channel reverses the direction. Instead of Claude querying a server, the server pushes events into the open session — a Telegram message, a CI result, a monitoring alert — and Claude can react while you are away from the terminal. Technically it is an MCP server that declares the claude/channel capability; the direction works back as well, so a reply lands in the same chat. One condition holds: events only arrive while the session is running. For permanent reachability, keep Claude in a background process or an open terminal.
The feature is a research preview, included since v2.1.80, and the shape of the flag may still change. Telegram, Discord and iMessage ship with it, plus fakechat as a demo that starts a chat interface on localhost — for trying things out without an external account. Every channel is a plugin and needs Bun. The path is always the same: install the plugin, set the token, restart Claude — passing the plugin as the flag’s argument, several of them space-separated:
claude --channels plugin:telegram@claude-plugins-official
Every channel keeps a list of permitted senders; everything else is dropped silently. Telegram and Discord fill it through pairing: you message the bot, it answers with a code, you approve the code in the session. iMessage treats the chat with yourself as permitted and takes further contacts by their handle. Two things are easy to overlook. An entry in .mcp.json is not enough — a server may only push once it is named in the flag. And if the channel forwards permission questions, every permitted sender can approve tool calls; that list is no formality.
For organizations, channels hang on two managed settings. channelsEnabled is the master switch — on claude.ai Team and Enterprise plans channels are blocked until someone enables them, on Console access with an API key they are permitted as long as no managed settings are rolled out. allowedChannelPlugins, once set, replaces the Anthropic-maintained list of permitted plugins entirely — including to add a marketplace of your own. Pro and Max accounts without an organization skip both checks and decide per session. Channels are not available on Amazon Bedrock, Google Cloud’s Agent Platform or Microsoft Foundry.
One last detail that puzzles people on the first attempt: when Claude replies through a channel, the reply is not in your terminal. There you see the incoming message, the tool call and a confirmation — the text itself appears on the other platform. And in -p mode, tools that would need terminal input are switched off so the session never waits for someone who is not there.