MCP - the Model Context Protocol - connects external tools, resources and prompts to Claude Code. The key thing to keep in mind: an MCP server is a separate trust boundary. It gets exactly the data and authority its protocol grants, and so it is treated as third-party code: you read its sources or the provider's terms and grant minimal access. Connecting a server "for convenience" without understanding what it can do means expanding the risk surface blindly.
There are several transports, and each has its role. HTTP is the recommended remote transport for request-response; SSE is deprecated and needed only for a legacy endpoint. stdio launches a local process, and here the separator matters: a double dash separates Claude's flags from the server command. WebSocket is set via JSON, suits push and does not support OAuth. Servers are managed by the commands claude mcp add, list, get and remove - from adding to checking and removal.
Scopes determine who sees the server and where it is stored. local (the default) lies in ~/.claude.json inside the project entry and is visible only to you in one project. project - in .mcp.json, visible to the team after trust and approval. user - in ~/.claude.json, visible to you in all projects. managed - the organization's policy. On a name collision the precedence is: local, project, user, plugin, then claude.ai connectors; the whole entry is taken, fields are not merged. A project .mcp.json requires explicit approval, and resetting the choice is the reset-project-choices command.
| Scope | Storage | Visibility |
|---|---|---|
| local (default) | ~/.claude.json in the project entry | Only you, one project |
| project | .mcp.json | The team after trust/approval |
| user | ~/.claude.json | Only you, all projects |
| managed | managed MCP policy | The organization |
Secrets in the MCP config are kept out of the repository. It helps to see a .mcp.json entry with variable substitution once: the url and the Authorization header take values from the environment via the variable-with-default syntax rather than storing the token literally. Substitution is supported in command, args, env, url and headers. The rule is simple and firm: a literal token in .mcp.json is a leaked secret, so you reference a variable and inject the secret itself from the environment or a secret store.
Authentication and the server's health are a separate check. A remote HTTP server may use OAuth: you run /mcp or the corresponding auth flow and pass the browser authorization; for non-standard providers there are preconfigured client credentials, a fixed callback port and scope restriction. An important subtlety: claude mcp list distinguishes configured from connected - the Added status means only that the config is written, not that the handshake succeeded. You check the health, the tool count, authentication and the real read and write capabilities.
Tools, resources and prompts come with clear semantics. Tools appear under names like mcp__server__tool and go through the ordinary permission flow; a server may mark a tool as requiring interaction, and then confirmation is kept even in a broad mode. Resources are mentioned via an at sign and a URI, and MCP prompts become dynamic slash commands. Elicitation lets a server request structured input during a call - but you must not collect secrets via a free prompt without verifying the protocol and the recipient.
The startup context is saved by tool search. Large MCP output is truncated by documented limits, so the server's task is better designed with pagination and filtering. Tool search defers the schemas of rarely used tools and loads the needed ones on request, sharply reducing the startup context; compatible models enable the mechanism automatically by a threshold, and a gateway must pass the protocol blocks. The alwaysLoad option is left only for small critical servers rather than enabled for all.
The main warning: MCP is not "just data". A write-capable tool can send messages, change tickets, a database or infrastructure - that is, act in external systems on your behalf. So for such servers you add pointed ask and deny per tool, a sandbox or the provider's test account and an audit trail. The typical failures are a literal token in .mcp.json, trusting the Added status instead of checking connected and a write-capable server with no narrow rules. Grant minimal access and verify the actual authority.
{
"mcpServers": {
"internal-docs": {
"type": "http",
"url": "${DOCS_MCP_URL:-https://docs.example.com/mcp}",
"headers": { "Authorization": "Bearer ${DOCS_MCP_TOKEN}" }
}
}
}
// substitution ${VAR} / ${VAR:-default}; a literal token must not be committed