C Claude Code Internals
EN | ES

MCP (Model Context Protocol)

MCP conecta Claude Code con herramientas y servicios externos. La implementación abarca 23 archivos en src/services/mcp/ y soporta 4 tipos de transporte, 2 flujos de autenticación, 6 ámbitos de configuración y un sistema completo de políticas enterprise.

4 tipos de transporte 6 ámbitos de configuración 23 archivos de implementación 2 flujos de auth (OAuth + XAA)
i Convención de nombres de herramientas
Cada herramienta MCP se expone como mcp__<servidor>__<herramienta>. Los caracteres fuera de [a-zA-Z0-9_-] se reemplazan por _, con límite de 64 caracteres. Este prefijo es el que se usa en las reglas de permisos allow/deny.

Arquitectura

Componente Archivo Propósito
Client client.ts (~3.400 líneas) Conexión, creación de transporte, encapsulado y llamadas a herramientas
Config config.ts (~800 líneas) Carga de configuración desde todos los ámbitos
Auth auth.ts (~1.200 líneas) Flujos de autenticación OAuth + XAA
XAA xaa.ts (512 líneas) Protocolo Cross-App Access (RFC 8693 + RFC 7523)
Normalization normalization.ts Normalización de nombres para el prefijo mcp__
Env Expansion envExpansion.ts Expansión de ${VAR} y ${VAR:-default} en la config
In-Process InProcessTransport.ts Par de transportes enlazados para servidores en proceso (Chrome, Computer Use)
Elicitation elicitationHandler.ts Gestor de solicitudes de elicitación MCP (prompts de auth por URL)
MCPTool src/tools/MCPTool/ Plantilla base clonada por cada herramienta MCP expuesta al modelo
McpAuthTool src/tools/McpAuthTool/ Herramienta pseudo para servidores que necesitan autenticación

Ámbitos de configuración (por prioridad)

Los servidores se cargan desde 6 fuentes. Mayor prioridad sobreescribe a menor cuando hay conflicto de nombres. El ámbito enterprise es exclusivo: si existe managed-mcp.json, el resto de ámbitos se ignoran.

# Ámbito Fuente Notas
1 claudeai API fetch Conectores de organización de Claude.ai (prioridad más baja)
2 plugin dynamic Servidores de plugins instalados
3 user ~/.claude/settings.json Configuración global del usuario
4 project .mcp.json Recorre el árbol de directorios hasta home
5 local .claude/settings.local.json Config privada del proyecto (no se sube al repo)
6 enterprise managed-mcp.json EXCLUSIVO: todos los demás ámbitos se ignoran cuando existe este archivo

Ejemplo de config de proyecto (.mcp.json)

{
  "mcpServers": {
    "github": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
    },
    "my-api": {
      "type": "sse",
      "url": "https://example.com/mcp/sse",
      "headers": { "Authorization": "Bearer ${API_TOKEN}" }
    }
  }
}

Todos los campos soportan expansión de ${VAR} y ${VAR:-default}. Los servidores en .mcp.json requieren aprobación explícita del usuario antes de conectar (almacenada en enabledMcpjsonServers en settings).

Tipos de transporte

stdio por defecto

Lanza un subproceso que se comunica por stdin/stdout. El transporte más común. El campo type es opcional por compatibilidad hacia atrás.

El stderr se captura para depuración (límite 64MB). Los servidores Chrome y Computer Use usan optimización en proceso para evitar ~325MB de overhead.

sse remoto

Conexión EventSource persistente. Sin timeout en el stream; las peticiones HTTP individuales tienen 60s de timeout.

Soporta OAuth con flujo en navegador. Soporta headersHelper para cabeceras de autenticación dinámicas.

http remoto

Implementa el protocolo MCP Streamable HTTP 2025-03-26. Añade Accept: application/json, text/event-stream automáticamente.

Soporta gestión de sesión via ID de sesión. Soporta autenticación OAuth.

ws remoto

Transporte WebSocket. Soporta Bun y Node.js. Protocolo: ["mcp"].

Soporta opciones de proxy y TLS. Las cabeceras son configurables.

Ciclo de vida de la conexión

Arranque

1

Cargar configs de todos los ámbitos (enterprise tiene control exclusivo si existe)

2

Deduplicar servidores por firma (URL para remotos, comando para stdio)

3

Filtrar por políticas enterprise de allow/deny

4

Verificar el estado de aprobación de servidores del proyecto

5

Conectar servidores locales (concurrencia: 3) y remotos (concurrencia: 20) en paralelo

6

En fallo de auth: cachear 15 min, crear herramienta pseudo McpAuthTool

7

En éxito: obtener herramientas, comandos y recursos en paralelo

Flujo de llamada a herramienta

1

El modelo emite un bloque tool_use con nombre "mcp__servidor__herramienta"

2

ensureConnectedClient() verifica o reconecta si la caché fue limpiada

3

Verificación de permisos via el sistema estándar (passthrough por defecto)

4

callMCPTool() con timeout, verifica el flag isError en la respuesta

5

processMCPResult(): si la salida supera 100.000 chars, guarda en archivo temporal y devuelve instrucciones para usar Read

6

En error de elicitación de URL (-32042): reintenta hasta 3 veces

Apagado

Servidores stdio

SIGINT → 100ms → SIGTERM → 400ms → SIGKILL

Tiempo máximo total: 600ms

Servidores remotos

client.close() → cierra transporte, rechaza peticiones pendientes

Autenticación

Flujo OAuth estándar SSE + HTTP

OAuth en el navegador con almacenamiento automático del token en el keychain del SO, usando nombre del servidor y hash de config como clave. Se refresca automáticamente en 401. Soporta step-up (403 con scope) y revocación (RFC 7009).

"oauth": {
  "clientId": "my-app",
  "callbackPort": 8080,
  "authServerMetadataUrl": "https://auth.example.com/.well-known/..."
}
XAA (Cross-App Access) SSO enterprise

Flujo SSO empresarial usando intercambio de tokens RFC 8693 y JWT Bearer grant RFC 7523. Se activa con CLAUDE_CODE_ENABLE_XAA=1. Ventaja clave: un único popup del navegador autentica N servidores MCP (el id_token se reutiliza).

Flujo: Descubrimiento PRM → Metadatos AS → id_token → ID-JAG → access_token

McpAuthTool (herramienta pseudo) estado needs-auth

Cuando un servidor falla al conectar por auth, se crea una herramienta pseudo llamada mcp__<servidor>__authenticate. Al invocarla el modelo inicia el flujo OAuth y al completarse las herramientas reales reemplazan a la pseudo. Siempre se aprueba automáticamente (sin prompt al usuario). El fallo de auth se cachea 15 minutos.

Exposición de herramientas

Ejemplos de nombres

Nombre del servidor Nombre de herramienta Expuesto como
github create_issue mcp__github__create_issue
slack search_public mcp__slack__search_public
My Server! do-thing mcp__My_Server___do_thing

Anotaciones de herramientas (especificación MCP)

Anotación Propiedad Efecto
readOnlyHint isConcurrencySafe, isReadOnly Puede ejecutarse en paralelo, tratada como solo lectura
destructiveHint isDestructive Señal de mayor riesgo en los prompts de permiso
openWorldHint isOpenWorld La herramienta puede acceder a sistemas externos
_meta.anthropic/searchHint searchHint Herramienta diferida (no se carga en contexto hasta que se busca)
_meta.anthropic/alwaysLoad alwaysLoad Herramienta omite la diferida, siempre en contexto

Las descripciones de herramientas tienen un límite de 2.048 caracteres. Cuando la salida supera 100.000 caracteres, se guarda en un archivo temporal y el modelo recibe instrucciones para usar la herramienta Read.

Sistema de permisos

Todas las herramientas MCP devuelven checkPermissions() → passthrough. En modo default siempre se pregunta al usuario, en bypassPermissions se aprueban automáticamente, en modo auto decide el clasificador YOLO.

Reglas de permiso del usuario

{
  "permissions": {
    "allow": [
      "mcp__github__search_code",
      "mcp__slack__*"
    ],
    "deny": [
      "mcp__untrusted_server__*"
    ]
  }
}

Políticas enterprise de servidores (managed-mcp.json)

{
  "allowedMcpServers": [
    { "serverName": "github" },
    { "serverUrl": "https://*.company.com/*" },
    { "serverCommand": ["npx", "-y", "@company/mcp-*"] }
  ],
  "deniedMcpServers": [
    { "serverName": "untrusted" }
  ]
}

La lista de denegación siempre tiene prioridad sobre la de permiso.

Comandos CLI

# Agregar servidor stdio (scope por defecto: local)
claude mcp add my-server npx -y @org/mcp-server
  -s, --scope <scope>      # local, user o project
  -e, --env KEY=VALUE      # variables de entorno

# Agregar servidor remoto (transporte detectado automáticamente desde la URL)
claude mcp add my-api https://api.example.com/mcp
  -t, --transport sse|http
  -H, --header "Key: Value"
  --client-id <id>         # Client ID para OAuth
  --xaa                    # Habilitar Cross-App Access

# Agregar con config JSON completa
claude mcp add-json my-server '{"type":"http","url":"https://example.com/mcp"}'

# Otras operaciones
claude mcp remove my-server [-s scope]
claude mcp list
claude mcp get my-server

Comando /mcp

Subcomando Descripción
/mcp Abrir la interfaz de configuración de MCP
/mcp enable [nombre|all] Habilitar servidor(es)
/mcp disable [nombre|all] Deshabilitar servidor(es)
/mcp reconnect <nombre> Reconectar un servidor específico (limpia caché, conexión nueva)

Características avanzadas

Script de cabeceras dinámicas (headersHelper)

Apunta a un script en headersHelper. El script recibe el nombre y URL del servidor como variables de entorno y debe devolver JSON con las cabeceras. Tiempo límite: 10s. Las cabeceras dinámicas sobreescriben las estáticas.

Recursos MCP

Los servidores pueden exponer recursos (archivos, datos) via ListMcpResourcesTool y ReadMcpResourceTool. Ambas son herramientas diferidas. Los recursos blob se decodifican de base64 y se escriben en disco.

Prompts MCP como comandos

Los prompts expuestos por los servidores se convierten en comandos de barra (mcp__servidor__nombre-prompt). Los argumentos se analizan desde el esquema del prompt y se pasan a client.getPrompt().

Servidores específicos de agente

Los agentes pueden referenciar servidores existentes por nombre (compartidos) o definir servidores inline (se limpian al terminar el agente). Los servidores requeridos deben estar configurados o el agente no arranca.

Instrucciones de servidor

Los servidores proveen instrucciones de uso durante el handshake (límite 2.048 chars). Se inyectan en el system prompt cada turno. El modo delta (feature-gated) evita invalidar la caché.

Transporte en proceso

Los servidores Chrome y Computer Use se ejecutan en proceso via InProcessTransport, evitando ~325MB de overhead de subproceso. Usa pares de transportes enlazados con entrega por queueMicrotask().

Constantes y timeouts clave

Variable / Constante Valor Propósito
MCP_TIMEOUT 30.000ms Timeout de conexión por servidor
MCP_TOOL_TIMEOUT 100.000.000ms (~27,8h) Timeout de llamada a herramienta (efectivamente infinito)
MCP_REQUEST_TIMEOUT_MS 60.000ms Timeout por petición HTTP (SSE/HTTP)
MAX_MCP_OUTPUT_TOKENS 25.000 Máximo de tokens en la salida de una herramienta
maxResultSizeChars 100.000 chars Límite de tamaño de salida antes de guardar en archivo
MAX_MCP_DESCRIPTION_LENGTH 2.048 chars Límite de descripción de herramienta
MCP_AUTH_CACHE_TTL_MS 15 min Duración de la caché needs-auth
MCP_FETCH_CACHE_SIZE 20 Tamaño de caché LRU para herramientas/recursos/comandos
concurrencia local 3 Conexiones simultáneas a servidores locales (stdio)
concurrencia remota 20 Conexiones simultáneas a servidores remotos
MAX_ERRORS_BEFORE_RECONNECT 3 Errores terminales antes de reconectar
MAX_URL_ELICITATION_RETRIES 3 Reintentos de elicitación de URL (-32042)

MCP_TIMEOUT, MCP_TOOL_TIMEOUT y MAX_MCP_OUTPUT_TOKENS están en el conjunto SAFE_ENV_VARS: pueden configurarse via managed settings sin disparar un diálogo de seguridad.

Gestión de errores

Tipo de error Tratamiento
Timeout de conexión (30s) Servidor marcado como failed
Error de auth (401) Cacheado como needs-auth 15 min, creada McpAuthTool
ECONNRESET / ETIMEDOUT / EPIPE Contados: 3 errores consecutivos cierran el transporte
ECONNREFUSED / EHOSTUNREACH Error terminal, transporte cerrado de inmediato
Sesión expirada (404 + -32001) Caché limpiada, reintento automático una vez
Elicitación de URL (-32042) Mostrar diálogo de URL al usuario, reintentar hasta 3 veces
Tres cosas que la mayoría no sabe sobre MCP
Primero: los servidores en .mcp.json necesitan aprobación explícita antes de conectar — usa enableAllProjectMcpServers: true en settings para aprobarlos todos de golpe. Segundo: puedes usar comodín en las reglas de permiso como mcp__slack__* para permitir un servidor entero sin aprobar cada herramienta por separado. Tercero: el timeout de herramienta MCP es efectivamente infinito (~27,8 horas) — si una herramienta parece bloqueada, usa /mcp reconnect nombre-servidor para forzar una conexión nueva.