MCP in Claude Code¶
Level: Intermediate · Time: ~40 min · Exam relevance: CCAR-P 7.1, 3.1, 3.7, 3.8
In plain English¶
Out of the box, Claude Code can work with your files, your shell and the web. MCP servers let it reach everything else: your issue tracker, design documents, databases, monitoring dashboards and internal services. Adding one is a single command, and once added its tools appear alongside Claude Code's built-in tools.
This page is the practical, Claude Code-specific companion to Module 08: how to add servers, where the configuration is stored, how teams share it, how it affects context and permissions, and how administrators control it.
Why it matters¶
- Team configuration (CCAR-P-7.1). A committed
.mcp.jsongives everyone the same integrations; managed MCP policy keeps them to an approved set. - Capability bloat (CCAR-P-3.1). Every server adds tools and trust. Scopes, allow-lists and permission rules are how you keep that in check.
- Integration choice (CCAR-P-3.7). In Claude Code you can often choose between an MCP server and a CLI the agent runs through Bash; see MCP versus alternatives.
- Context (CCAR-P-3.8). Claude Code defers MCP tool definitions and discovers them with tool search, so many servers cost little context.
How it works¶
Adding servers¶
# Remote server over Streamable HTTP (Claude Code falls back to SSE if needed on recent versions)
claude mcp add --transport http notion https://mcp.notion.com/mcp
# With a static header (prefer OAuth where the server supports it)
claude mcp add --transport http internal-api https://mcp.internal.example.com/mcp \
--header "Authorization: Bearer ${INTERNAL_MCP_TOKEN}"
# Local stdio server. Options come before the name; everything after -- is the launch command.
claude mcp add --env ASSETS_LOG_LEVEL=WARNING --transport stdio assets -- uvx contoso-assets-mcp==1.4.2
# From a JSON definition (also the way to add WebSocket servers: "type": "ws")
claude mcp add-json reports '{"type":"http","url":"https://mcp.reports.example.com/mcp"}'
# Import servers you already configured in Claude Desktop
claude mcp add-from-claude-desktop
Manage them:
claude mcp list # health status of each server (Connected, Needs authentication, Failed to connect, Pending approval)
claude mcp get notion # details, including the reason for a failure
claude mcp remove notion
claude mcp reset-project-choices # reset your approvals of .mcp.json servers
Inside a session, /mcp shows servers and tools, signs in to OAuth-protected servers, reconnects, and enables or disables servers for the current project.
Scopes and where configuration lives¶
| Scope | Flag | Loads in | Shared with team | Stored in |
|---|---|---|---|---|
| Local (default) | --scope local |
Current project only | No | ~/.claude.json, under the project's path |
| Project | --scope project |
Current project | Yes, via version control | .mcp.json at the project root |
| User | --scope user |
All your projects | No | ~/.claude.json |
When the same server name is defined in several places, Claude Code uses one definition with this precedence: local, then project, then user, then plugin-provided servers, then claude.ai connectors. Entries are not merged field by field.
Note: MCP "local scope" lives in
~/.claude.json, which is different from the general.claude/settings.local.jsonfile.
A shared .mcp.json¶
{
"mcpServers": {
"tickets": {
"type": "http",
"url": "${TICKETS_MCP_URL:-https://mcp.tickets.example.com/mcp}"
},
"assets": {
"type": "stdio",
"command": "uvx",
"args": ["contoso-assets-mcp==1.4.2"],
"env": { "ASSETS_API_TOKEN": "${ASSETS_API_TOKEN}" }
}
}
}
Claude Code expands ${VAR} and ${VAR:-default} in command, args, env, url and headers, so the committed file carries no secrets: each developer supplies tokens through environment variables or OAuth.
In interactive sessions, Claude Code asks each developer to approve project-scoped servers from .mcp.json before using them; a cloned repository cannot approve its own servers through its committed settings until the folder is trusted. In claude -p, Agent SDK and some cloud sessions there is no prompt and project servers load without asking (page 9 explains how to prevent that).
Authentication¶
For OAuth-protected remote servers, add the server and then run /mcp to sign in through the browser. Claude Code supports pre-configured OAuth client credentials, a fixed callback port, scope restriction, and a headersHelper command that generates headers at connect time for custom schemes. Tokens are stored by Claude Code, not in .mcp.json.
Using MCP tools, resources and prompts¶
- Tools appear as
mcp__<server>__<tool>. Claude calls them like built-in tools, subject to permissions. - Resources: type
@to see resources from connected servers and reference them as@server:protocol://path, for example@tickets:ticket://PAY-1042. - Prompts become commands:
/mcp__<server>__<prompt>(listed as/server:prompt (MCP)), with arguments separated by spaces. - claude.ai connectors you have enabled can also reach Claude Code; their tools appear as
mcp__claude_ai_<server>__<tool>.
Context: tool search and output limits¶
- Tool search is on by default (as of 2026-10-24): only tool names and server instructions load at session start; full definitions load when Claude needs them. Control it with the
ENABLE_TOOL_SEARCHenvironment variable. Server authors should write good server instructions so Claude knows when to search for their tools. - Claude Code warns when an MCP tool result exceeds 10,000 tokens, and by default caps results at 25,000 tokens (
MAX_MCP_OUTPUT_TOKENS). Larger successful results are saved to a file Claude can read instead of flooding context.
Permissions for MCP tools¶
Use the normal permission rules (page 4):
{
"permissions": {
"allow": ["mcp__tickets__tickets_search", "mcp__tickets__tickets_get"],
"ask": ["mcp__tickets__tickets_comment"],
"deny": ["mcp__tickets__tickets_delete"]
}
}
mcp__tickets__* matches every tool from a server. Server authors can mark a tool with _meta["anthropic/requiresUserInteraction"]: true so Claude Code prompts on every call, even in auto and bypass modes. Subagents can be given their own mcpServers list so that only the subagent that needs a server can use it.
Organisation controls (managed MCP)¶
| Pattern | Configure |
|---|---|
| Disable MCP entirely | managed-mcp.json with an empty mcpServers map |
| Fixed deployment: everyone gets the same servers and cannot add others | managed-mcp.json at /Library/Application Support/ClaudeCode/ (macOS), /etc/claude-code/ (Linux, WSL) or C:\Program Files\ClaudeCode\ (Windows) |
| Provide servers to everyone, who can still add their own | managedMcpServers in managed settings |
| Approved catalogue: only listed servers may be added | allowedMcpServers plus allowManagedMcpServersOnly: true |
| Block known-bad servers | deniedMcpServers |
Allow-list and deny-list entries match by serverUrl (wildcards allowed), serverCommand (exact argument array) or serverName. Without allowManagedMcpServersOnly, allow-lists from user and project settings merge with the managed list, so users can broaden it; the deny-list always merges from every scope.
Claude Code as an MCP server¶
claude mcp serve runs Claude Code itself as a stdio MCP server that other MCP clients (such as Claude Desktop) can connect to and use its tools.
Example¶
A platform team's onboarding instructions for a repository:
# 1. Export your personal token (from the internal token portal); never commit it
export ASSETS_API_TOKEN=... # placeholder: get your own token
# 2. Start Claude Code in the repo and approve the project's MCP servers when prompted
claude
# 3. In the session
/mcp # sign in to "tickets" via OAuth
> Summarise @tickets:ticket://PAY-1042 and find the code paths it mentions
> /mcp__tickets__triage PAY-1042 # run the server's triage prompt
Enterprise use case¶
Adventure Works (fictional) let engineers add MCP servers freely during a pilot and then audited usage: 41 distinct servers, several unpinned npx -y commands, and two community servers with broad OAuth scopes to the corporate document store.
For general availability, the team deployed managed settings with an approved catalogue (allowedMcpServers plus allowManagedMcpServersOnly: true), using URL patterns for vendor-hosted servers and exact, version-pinned commands for local ones. Common servers (tickets, documentation search) were delivered to everyone with managedMcpServers. Each repository's .mcp.json lists only what that codebase needs, with ${VAR} placeholders for tokens. Permission rules deny destructive tools by default, and the security team's MCP review checklist from Module 08 gates catalogue additions.
Common mistakes¶
- Committing tokens in
.mcp.json. Use${VAR}expansion or OAuth. - Placing options after
--in stdio adds. Everything after--goes to the server command. - Putting
--env KEY=valuedirectly before the server name, which the CLI reads as another pair; put another option between them. - Assuming
.mcp.jsonis reviewed automatically. Approval is per developer in interactive sessions, and absent in headless runs. - Loading many large servers without tool search (or disabling it) and wondering why context fills quickly.
- Unpinned package commands (
npx -y some-server). - Relying on a soft allow-list (without
allowManagedMcpServersOnly) as an enforcement control.
Security considerations¶
- Every MCP server is third-party code or a third-party service with access to your session's data. Apply the provenance checks in MCP security.
- Local stdio servers and their environment variables run outside the Bash sandbox with your user permissions.
- Use permission rules to deny destructive MCP tools and require confirmation for external effects.
- In CI, use
--strict-mcp-configwith an explicit--mcp-config, or--bare, so repositories cannot add servers to automated runs.
Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
claude mcp list shows Needs authentication |
OAuth sign-in not done | /mcp → authenticate |
Pending approval for a .mcp.json server |
Not approved yet, or folder not trusted | Run claude interactively, accept trust, approve |
Failed to connect (stdio) |
Wrong command path, missing runtime, or server printing to stdout | claude mcp get <name> for details; run the command manually |
| Server blocked | Not on the managed allow-list | /status to see managed sources; request catalogue approval |
| Tool results truncated or saved to a file | Over the output limit | Paginate on the server, or raise MAX_MCP_OUTPUT_TOKENS deliberately |
More in MCP troubleshooting.
Check your understanding¶
- Which scope shares a server with your team, and where is it stored?
- How do you keep a team-shared server's token out of version control?
- What permission rule allows every tool from a server named
tickets? - Which managed settings create an authoritative approved catalogue of MCP servers?
- How does Claude Code keep context small when many MCP servers are connected?
Answers
- Project scope, stored in
.mcp.jsonat the project root (committed to version control). - Use
${VAR}(or${VAR:-default}) expansion in.mcp.jsonand have each developer provide the value in their environment, or use OAuth through/mcp. mcp__tickets__*(ormcp__tickets) inpermissions.allow.allowedMcpServerstogether withallowManagedMcpServersOnly: truein a managed settings source.- Tool search is on by default: only tool names and server instructions load at start, and full definitions load on demand.
Further reading¶
- Connect Claude Code to tools via MCP and MCP quickstart (Claude Code Docs)
- Managed MCP configuration (Claude Code Docs)
- Module 08: Model Context Protocol