SpyBara
Go Premium

agent-sdk/mcp.md 2026-10-31 23:02 UTC to 2026-11-01 23:57 UTC

No changes for this document in this history range.

2026
Mon 9 23:02

Conectar con herramientas externas usando MCP

Configure servidores MCP para extender su agente con herramientas externas. Cubre tipos de transporte, búsqueda de herramientas para conjuntos grandes de herramientas, autenticación y manejo de errores.

El Protocolo de Contexto de Modelo (MCP) es un estándar abierto para conectar agentes de IA a herramientas externas y fuentes de datos. Con MCP, su agente puede consultar bases de datos, integrarse con APIs como Slack y GitHub, y conectarse a otros servicios sin escribir implementaciones de herramientas personalizadas.

Los servidores MCP pueden ejecutarse como procesos locales, conectarse a través de HTTP o ejecutarse directamente dentro de su aplicación SDK.

[!NOTE]

Esta página cubre la configuración de MCP para el Agent SDK. Para agregar servidores MCP a la CLI de Claude Code de modo que se carguen en cada proyecto, consulte Alcances de instalación de MCP.

Inicio rápido

Este ejemplo se conecta al servidor MCP de documentación de Claude Code usando transporte HTTP y utiliza allowedTools con un comodín para permitir todas las herramientas del servidor.

import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Use the docs MCP server to explain what hooks are in Claude Code",
  options: {
    mcpServers: {
      "claude-code-docs": {
        type: "http",
        url: "https://code.claude.com/docs/mcp"
      }
    },
    allowedTools: ["mcp__claude-code-docs__*"]
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage


async def main():
    options = ClaudeAgentOptions(
        mcp_servers={
            "claude-code-docs": {
                "type": "http",
                "url": "https://code.claude.com/docs/mcp",
            }
        },
        allowed_tools=["mcp__claude-code-docs__*"],
    )

    async for message in query(
        prompt="Use the docs MCP server to explain what hooks are in Claude Code",
        options=options,
    ):
        if isinstance(message, ResultMessage) and message.subtype == "success":
            print(message.result)


asyncio.run(main())

El agente se conecta al servidor de documentación, busca información sobre hooks y devuelve los resultados.

Agregar un servidor MCP

Puede configurar servidores MCP en código al llamar a query(), o en un archivo .mcp.json cargado mediante settingSources.

Agregar un servidor en código

Pase servidores MCP directamente en la opción mcpServers. Este ejemplo inicia un servidor MCP del sistema de archivos local para /Users/me/projects. Reemplace esa ruta con un directorio en su máquina:

import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "List files in my project",
  options: {
    mcpServers: {
      filesystem: {
        command: "npx",
        args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"]
      }
    },
    allowedTools: ["mcp__filesystem__*"]
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage


async def main():
    options = ClaudeAgentOptions(
        mcp_servers={
            "filesystem": {
                "command": "npx",
                "args": [
                    "-y",
                    "@modelcontextprotocol/server-filesystem",
                    "/Users/me/projects",
                ],
            }
        },
        allowed_tools=["mcp__filesystem__*"],
    )

    async for message in query(prompt="List files in my project", options=options):
        if isinstance(message, ResultMessage) and message.subtype == "success":
            print(message.result)


asyncio.run(main())

Agregar un servidor desde un archivo de configuración

Cree un archivo .mcp.json en la raíz de su proyecto. El archivo se carga cuando la fuente de configuración project está habilitada, que lo está para las opciones predeterminadas de query(). Si establece settingSources explícitamente, incluya "project" para que este archivo se cargue. Reemplace /Users/me/projects con un directorio en su máquina:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"]
    }
  }
}

Temporización de la conexión

Claude Code empieza a conectar tus servidores MCP cuando se inicia la sesión, y envía el mensaje init una vez que termina la espera del primer turno, si la hay. Cuánto espera el primer turno a un servidor depende de dónde lo configuraste. Si estableces permissionPromptToolName, el primer turno siempre espera al servidor de esa herramienta, hasta MCP_TIMEOUT, dondequiera que lo hayas configurado.

Para un servidor en options.mcpServers, busca su tipo en la primera columna para ver cuánto lo espera el primer turno.

Tipo de servidor ¿Retrasa el primer turno? Tiempo de espera del primer turno
Servidor stdio, o servidor HTTP/SSE sin una lista de herramientas en caché Sí, hasta que se conecte MCP_TIMEOUT, 30 segundos por defecto; la conexión falla en ese plazo
Servidor remoto con una lista de herramientas en caché, guardada por Claude Code desde una conexión anterior No; las herramientas en caché están disponibles desde el primer turno Ninguno; se conecta en su primera llamada de herramienta, y esa conexión diferida tiene su propio tiempo de espera
Servidor SDK en proceso Sí, hasta que se conecte y enumere sus herramientas MCP_TIMEOUT, 30 segundos por defecto, por intento de conexión; la conexión falla en ese plazo

Un servidor tiene una lista de herramientas en caché solo cuando la caché de descubrimiento de MCP está activada.

Los servidores de archivos de configuración como .mcp.json, o de plugins, a menudo todavía muestran pending en el mensaje init. Cuánto los espera el primer turno depende de options.mcpServers y de la búsqueda de herramientas:

  • options.mcpServers incluye un servidor stdio, HTTP o SSE: el primer turno también espera a los servidores pendientes de archivos de configuración y de plugins, hasta MCP_TIMEOUT.
  • En caso contrario, cuando ANTHROPIC_BASE_URL apunta a un gateway y ENABLE_TOOL_SEARCH no está definido: el primer turno espera hasta 2 segundos a cada servidor pendiente de archivos de configuración y de plugins.
  • En caso contrario, con la búsqueda de herramientas activada, que es el valor predeterminado: el primer turno espera hasta 2 segundos, y solo a los servidores pendientes que establecen alwaysLoad: true o que nombraste. Los demás siguen conectándose en segundo plano, y Claude accede a sus herramientas una vez que se conectan.
  • En caso contrario, con la búsqueda de herramientas desactivada: el primer turno espera hasta 2 segundos a cada servidor pendiente de archivos de configuración y de plugins. La búsqueda de herramientas está desactivada cuando tu valor de ENABLE_TOOL_SEARCH o tu modelo la desactiva, o cuando excluyes la herramienta ToolSearch, por ejemplo a través de disallowedTools.

Servidores nombrados

Nombras un servidor al incluir cualquiera de sus herramientas, como mcp__github__list_issues o mcp__github__*, en allowedTools o en una regla permissions.allow en la opción settings. Un hook mcp_tool también nombra el servidor al que llama cuando lo configuras en un evento de envío de prompt, uso de herramienta, permiso, subagente, tarea, elicitación o worktree. Antes de v2.1.284, nombrar un servidor no tenía efecto en la espera del primer turno.

Establece tú mismo la espera del primer turno

Para elegir tú mismo la espera del primer turno, establece CLAUDE_CODE_MCP_STARTUP_WAIT_MS en la opción env, por ejemplo CLAUDE_CODE_MCP_STARTUP_WAIT_MS: "5000". El primer turno entonces espera hasta esa cantidad de milisegundos a los servidores pendientes de archivos de configuración y de plugins, esté o no activada la búsqueda de herramientas. El mismo límite reemplaza la espera MCP_TIMEOUT para los servidores stdio, HTTP y SSE en options.mcpServers.

Tres esperas se aplican sea cual sea el valor que establezcas, incluido 0:

  • Un servidor permissionPromptToolName: hasta MCP_TIMEOUT.
  • Un servidor SDK en proceso: hasta MCP_TIMEOUT por intento de conexión.
  • Un servidor nombrado que aún se está conectando: al menos hasta 2 segundos, por lo que un valor inferior a 2000 no acorta su espera.

Establece la variable en 0 para omitir la espera para todos los demás servidores. Los servidores aún pendientes cuando termina la espera siguen conectándose en segundo plano. CLAUDE_CODE_MCP_STARTUP_WAIT_MS requiere Claude Code v2.1.274 o posterior.

Haz que el inicio espere a los servidores

Dos ajustes hacen que el propio inicio espere, antes de que Claude Code envíe el mensaje init:

  • MCP_CONNECTION_NONBLOCKING establecido en 0: el inicio espera a todo el lote de conexiones, hasta 5 segundos por defecto. Establece MCP_CONNECT_TIMEOUT_MS, en milisegundos, para cambiar ese límite. Los servidores aún pendientes al alcanzar el límite siguen conectándose en segundo plano.
  • alwaysLoad: true en la configuración de un servidor: el inicio espera hasta el mismo límite a las herramientas de ese servidor, para que el primer turno las tenga con su esquema completo, exentas del aplazamiento de la búsqueda de herramientas. Un servidor remoto con una lista de herramientas en caché las proporciona sin conectarse ni retener el inicio.

El mensaje init reporta el estado de cada servidor en el momento en que Claude Code lo envía.

Permitir herramientas MCP

Las herramientas MCP requieren permiso explícito antes de que Claude pueda usarlas. Sin permiso, Claude verá que las herramientas están disponibles pero no podrá llamarlas.

Convención de nomenclatura de herramientas

Las herramientas MCP se nombran mcp__<server-name>__<tool-name>, donde <server-name> es el nombre con el que registras el servidor, como su clave en mcpServers.

Los caracteres del nombre del servidor como . y los espacios se reemplazan por _. Esta tabla muestra el nombre completo de una herramienta list_issues para dos claves de servidor:

Clave en mcpServers Nombre completo de la herramienta
github mcp__github__list_issues
my.server mcp__my_server__list_issues

Usa los nombres completos de las herramientas en allowedTools y en las reglas de permisos de MCP. Para un servidor proporcionado por un plugin, <server-name> adopta la forma con ámbito de plugin y comienza con plugin_.

Aprobación automática con allowedTools

Use allowedTools para aprobar automáticamente herramientas MCP específicas para que Claude pueda usarlas sin un aviso de permiso:

const _ = {
  options: {
    mcpServers: {
      // your servers
    },
    allowedTools: [
      "mcp__github__*", // All tools from the github server
      "mcp__db__query", // Only the query tool from db server
      "mcp__slack__send_message" // Only send_message from slack server
    ]
  }
};
options = ClaudeAgentOptions(
    mcp_servers={
        # your servers
    },
    allowed_tools=[
        "mcp__github__*",  # All tools from the github server
        "mcp__db__query",  # Only the query tool from db server
        "mcp__slack__send_message",  # Only send_message from slack server
    ],
)

Los caracteres comodín (*) le permiten permitir todas las herramientas de un servidor sin enumerar cada una individualmente.

[!NOTE]

Prefiera allowedTools sobre modos de permiso para acceso MCP. permissionMode: "acceptEdits" no aprueba automáticamente herramientas MCP (solo ediciones de archivos y comandos Bash del sistema de archivos). permissionMode: "bypassPermissions" sí aprueba automáticamente herramientas MCP pero también desactiva la mayoría de otros avisos de seguridad, lo que es más amplio de lo necesario; consulte Cómo se evalúan los permisos para los avisos que permanecen. Un carácter comodín en allowedTools otorga exactamente el servidor MCP que desea y nada más. Consulte Modos de permiso para una comparación completa.

Descubrir herramientas disponibles

Para ver qué herramientas proporciona un servidor MCP, consulte la documentación del servidor o inspeccione el array tools en el mensaje init system. Los nombres de herramientas MCP comienzan con mcp__.

Claude Code emite el mensaje init después de la espera de conexión de primer turno para servidores pasados en options.mcpServers, por lo que el array tools enumera las herramientas mcp__ de cada servidor que se ha conectado para entonces, más las de servidores con una lista de herramientas en caché, que se conectan en el primer uso. Las herramientas de cualquier otro servidor que no se haya conectado están ausentes; consulte Manejo de errores para leer el estado de cada servidor.

Este filtro imprime los nombres de herramientas MCP:

import { query } from "@anthropic-ai/claude-agent-sdk";

const options = {
  mcpServers: {
    // your servers
  },
};

for await (const message of query({ prompt: "...", options })) {
  if (message.type === "system" && message.subtype === "init") {
    const mcpTools = message.tools.filter((name) => name.startsWith("mcp__"));
    console.log("Available MCP tools:", mcpTools);
  }
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, SystemMessage


async def main():
    options = ClaudeAgentOptions(
        mcp_servers={
            # your servers
        },
    )
    async for message in query(prompt="...", options=options):
        if isinstance(message, SystemMessage) and message.subtype == "init":
            mcp_tools = [t for t in message.data.get("tools", []) if t.startswith("mcp__")]
            print("Available MCP tools:", mcp_tools)


asyncio.run(main())

También puede pedirle a Claude que enumere las herramientas disponibles de un servidor.

Tipos de transporte

Los servidores MCP se comunican con su agente utilizando diferentes protocolos de transporte. Consulte la documentación del servidor para ver qué transporte admite:

  • Si la documentación le proporciona un comando para ejecutar (como npx @modelcontextprotocol/server-filesystem), use stdio
  • Si la documentación le proporciona una URL, use HTTP o SSE
  • Si está creando sus propias herramientas en código, use un servidor MCP SDK

Servidores stdio

Procesos locales que se comunican a través de stdin/stdout. Utiliza esto para servidores MCP que ejecutas en la misma máquina. Para el formato .mcp.json, usa los mismos campos que se muestran en Agregar un servidor desde un archivo de configuración. En código, pasa el comando y sus argumentos. Reemplaza /Users/me/projects con un directorio en tu máquina:

const _ = {
  options: {
    mcpServers: {
      filesystem: {
        command: "npx",
        args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"]
      }
    },
    allowedTools: ["mcp__filesystem__read_file", "mcp__filesystem__list_directory"]
  }
};
options = ClaudeAgentOptions(
    mcp_servers={
        "filesystem": {
            "command": "npx",
            "args": [
                "-y",
                "@modelcontextprotocol/server-filesystem",
                "/Users/me/projects",
            ],
        }
    },
    allowed_tools=["mcp__filesystem__read_file", "mcp__filesystem__list_directory"],
)

Servidores HTTP/SSE

Use HTTP o SSE para servidores MCP alojados en la nube y API remotas. Para el formulario .mcp.json, use los mismos campos que en el ejemplo en Encabezados HTTP para servidores remotos, con "type": "sse" para un servidor SSE. En código, pase la URL del servidor:

const _ = {
  options: {
    mcpServers: {
      "remote-api": {
        type: "sse",
        url: "https://api.example.com/mcp/sse",
        headers: {
          Authorization: `Bearer ${process.env.API_TOKEN}`
        }
      }
    },
    allowedTools: ["mcp__remote-api__*"]
  }
};
options = ClaudeAgentOptions(
    mcp_servers={
        "remote-api": {
            "type": "sse",
            "url": "https://api.example.com/mcp/sse",
            "headers": {"Authorization": f"Bearer {os.environ['API_TOKEN']}"},
        }
    },
    allowed_tools=["mcp__remote-api__*"],
)

Para el transporte HTTP transmisible, use "type": "http" en su lugar. En archivos de configuración .mcp.json y otros JSON, "streamable-http" se acepta como un alias para "http". El tipo McpHttpServerConfig de los SDK declara solo "http", así que use "http" para servidores que pase en código.

Servidores MCP SDK

Defina herramientas personalizadas directamente en el código de su aplicación en lugar de ejecutar un proceso de servidor separado. Consulte la guía de herramientas personalizadas para obtener detalles de implementación.

Un servidor MCP SDK registrado por una solicitud de control initialize comienza a conectarse tan pronto como Claude Code procesa la solicitud.

Búsqueda de herramientas MCP

Cuando tiene muchas herramientas MCP configuradas, las definiciones de herramientas pueden consumir una porción significativa de su ventana de contexto. La búsqueda de herramientas resuelve esto al retener las definiciones de herramientas del contexto y cargar solo las que Claude necesita para cada turno.

La búsqueda de herramientas está habilitada de forma predeterminada. Consulte Búsqueda de herramientas para opciones de configuración, mejores prácticas y uso de búsqueda de herramientas con herramientas SDK personalizadas.

Autenticación

La mayoría de los servidores MCP requieren autenticación para acceder a servicios externos. Pase las credenciales a través de variables de entorno en la configuración del servidor.

Pasar credenciales a través de variables de entorno

Use el campo env para pasar claves API, tokens y otras credenciales al servidor MCP:

[tab] En código

const _ = {
  options: {
    mcpServers: {
      "api-server": {
        command: "npx",
        args: ["-y", "@your-org/api-mcp-server"],
        env: {
          API_KEY: process.env.API_KEY
        }
      }
    },
    allowedTools: ["mcp__api-server__*"]
  }
};
options = ClaudeAgentOptions(
    mcp_servers={
        "api-server": {
            "command": "npx",
            "args": ["-y", "@your-org/api-mcp-server"],
            "env": {"API_KEY": os.environ["API_KEY"]},
        }
    },
    allowed_tools=["mcp__api-server__*"],
)

[tab] .mcp.json

{
  "mcpServers": {
    "api-server": {
      "command": "npx",
      "args": ["-y", "@your-org/api-mcp-server"],
      "env": {
        "API_KEY": "${API_KEY}"
      }
    }
  }
}

La sintaxis ${API_KEY} expande variables de entorno en tiempo de ejecución.

Encabezados HTTP para servidores remotos

Para servidores HTTP y SSE, pase los encabezados de autenticación directamente en la configuración del servidor:

[tab] En código

const _ = {
  options: {
    mcpServers: {
      "secure-api": {
        type: "http",
        url: "https://api.example.com/mcp",
        headers: {
          Authorization: `Bearer ${process.env.API_TOKEN}`
        }
      }
    },
    allowedTools: ["mcp__secure-api__*"]
  }
};
options = ClaudeAgentOptions(
    mcp_servers={
        "secure-api": {
            "type": "http",
            "url": "https://api.example.com/mcp",
            "headers": {"Authorization": f"Bearer {os.environ['API_TOKEN']}"},
        }
    },
    allowed_tools=["mcp__secure-api__*"],
)

[tab] .mcp.json

{
  "mcpServers": {
    "secure-api": {
      "type": "http",
      "url": "https://api.example.com/mcp",
      "headers": {
        "Authorization": "Bearer ${API_TOKEN}"
      }
    }
  }
}

La sintaxis ${API_TOKEN} expande variables de entorno en tiempo de ejecución.

Para un ejemplo completo y funcional de un servidor remoto autenticado con encabezados, consulte Listar problemas de un repositorio.

Autenticación OAuth2

La especificación MCP admite OAuth 2.1 para autorización. El SDK no abre un navegador ni ejecuta un flujo OAuth interactivo. Cuando un servidor configurado devuelve un desafío de autorización y Claude Code no tiene ningún token para enviar, el SDK informa el estado del servidor como needs-auth o failed:

  • needs-auth: Claude Code no encontró ningún inicio de sesión que pueda usar para el servidor. Pasa un token en headers, o inicia sesión desde una sesión interactiva de Claude Code en la misma máquina antes de la ejecución.
  • failed, con un error en su entrada de McpServerStatus que comienza con Couldn't read the stored credentials o A request to MCP server: Claude Code no pudo leer su almacén de credenciales. Para saber qué hacer, consulta Couldn't read the stored credentials for MCP server. Antes de Claude Code v2.1.307, el estado era needs-auth en su lugar cuando el llavero de inicio de sesión de una Mac estaba bloqueado.

En cualquiera de los casos, la ejecución del agente continúa sin las herramientas de ese servidor. La matriz mcp_servers del mensaje de inicialización del sistema aún puede mostrar pending para ese servidor cuando se emite. Para confirmar si un servidor necesita credenciales, consulta mcpServerStatus() en el SDK de TypeScript o get_mcp_status() en Python.

Para proporcionar credenciales, complete el flujo OAuth en su propia aplicación y pase el token de acceso resultante en los headers del servidor:

// Después de completar el flujo OAuth en su aplicación.
// Implemente getAccessTokenFromOAuthFlow para su proveedor OAuth.
const accessToken = await getAccessTokenFromOAuthFlow();

const options = {
  mcpServers: {
    "oauth-api": {
      type: "http",
      url: "https://api.example.com/mcp",
      headers: {
        Authorization: `Bearer ${accessToken}`
      }
    }
  },
  allowedTools: ["mcp__oauth-api__*"]
};
# Después de completar el flujo OAuth en su aplicación.
# Implemente get_access_token_from_oauth_flow para su proveedor OAuth.
access_token = await get_access_token_from_oauth_flow()

options = ClaudeAgentOptions(
    mcp_servers={
        "oauth-api": {
            "type": "http",
            "url": "https://api.example.com/mcp",
            "headers": {"Authorization": f"Bearer {access_token}"},
        }
    },
    allowed_tools=["mcp__oauth-api__*"],
)

Ejemplos

Listar problemas de un repositorio

Este ejemplo se conecta al servidor MCP de GitHub remoto para listar problemas recientes. El ejemplo incluye registro de depuración para verificar la conexión MCP y las llamadas a herramientas.

Antes de ejecutar, cree un token de acceso personal de GitHub con acceso de lectura a los repositorios que desea consultar y establézcalo como variable de entorno:

export GITHUB_TOKEN=YOUR_GITHUB_PAT
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "List the 3 most recent issues in anthropics/claude-code",
  options: {
    mcpServers: {
      github: {
        type: "http",
        url: "https://api.githubcopilot.com/mcp/",
        headers: {
          Authorization: `Bearer ${process.env.GITHUB_TOKEN}`
        }
      }
    },
    allowedTools: ["mcp__github__list_issues"]
  }
})) {
  // Verify MCP server connected successfully
  if (message.type === "system" && message.subtype === "init") {
    console.log("MCP servers:", message.mcp_servers);
  }

  // Log when Claude calls an MCP tool
  if (message.type === "assistant") {
    for (const block of message.message.content) {
      if (block.type === "tool_use" && block.name.startsWith("mcp__")) {
        console.log("MCP tool called:", block.name);
      }
    }
  }

  // Print the final result
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}
import asyncio
import os
from claude_agent_sdk import (
    query,
    ClaudeAgentOptions,
    ResultMessage,
    SystemMessage,
    AssistantMessage,
)


async def main():
    options = ClaudeAgentOptions(
        mcp_servers={
            "github": {
                "type": "http",
                "url": "https://api.githubcopilot.com/mcp/",
                "headers": {"Authorization": f"Bearer {os.environ['GITHUB_TOKEN']}"},
            }
        },
        allowed_tools=["mcp__github__list_issues"],
    )

    async for message in query(
        prompt="List the 3 most recent issues in anthropics/claude-code",
        options=options,
    ):
        # Verify MCP server connected successfully
        if isinstance(message, SystemMessage) and message.subtype == "init":
            print("MCP servers:", message.data.get("mcp_servers"))

        # Log when Claude calls an MCP tool
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if hasattr(block, "name") and block.name.startswith("mcp__"):
                    print("MCP tool called:", block.name)

        # Print the final result
        if isinstance(message, ResultMessage) and message.subtype == "success":
            print(message.result)


asyncio.run(main())

En la línea MCP servers:, un status de connected para github confirma que el token funciona. Si Claude Code tiene una lista de herramientas en caché para el servidor, el estado puede mostrar pending en su lugar y el servidor se conecta en su primera llamada a herramienta. Si el estado es failed o needs-auth, consulte Manejo de errores antes de confiar en el resultado, ya que Claude puede recurrir a herramientas integradas cuando el servidor no está disponible.

Consultar una base de datos

Este ejemplo utiliza DBHub para consultar una base de datos Postgres. El agente descubre automáticamente el esquema de la base de datos, escribe la consulta SQL y devuelve los resultados.

La herramienta execute_sql de DBHub ejecuta cualquier SQL que emita el agente, incluidas escrituras, a menos que lo restrinja. Establecer readonly = true en el archivo de configuración de DBHub hace que DBHub rechace las declaraciones INSERT, UPDATE, DELETE y DDL, por lo que el ejemplo no puede modificar sus datos incluso si el agente emite una escritura. DBHub resuelve ${DATABASE_URL} desde el entorno del proceso cuando carga la configuración, por lo que la cadena de conexión se mantiene fuera del archivo. Cree este dbhub.toml junto a su script:

[[sources]]
id = "production"
dsn = "${DATABASE_URL}"

[[tools]]
name = "execute_sql"
source = "production"
readonly = true

El script luego apunta DBHub al archivo de configuración en lugar de pasar una cadena de conexión directamente. Antes de ejecutar, establezca la variable de entorno DATABASE_URL en su cadena de conexión. Reemplace los valores de marcador de posición con los detalles de su propia base de datos:

export DATABASE_URL=postgresql://user:password@localhost:5432/mydb
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  // Natural language query - Claude writes the SQL
  prompt: "How many users signed up last week? Break it down by day.",
  options: {
    mcpServers: {
      postgres: {
        command: "npx",
        // dbhub.toml sets readonly = true, so execute_sql rejects writes
        args: ["-y", "@bytebase/dbhub", "--config", "dbhub.toml"]
      }
    },
    allowedTools: ["mcp__postgres__execute_sql"]
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage


async def main():
    options = ClaudeAgentOptions(
        mcp_servers={
            "postgres": {
                "command": "npx",
                # dbhub.toml sets readonly = true, so execute_sql rejects writes
                "args": [
                    "-y",
                    "@bytebase/dbhub",
                    "--config",
                    "dbhub.toml",
                ],
            }
        },
        allowed_tools=["mcp__postgres__execute_sql"],
    )

    # Natural language query - Claude writes the SQL
    async for message in query(
        prompt="How many users signed up last week? Break it down by day.",
        options=options,
    ):
        if isinstance(message, ResultMessage) and message.subtype == "success":
            print(message.result)


asyncio.run(main())

Manejo de errores

Los servidores MCP pueden fallar al conectarse por varias razones: el proceso del servidor podría no estar instalado, las credenciales podrían ser inválidas, o un servidor remoto podría ser inaccesible.

Claude Code emite un mensaje system con subtipo init al inicio de cada consulta. Este mensaje incluye el estado de conexión para cada servidor MCP. El campo status puede ser "pending", "connected", "failed", "needs-auth" o "disabled". Claude Code emite el mensaje init después del tiempo de espera de conexión de primer turno para servidores pasados en options.mcpServers, por lo que un servidor de este tipo que se conectó dentro del tiempo de espera muestra "connected".

En el mensaje init, no trate "pending" como un fallo por sí solo. Puede significar cualquiera de estos:

Verifique "failed" o "needs-auth" para detectar servidores que no serán utilizables:

import { query } from "@anthropic-ai/claude-agent-sdk";

try {
  for await (const message of query({
    prompt: "Process data",
    options: {
      mcpServers: {
        // Replace dataServer with your server configuration
        "data-processor": dataServer
      }
    }
  })) {
    if (message.type === "system" && message.subtype === "init") {
      const unavailableServers = message.mcp_servers.filter(
        (s) => s.status === "failed" || s.status === "needs-auth"
      );

      if (unavailableServers.length > 0) {
        console.warn("Unavailable MCP servers:", unavailableServers);
      }
    }

    if (message.type === "result" && message.subtype === "error_during_execution") {
      console.error("Execution failed");
    }
  }
} catch (error) {
  // A single-shot query() throws after yielding an error result. If the
  // failure was an error result, the error subtype branch above has
  // already run; a failure to start or reach the Claude Code process
  // yields no result message. MCP servers that fail to connect don't
  // throw: use the status check above, and note that servers still
  // "pending" at init need a later status check.
  console.log(`Session ended with an error: ${error}`);
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, SystemMessage, ResultMessage


async def main():
    # Replace data_server with your server configuration
    options = ClaudeAgentOptions(mcp_servers={"data-processor": data_server})

    try:
        async for message in query(prompt="Process data", options=options):
            if isinstance(message, SystemMessage) and message.subtype == "init":
                unavailable_servers = [
                    s
                    for s in message.data.get("mcp_servers", [])
                    if s.get("status") in ("failed", "needs-auth")
                ]

                if unavailable_servers:
                    print(f"Unavailable MCP servers: {unavailable_servers}")

            if (
                isinstance(message, ResultMessage)
                and message.subtype == "error_during_execution"
            ):
                print("Execution failed")
    except Exception as error:
        # A single-shot query() raises after yielding an error result. If the
        # failure was an error result, the error subtype branch above has
        # already run; a failure to start or reach the Claude Code process
        # yields no result message. MCP servers that fail to connect don't
        # raise: use the status check above, and note that servers still
        # "pending" at init need a later status check.
        print(f"Session ended with an error: {error}")


asyncio.run(main())

El estado de un servidor remoto también puede cambiar después de que reporta "connected". Cuando la conexión a él se cae a mitad de sesión, Claude Code mueve el servidor de vuelta a "pending" mientras se reconecta. Una llamada posterior a mcpServerStatus() en TypeScript, o ClaudeSDKClient.get_mcp_status() en Python, puede entonces reportar "pending" para un servidor que vio conectado anteriormente, sin cambio de configuración de su parte.

Después de que cinco intentos de reconexión fallen, el servidor reporta "failed", o "needs-auth" cuando necesita ser autorizado nuevamente. Un servidor HTTP o SSE en estado "failed" aún puede volver a "connected" sin que hagas ninguna llamada, porque Claude Code sigue reintentando en segundo plano después de un error transitorio. Para reintentar manualmente, llama a reconnectMcpServer() en TypeScript o ClaudeSDKClient.reconnect_mcp_server() en Python.

Solución de problemas

El servidor muestra estado "failed"

Verifique el mensaje init para ver qué servidores no pudieron conectarse:

if (message.type === "system" && message.subtype === "init") {
  for (const server of message.mcp_servers) {
    if (server.status === "failed") {
      console.error(`Server ${server.name} failed to connect`);
    }
  }
}
if isinstance(message, SystemMessage) and message.subtype == "init":
    for server in message.data.get("mcp_servers", []):
        if server.get("status") == "failed":
            print(f"Server {server['name']} failed to connect")

Un estado "pending" no significa que el servidor haya fallado. Consulte Manejo de errores para ver los casos que cubre en la inicialización. Para obtener estados actualizados más adelante en la sesión, llame al método mcpServerStatus() de la consulta en el SDK de TypeScript, o ClaudeSDKClient.get_mcp_status() en Python.

Causas comunes:

  • Variables de entorno faltantes: Asegúrese de que los tokens y credenciales requeridos estén configurados. Para servidores stdio, verifique que el campo env coincida con lo que el servidor espera.
  • Servidor no instalado: Para comandos npx, verifique que el paquete exista y que Node.js esté en su PATH.
  • Cadena de conexión inválida: Para servidores de base de datos, verifique el formato de la cadena de conexión y que la base de datos sea accesible.
  • Problemas de red: Para servidores HTTP/SSE remotos, verifique que la URL sea accesible y que los firewalls permitan la conexión.

Las herramientas no se están llamando

Si Claude ve herramientas pero no las utiliza, verifique que haya otorgado permiso con allowedTools:

const _ = {
  options: {
    mcpServers: {
      // your servers
    },
    allowedTools: ["mcp__servername__*"] // Auto-approve calls from this server
  }
};
options = ClaudeAgentOptions(
    mcp_servers={
        # your servers
    },
    allowed_tools=["mcp__servername__*"],  # Auto-approve calls from this server
)

Falta una herramienta en un servidor MCP del SDK

En el SDK de TypeScript, cuando el esquema de entrada de una herramienta no se puede convertir a JSON Schema, el servidor que creaste con createSdkMcpServer() omite esa herramienta al listar sus herramientas. En ese momento, el SDK emite una advertencia. En Node.js, la advertencia es una advertencia de proceso con el código CLAUDE_SDK_MCP_TOOL_SCHEMA_UNCONVERTIBLE, y comienza con este texto:

Tool "<name>" on SDK MCP server "<server>" was left out of the server's tool list, because its input schema cannot be converted to JSON Schema

El resto de la advertencia incluye el mensaje del error de conversión cuando lo hay y, a continuación, indica qué revisar y cambiar.

Antes de la versión v0.3.286 del Agent SDK de TypeScript, un solo esquema no convertible hacía que fallara todo el listado de herramientas del servidor sin esta advertencia, por lo que ninguna de las herramientas de ese servidor llegaba a Claude.

Tiempos de espera de conexión

Las conexiones del servidor MCP se agotan después de 30 segundos de forma predeterminada. Para cambiar cuánto tiempo puede tomar una llamada de herramienta en ejecución, establezca MCP_TOOL_TIMEOUT. Si su servidor tarda más en iniciarse, la conexión falla. Aumente el límite de conexión con la variable de entorno MCP_TIMEOUT, en milisegundos. Para servidores que necesitan más tiempo de inicio, también considere:

  • Usar un servidor más ligero si está disponible
  • Precalentar el servidor antes de iniciar su agente
  • Verificar los registros del servidor para detectar causas de inicialización lenta

En TypeScript, puede establecer el límite de llamadas de herramientas para un único servidor MCP del SDK pasando timeout a createSdkMcpServer().

La salida de la herramienta excede el máximo de tokens permitidos

El SDK aplica los mismos límites de salida MCP que Claude Code. Cuando el resultado exitoso de una herramienta sin contenido de imagen es mayor que 25.000 tokens, Claude Code guarda la salida en un archivo y reemplaza el resultado de la herramienta con un mensaje de error que nombra la ruta del archivo, para que el agente pueda leer la salida en porciones.

Para cambiar el límite de tokens, establece la variable de entorno MAX_MCP_OUTPUT_TOKENS. A menos que la herramienta declare anthropic/maxResultSizeChars, un resultado de texto exitoso de más de 50.000 caracteres se guarda en un archivo independientemente del límite de tokens. Consulta Límites de salida MCP y advertencias para el comportamiento completo, incluida la forma en que un servidor declara esa anotación.

Recursos relacionados