Trilha 2 2.5 MCP Integration
MODULO 2.5

🔌 MCP Integration

Model Context Protocol: 8 transports, 7-layer config cascade, OAuth com PKCE, tool proxying, elicitation e deduplication baseada em conteudo.

~55
Minutos
8
Transports
7
Config Layers
Avancado
Nivel
1

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>.

4 CAMADAS DE ARQUITETURA
  • services/mcp/ -- Connection lifecycle, config loading, OAuth, transport setup
  • tools/MCPTool/ -- Proxy tool wrapping remote MCP calls with runtime overrides
  • commands/mcp/ -- User-facing /mcp slash command interface
  • components/mcp/ -- React UI panels for settings and dialogs
2

Transport Types

Oito tipos de transport, cada um com requisitos de setup distintos:

graph LR A["Claude Code CLI"] --> B{"Transport Type"} B -->|stdio| C["StdioClientTransport\nSubprocess spawn"] B -->|sse| D["SSEClientTransport\nPersistent EventSource\n+ OAuth"] B -->|http| E["StreamableHTTPClientTransport\nJSON + SSE on POST\n+ OAuth"] B -->|ws| F["WebSocketTransport\nws module or Bun WS"] B -->|sse-ide| G["SSE for IDE\nNo auth"] B -->|ws-ide| H["WS for IDE\nOptional token"] B -->|sdk| I["SdkControlTransport\nIn-process control"] B -->|in-process| J["InProcessTransport\nLinked pair\nChrome / ComputerUse"] style C fill:#1e293b,stroke:#3b82f6,color:#e2e8f0 style D fill:#1e293b,stroke:#10b981,color:#e2e8f0 style E fill:#1e293b,stroke:#10b981,color:#e2e8f0 style F fill:#1e293b,stroke:#f59e0b,color:#e2e8f0 style G fill:#1e293b,stroke:#ef4444,color:#e2e8f0 style H fill:#1e293b,stroke:#ef4444,color:#e2e8f0 style I fill:#1e293b,stroke:#8b5cf6,color:#e2e8f0 style J fill:#1e293b,stroke:#8b5cf6,color:#e2e8f0

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.

3

7-Layer Config Scope Cascade

Priority Scope Source Notes
1enterprisemanaged-mcp.json (MDM)Blocks all user add/remove
2dynamic--mcp-config flagPolicy-filtered
3claudeaiClaude.ai connector APIDeduplicated by URL sig
4project.mcp.json (CWD & parents)Child overrides parent
5local~/.claude/projects/<hash>/Not git-tracked
6user~/.claude/settings.jsonUser-wide defaults
7managedPlugin-provided serversNamespaced plugin:name:server
ENTERPRISE LOCK

Quando managed-mcp.json existe, addMcpConfig() throws: "enterprise MCP configuration is active and has exclusive control." Tools como claude mcp add sao completamente bloqueadas.

POLICY ALLOW/DENY LISTS

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 *).

4

Connection Lifecycle e State Machine

8 ETAPAS DO LIFECYCLE
  1. Config Assembly -- All scopes merged e policy-filtered. Env vars expanded.
  2. Batched Connection -- Stdio: batches de 3. Remote: batches de 20.
  3. Transport Construction -- Based on serverRef.type, correct SDK transport.
  4. client.connect() with Timeout -- Default 30s. Races connect vs timeout.
  5. Auth Handling -- 401 -> needs-auth state. McpAuthTool pseudo-tool injected.
  6. Capability Negotiation -- roots:{} e elicitation:{} capabilities. Server instructions truncated to 2048 chars.
  7. Tool/Resource/Prompt Fetch -- Fetched in parallel. Names normalized.
  8. 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])
5

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)}`
}
DESCRIPTION CAP: 2048 CHARS

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

TRES TIPOS DE RESULTADO
  • Image content: resized/downsampled, retornado como base64
  • Binary blobs: persistidos em disco, path retornado como texto
  • Resultado > 100 KB: truncado com instrucoes
6

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.

sequenceDiagram participant C as Claude Code participant KS as Keychain participant AS as Auth Server participant MCP as MCP Server C->>C: client.connect() -> 401 C->>C: set state: needs-auth C->>C: inject McpAuthTool Note over C: Model calls authenticate C->>AS: discoverOAuthServerMetadata() AS-->>C: PKCE endpoint C->>AS: /authorize?code_challenge=... C-->>C: open browser AS-->>C: callback with auth_code C->>AS: POST /token (code + verifier) AS-->>C: access_token + refresh_token C->>KS: store tokens C->>MCP: reconnect MCP-->>C: connected - real tools swap in
McpAuthTool: MODEL-TRIGGERED AUTH

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.

SLACK 200-ERROR QUIRK

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.

7

Elicitation e Deduplication

Elicitation: Dois Modos

FORM MODE

Server envia JSON Schema; user preenche form. Response: accept com content, decline ou cancel.

URL MODE

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

CONTENT-BASED, NAO NAME-BASED
  • Stdio signature: stdio:["cmd","arg1"]
  • Remote signature: url:https://vendor.example.com/mcp
  • CCR Proxy: URLs rewritten through proxy preservam original via mcp_url query param
  • Manual wins over plugin -- user-configured beats plugin-provided
  • First plugin wins -- se dois plugins proveem mesmo server
8

XAA -- Cross-App Access

ENTERPRISE SSO EXTENSION

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

1

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.

2

7-layer scope cascade -- enterprise > dynamic > claudeai > project > local > user > managed. Enterprise lock bloqueia add/remove manual.

3

Config files walk directory tree -- .mcp.json read de cada parent directory ate root; child overrides parent.

4

OAuth model-triggerable -- McpAuthTool pseudo-tool permite Claude iniciar auth autonomamente. Real tools auto-replace apos callback.

5

Tool descriptions hard-capped 2048 chars -- previne context explosion de OpenAPI servers.

6

Deduplication content-based -- same command array ou URL = same server independente de nomes em fontes diferentes.

2.4 Search Tools Trilha 2: Index