Skip to main content
Las herramientas personalizadas extienden el SDK del Agente permitiéndole definir sus propias funciones que Claude puede llamar durante una conversación. Usando el servidor MCP en proceso del SDK, puede dar a Claude acceso a bases de datos, APIs externas, lógica específica del dominio u cualquier otra capacidad que su aplicación necesite.

Referencia rápida

Crear una herramienta personalizada

Una herramienta se define por cuatro partes, pasadas como argumentos al helper tool() en TypeScript o al decorador @tool en Python:
  • Nombre: un identificador único que Claude utiliza para llamar a la herramienta.
  • Descripción: qué hace la herramienta. Claude lee esto para decidir cuándo llamarla.
  • Esquema de entrada: los argumentos que acepta la herramienta, declarados según el lenguaje:
    • TypeScript: un esquema Zod. Los args del manejador toman sus tipos a partir de él. Llama a .describe() en un campo para darle una descripción que Claude ve.
    • Python: un diccionario que asigna nombres a tipos, como {"latitude": float}, que el SDK convierte a JSON Schema por ti. Envuelve un tipo en Annotated, como {"latitude": Annotated[float, "Latitude coordinate"]}, para darle al campo una descripción que Claude ve. El decorador también acepta un diccionario completo de JSON Schema directamente cuando necesitas enumeraciones, rangos, campos opcionales u objetos anidados.
  • Manejador: la función asincrónica que se ejecuta cuando Claude llama a la herramienta. Recibe los argumentos validados y debe devolver un objeto con:
    • content (requerido): una matriz de bloques de resultado, cada uno con un type de "text", "image", "audio", "resource" o "resource_link". Consulte Devolver imágenes y recursos para bloques que no sean texto.
    • structuredContent (opcional): un objeto JSON que contiene el resultado como datos legibles por máquina, devuelto junto con content. Consulte Devolver datos estructurados.
    • isError (opcional): establézcalo en true para señalar un fallo de herramienta para que Claude pueda reaccionar. Consulte Manejar errores.
Después de definir una herramienta, envuélvala en un servidor con createSdkMcpServer (TypeScript) o create_sdk_mcp_server (Python). El servidor se ejecuta en el proceso dentro de su aplicación, no como un proceso separado. Los ejemplos de Python de esta página que realizan solicitudes HTTP usan httpx. Agrégalo con el gestor de paquetes que usa tu proyecto:

Ejemplo de herramienta meteorológica

Este ejemplo define una herramienta get_temperature y la envuelve en un servidor MCP, sin pasar el servidor a query. Para ejecutar la herramienta, consulta Llamar a una herramienta personalizada a continuación.
Consulte la referencia de TypeScript tool() o la referencia de Python @tool para obtener detalles completos de parámetros, incluidos formatos de entrada de JSON Schema y estructura de valores de retorno.

Hacer un parámetro opcional

Para hacer un parámetro opcional, decláralo como opcional en el esquema y aplica el valor predeterminado en el manejador:
  • TypeScript: agrega .optional() al campo Zod.
  • Python: el esquema de diccionario requiere cada clave. Usa la forma de JSON Schema, deja el parámetro fuera de required y léelo con args.get(). Para un esquema tipado con claves opcionales, consulta clase TypedDict.
La herramienta get_precipitation_chance a continuación muestra ambos patrones.

Llamar a una herramienta personalizada

Pase el servidor MCP que creó a query a través de la opción mcpServers. La clave en mcpServers se convierte en el segmento {server_name} en el nombre completamente calificado de cada herramienta: mcp__{server_name}__{tool_name}. Liste ese nombre en allowedTools para que la herramienta se ejecute sin un aviso de permiso. Estos fragmentos reutilizan el weatherServer del ejemplo de herramienta meteorológica para preguntarle a Claude cuál es el clima en una ubicación específica.
Combina este fragmento con las definiciones de herramienta y servidor del ejemplo de herramienta meteorológica en un archivo, weather.py o weather.ts, y luego ejecútalo desde tu terminal:
Claude llama a get_temperature y el script imprime una respuesta de una línea con la temperatura actual en San Francisco.

Agregar más herramientas

Un servidor contiene tantas herramientas como liste en su matriz tools. Con más de una herramienta en un servidor, puede listar cada una en allowedTools individualmente o usar el comodín mcp__weather__* para cubrir cada herramienta que el servidor expone. El ejemplo a continuación define una segunda herramienta, get_precipitation_chance, y reemplaza la definición de weatherServer del ejemplo de herramienta meteorológica con una que lista ambas herramientas en la matriz.
Búsqueda de herramientas está habilitada de forma predeterminada y difiere las herramientas MCP del SDK: Claude ve el nombre de cada herramienta en una lista compacta y carga su esquema completo bajo demanda. Con la búsqueda de herramientas deshabilitada, cada herramienta en esta matriz consume espacio de ventana de contexto en cada turno. En TypeScript, pase alwaysLoad: true en el argumento extras de tool() o en las opciones de createSdkMcpServer() para mantener el esquema completo de una herramienta en el aviso inicial.

Agregar anotaciones de herramientas

Las anotaciones de herramientas son metadatos opcionales que describen cómo se comporta una herramienta. Páselas como el quinto argumento al helper tool() en TypeScript o a través del argumento de palabra clave annotations para el decorador @tool en Python. Todos los campos de sugerencia son booleanos. Las anotaciones son metadatos, no cumplimiento. Una herramienta marcada como readOnlyHint: true aún puede escribir en el disco si eso es lo que hace el manejador. Mantenga la anotación precisa con respecto al manejador. Este ejemplo agrega readOnlyHint a la herramienta get_temperature del ejemplo de herramienta meteorológica.
Consulte ToolAnnotations en la referencia de TypeScript o Python.

Controlar el acceso a herramientas

El ejemplo de herramienta meteorológica registró un servidor y enumeró herramientas en allowedTools. Esta sección cubre cómo delimitar el acceso cuando tiene varias herramientas o desea restringir las integradas. Para saber cómo se construyen los nombres de herramientas, consulte Llamar a una herramienta personalizada.

Configurar herramientas permitidas

La opción tools y las listas permitidas/no permitidas afectan dos capas: disponibilidad, que controla si una herramienta aparece en el contexto de Claude, y permiso, que controla si una llamada se aprueba una vez que Claude intenta realizarla. tools y las entradas de disallowedTools con nombre simple cambian la disponibilidad. allowedTools y las reglas de disallowedTools con alcance cambian el permiso. Si nombra una de las herramientas de seguimiento de tareas en allowedTools, Claude Code también opta por la sesión. Para eliminar una herramienta integrada por completo, omítala de tools o enumere su nombre simple en disallowedTools (Python: disallowed_tools); ambas mantienen la herramienta fuera del contexto para que Claude nunca intente usarla. Una regla de disallowedTools con alcance bloquea las llamadas coincidentes pero deja la herramienta visible, por lo que Claude puede desperdiciar un turno intentándolo. Consulte Configurar permisos para el orden de evaluación completo.

Manejar errores

Un error del controlador no detiene el bucle del agente. El servidor MCP en proceso del SDK detecta excepciones no capturadas y las devuelve como resultados de error, por lo que la forma en que informa un error determina lo que Claude lee, no si la consulta falla: En ambos casos Claude puede reintentar, probar una herramienta diferente o explicar el fallo. Capture errores usted mismo cuando el mensaje de excepción sin procesar no sea suficiente para que Claude actúe. El ejemplo a continuación captura dos tipos de fallos dentro del controlador y compone el mensaje de error que Claude lee. Un estado HTTP que no es 200 se captura de la respuesta y se devuelve como un resultado de error. Un error de red o JSON inválido se captura por el try/except (Python) o try/catch (TypeScript) circundante y también se devuelve como un resultado de error. En ambos casos Claude recibe un mensaje que describe el fallo en lugar de una cadena de excepción sin procesar.

Devolver imágenes y recursos

El array content en un resultado de herramienta acepta bloques text, image, audio, resource y resource_link. Puede mezclarlos en la misma respuesta. En TypeScript, el SDK guarda bloques de audio en disco y Claude recibe un bloque de texto con la ruta del archivo guardado; en Python, el SDK elimina bloques de audio del resultado de la herramienta y registra una advertencia. Claude recibe cada bloque de enlace de recurso como un bloque de texto que contiene el nombre, URI y descripción del enlace. En TypeScript, su aplicación también recibe los enlaces mismos como resourceLinks en el tool_use_result del mensaje del usuario; en Python, el SDK los aplana a texto antes de que la CLI vea el resultado, por lo que la clave resourceLinks de Python nunca se produce para herramientas en proceso.

Imágenes

Un bloque de imagen lleva los bytes de la imagen en línea, codificados como base64. No hay campo de URL. Para devolver una imagen que vive en una URL, búsquela en el controlador, lea los bytes de respuesta y codifíquelos en base64 antes de devolverlos. Una imagen PNG, JPEG, GIF o WebP llega a Claude como entrada visual; una imagen de cualquier otro tipo se guarda en disco y Claude recibe su ruta de archivo como texto en su lugar.

Recursos

Un bloque de recurso incrusta un contenido identificado por un URI. El contenido real se encuentra en el campo text o blob del bloque. Úselo cuando su herramienta produce un archivo generado o un registro de un sistema externo. Este ejemplo muestra un bloque de recurso devuelto desde dentro de un controlador de herramienta. El SDK no lee desde el URI del ejemplo, file:///tmp/report.md.
Estas formas de bloque provienen del tipo MCP CallToolResult. Consulte la especificación de MCP para la definición completa.

Devolver datos estructurados

structuredContent es un objeto JSON opcional en el resultado, separado del array content. Úselo para devolver valores sin procesar que Claude pueda leer como campos exactos en lugar de analizarlos de una cadena de texto o imagen. Cuando structuredContent está configurado, Claude recibe el JSON más cualquier bloque de imagen o recurso de content. Los bloques de texto en content no se reenvían, ya que se asume que duplican los datos estructurados. El ejemplo a continuación representa un gráfico como un bloque de imagen y devuelve los puntos de datos detrás de él en structuredContent desde el mismo controlador. En el fragmento, chartPngBuffer es un Buffer que contiene los bytes PNG renderizados.
TypeScript
El decorador @tool de Python reenvía solo content e is_error del diccionario de retorno del controlador. Para devolver structuredContent desde Python, ejecute un servidor MCP independiente en lugar de un servidor SDK en proceso.

Ejemplo: convertidor de unidades

Esta herramienta convierte valores entre unidades de longitud, temperatura y peso. Un usuario puede preguntar “convertir 100 kilómetros a millas” o “¿cuántos grados Celsius son 72°F?”, y Claude elige el tipo de unidad correcto y las unidades de la solicitud. Demuestra dos patrones:
  • Esquemas de enumeración: unit_type está restringido a un conjunto fijo de valores. En TypeScript, use z.enum(). En Python, el esquema dict no admite enumeraciones, por lo que se requiere el esquema JSON Schema completo.
  • Manejo de entrada no compatible: cuando no se encuentra un par de conversión, el controlador devuelve isError: true para que Claude pueda indicar al usuario qué salió mal en lugar de tratar un fallo como un resultado normal.
Una vez que el servidor está definido, páselo a query de la misma manera que el ejemplo del clima. Este ejemplo envía tres solicitudes diferentes en un bucle para mostrar la misma herramienta manejando diferentes tipos de unidades. Para cada respuesta, inspecciona objetos AssistantMessage (que contienen las llamadas a herramientas que Claude realizó durante ese turno) e imprime cada ToolUseBlock antes de imprimir el texto final de ResultMessage. Esto le permite ver cuándo Claude está usando la herramienta frente a responder desde su propio conocimiento. Debido a que tool search está activado de forma predeterminada, la salida también puede incluir una llamada a ToolSearch cuando Claude carga el esquema de herramienta diferido.

Próximos pasos

Puede mezclar los patrones en esta página en el mismo servidor: un único servidor puede contener una herramienta de base de datos, una herramienta de puerta de enlace API y un renderizador de imágenes uno al lado del otro. Desde aquí:
  • Si su servidor crece a docenas de herramientas, consulte búsqueda de herramientas para diferir su carga hasta que Claude las necesite.
  • Para conectarse a servidores MCP externos (sistema de archivos, GitHub, Slack) en lugar de construir los suyos propios, consulte Conectar servidores MCP.
  • Para controlar qué herramientas se ejecutan automáticamente frente a las que requieren aprobación, consulte Configurar permisos.