What MCP Is in Claude Code
MCP (Model Context Protocol) fornece tools externas e data sources para modelos de IA. No Claude Code, cada MCP server prove tools registradas via a interface standard Tool, namespaced como mcp__<server>__<tool>.
services/mcp/-- Connection lifecycle, config loading, OAuth, transport setuptools/MCPTool/-- Proxy tool wrapping remote MCP calls with runtime overridescommands/mcp/-- User-facing /mcp slash command interfacecomponents/mcp/-- React UI panels for settings and dialogs
Transport Types
Oito tipos de transport, cada um com requisitos de setup distintos:
InProcessTransport
class InProcessTransport implements Transport {
private peer: InProcessTransport | undefined
async send(message: JSONRPCMessage): Promise<void> {
queueMicrotask(() => { this.peer?.onmessage?.(message) })
}
}
export function createLinkedTransportPair(): [Transport, Transport] {
const a = new InProcessTransport()
const b = new InProcessTransport()
a._setPeer(b); b._setPeer(a)
return [a, b]
}
Usa queueMicrotask para entregar mensagens, evitando stack overflows em chamadas recursivas.
7-Layer Config Scope Cascade
| Priority | Scope | Source | Notes |
|---|---|---|---|
| 1 | enterprise | managed-mcp.json (MDM) | Blocks all user add/remove |
| 2 | dynamic | --mcp-config flag | Policy-filtered |
| 3 | claudeai | Claude.ai connector API | Deduplicated by URL sig |
| 4 | project | .mcp.json (CWD & parents) | Child overrides parent |
| 5 | local | ~/.claude/projects/<hash>/ | Not git-tracked |
| 6 | user | ~/.claude/settings.json | User-wide defaults |
| 7 | managed | Plugin-provided servers | Namespaced plugin:name:server |
Quando managed-mcp.json existe, addMcpConfig() throws: "enterprise MCP configuration is active and has exclusive control." Tools como claude mcp add sao completamente bloqueadas.
Enterprise policy pode definir allowedMcpServers e deniedMcpServers. Denylist tem precedencia absoluta. Matching por name (exact), command (full array para stdio), ou URL pattern (glob com *).
Connection Lifecycle e State Machine
- Config Assembly -- All scopes merged e policy-filtered. Env vars expanded.
- Batched Connection -- Stdio: batches de 3. Remote: batches de 20.
- Transport Construction -- Based on serverRef.type, correct SDK transport.
- client.connect() with Timeout -- Default 30s. Races connect vs timeout.
- Auth Handling -- 401 -> needs-auth state. McpAuthTool pseudo-tool injected.
- Capability Negotiation -- roots:{} e elicitation:{} capabilities. Server instructions truncated to 2048 chars.
- Tool/Resource/Prompt Fetch -- Fetched in parallel. Names normalized.
- Live Notifications -- ToolListChanged subscriptions. Exponential backoff reconnect (1s -> 30s cap).
Timeout Race Pattern
const connectPromise = client.connect(transport)
const timeoutPromise = new Promise<never>((_, reject) => {
const id = setTimeout(() => {
transport.close().catch(() => {})
reject(new Error(`MCP server "${name}" timed out after ${timeout}ms`))
}, getConnectionTimeoutMs())
connectPromise.then(() => clearTimeout(id), () => clearTimeout(id))
})
await Promise.race([connectPromise, timeoutPromise])
Tool Proxying e MCPTool
MCPTool e um template. Para cada tool de cada server conectado, fetchToolsForClient() clona com metadata real overridden.
Name Normalization
export function normalizeNameForMCP(name: string): string {
let normalized = name.replace(/[^a-zA-Z0-9_-]/g, '_')
if (name.startsWith('claude.ai ')) {
normalized = normalized.replace(/_+/g, '_').replace(/^_|_$/g, '')
}
return normalized
}
export function buildMcpToolName(server: string, tool: string): string {
return `mcp__${normalizeNameForMCP(server)}__${normalizeNameForMCP(tool)}`
}
OpenAPI-generated servers despejam 15-60 KB de docs em tool.description. Claude Code hard-caps tanto tool descriptions quanto server instructions em 2048 characters para gerenciar context window.
Result Handling
- Image content: resized/downsampled, retornado como base64
- Binary blobs: persistidos em disco, path retornado como texto
- Resultado > 100 KB: truncado com instrucoes
OAuth Authentication e McpAuthTool
MCP servers usando SSE ou HTTP transport podem requerer OAuth. O sistema implementa fluxo PKCE completo com XAA (Cross-App Access) extension support.
Quando server entra em needs-auth state, pseudo-tool mcp__<server>__authenticate e injetada. Modelo chama para iniciar OAuth e receber URL de autorizacao. Apos callback, real tools substituem automaticamente via prefix-based replacement no AppState.
RFC 6749 invalid_grant error triggera token invalidation. Slack retorna HTTP 200 com {"error":"invalid_refresh_token"}. Claude Code normaliza esses codigos non-standard para invalid_grant reescrevendo para synthetic 400 antes de passar ao SDK.
Elicitation e Deduplication
Elicitation: Dois Modos
Server envia JSON Schema; user preenche form. Response: accept com content, decline ou cancel.
Server envia URL (OAuth step-up, confirmacao externa). Two-phase: open URL -> wait for ElicitationComplete notification.
client.setRequestHandler(ElicitRequestSchema, async (request, extra) => {
// 1. Try hooks first (programmatic response)
const hookResponse = await runElicitationHooks(serverName, request.params, extra.signal)
if (hookResponse) return hookResponse
// 2. Queue for user interaction
const response = new Promise<ElicitResult>(resolve => {
setAppState(prev => ({
...prev,
elicitation: {
queue: [...prev.elicitation.queue, {
serverName, requestId: extra.requestId,
params: request.params,
respond: resolve,
}],
},
}))
})
return await response
})
Server Deduplication
- Stdio signature:
stdio:["cmd","arg1"] - Remote signature:
url:https://vendor.example.com/mcp - CCR Proxy: URLs rewritten through proxy preservam original via
mcp_urlquery param - Manual wins over plugin -- user-configured beats plugin-provided
- First plugin wins -- se dois plugins proveem mesmo server
XAA -- Cross-App Access
Quando xaa: true setado na config do MCP server, o sistema troca IdP ID-token por OAuth token do MCP server silenciosamente ao inves de abrir browser. Configurado uma vez em settings.xaaIdp, compartilhado entre todos os servers XAA-enabled.
🎯 Resumo e Takeaways
8 transport types -- stdio, sse, http, ws, sse-ide, ws-ide, sdk, in-process. Public transports support OAuth; IDE variants auth-free ou token-based.
7-layer scope cascade -- enterprise > dynamic > claudeai > project > local > user > managed. Enterprise lock bloqueia add/remove manual.
Config files walk directory tree -- .mcp.json read de cada parent directory ate root; child overrides parent.
OAuth model-triggerable -- McpAuthTool pseudo-tool permite Claude iniciar auth autonomamente. Real tools auto-replace apos callback.
Tool descriptions hard-capped 2048 chars -- previne context explosion de OpenAPI servers.
Deduplication content-based -- same command array ou URL = same server independente de nomes em fontes diferentes.