Del script a tu propio agente: el Claude Agent SDK en 90 minutos
Conoces Claude Code como CLI. Con el Agent SDK integras el mismo bucle agéntico en tu propio código, con control de herramientas, límite de presupuesto y conexión MCP. Paso a paso.
A Claude Code lo conoces como esa cosa del terminal. Escribes, lee ficheros, escribe código, pregunta. Lo que mucha gente no sabe es que justo ese bucle agéntico está dentro de un paquete npm que puedes meter en tu propio proyecto. El Claude Agent SDK. Con él no construyes un chatbot que solo devuelve texto, sino un agente que usa herramientas, toca ficheros, planifica varios pasos y al final entrega un resultado. En este playbook construimos paso a paso un agente pequeño que revisa un fichero en busca de bugs y los arregla él mismo. Después sabrás cómo permitir herramientas, poner tope a los costes y enganchar un servidor MCP. Necesitas Node 20 o superior y una API key de Anthropic.
1. Cuándo compensa el SDK y cuándo no
Antes de instalar, una ubicación honesta. El SDK no es "Claude Code pero como librería para chatear". Es el bucle agéntico sin la interfaz de terminal alrededor. Lo coges cuando quieres meter comportamiento de agente en algo propio: un job de CI que revisa PRs, un cron nocturno que repasa logs, una herramienta interna que despacha tickets. Si solo quieres mandar un prompt y recibir una respuesta, sin herramientas y sin varios pasos, entonces la API normal de mensajes de Anthropic es la opción más simple. El SDK brilla solo cuando el agente tiene que pensar más de una vez y además hacer algo. A mí me da la sensación de que la mayoría echa mano del SDK demasiado pronto, para cosas que también resolvería una simple llamada a la API.
2. Instalar y la primera señal de vida
Crea un proyecto vacío e instala el paquete. El estado actual es la versión 0.3.162.
npm install @anthropic-ai/claude-agent-sdk
export ANTHROPIC_API_KEY=sk-ant-...
Y ahora el agente más corto que existe. Un fichero agent.mjs:
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Explicame en dos frases que hace esta base de codigo.",
options: {
maxTurns: 1,
allowedTools: ["Read", "Grep"]
}
})) {
if (message.type === "result") {
console.log(message.result);
}
}
query() no es una llamada normal que devuelve un objeto. Es un iterador asíncrono. Recorres con for await un flujo de mensajes mientras el agente trabaja. Eso es justo lo que lo convierte en agente y no en un endpoint de chat.
3. Entender de verdad el bucle agéntico
Cada mensaje del iterador tiene un type. Al principio necesitas tres. assistant es Claude pensando o llamando a una herramienta. result es el resultado final. Entre medias pueden venir muchos mensajes assistant, cada uno un paso del bucle. Así lees los dos:
for await (const message of query({ prompt, options })) {
if (message.type === "assistant" && message.message?.content) {
for (const block of message.message.content) {
if ("text" in block) {
console.log(block.text); // el razonamiento de Claude
} else if ("name" in block) {
console.log(`Tool: ${block.name}`); // que herramienta corre ahora
}
}
} else if (message.type === "result") {
console.log(`Listo: ${message.subtype}`);
}
}
Cuando lo ves correr una vez, entiendes todo el SDK. Claude piensa, llama a una herramienta, recibe el resultado, sigue pensando, hasta que termina. Tú solo miras y decides qué puede tocar.
4. Permitir y bloquear herramientas
La palanca más importante es allowedTools. Si la dejas fuera, Claude puede usar todas las herramientas integradas, también Bash y Write. Eso al principio no lo quieres. Indica explícitamente qué está permitido:
options: {
allowedTools: ["Read", "Edit", "Glob", "Grep"],
disallowedTools: ["Bash"]
}
Los nombres de las herramientas integradas son los mismos que en Claude Code: Read, Write, Edit, Glob, Grep, Bash. Una regla práctica que funciona: empieza solo con herramientas de lectura, Read, Grep, Glob, y limítate a observar al agente. Solo cuando el comportamiento encaje, añades Edit. Bash lo das el último y solo si de verdad hace falta, porque con eso el agente puede lanzar comandos arbitrarios.
5. Permission mode, el tornillo de seguridad
Permitir herramientas es una mitad, la otra es quién hace el clic. Para eso está permissionMode. Por defecto es 'default', donde el agente pregunta en las acciones delicadas, lo cual en un script sin una persona delante acaba en un cuelgue. Para tiradas sin supervisión coges 'acceptEdits', y entonces las ediciones de ficheros pasan automáticamente y el resto sigue controlado:
options: {
allowedTools: ["Read", "Edit", "Glob"],
permissionMode: "acceptEdits"
}
También existe 'bypassPermissions', que deja pasar de verdad todo. Para eso además tienes que poner allowDangerouslySkipPermissions: true, y el nombre lo dice todo. Usa eso solo en una sandbox o en un contenedor desechable, nunca en tu máquina real con ficheros reales. Yo lo dejé correr una vez en local y me cargué una rama de git, desde entonces solo en Docker.
6. Controlar el system prompt
Por defecto el SDK corre con el system prompt vacío, así que tu agente es una hoja en blanco. Dos formas de cambiarlo. O das tu propia cadena y lo controlas todo tú:
options: {
systemPrompt: "Eres especialista en Python. Escribe type hints, docstrings cortas, sin comentarios que expliquen lo obvio."
}
O tomas el comportamiento de Claude Code como base y solo le enganchas tu añadido:
options: {
systemPrompt: {
type: "preset",
preset: "claude_code",
append: "Respeta nuestra config de ESLint y no hagas commit directo en main."
}
}
El preset te da todo el comportamiento de Claude Code, convenciones de ficheros, prudencia con las acciones destructivas, todo. Para la mayoría de agentes de construcción, el preset más append es mejor punto de partida que un prompt propio vacío.
7. Poner tope al presupuesto y a los turnos
Un agente que piensa en bucle puede salir caro si se pierde. Siempre metes dos límites. maxTurns limita cuántas veces recorre el bucle, maxBudgetUsd para en un importe en dólares:
options: {
maxTurns: 12,
maxBudgetUsd: 0.50
}
En un job nocturno que recorre 30 ficheros, esas dos líneas son exactamente la diferencia entre "cuesta 40 céntimos" y "cuesta sin querer 12 dólares". Ponlas siempre, también mientras trasteas. Si quieres Opus con razonamiento largo para tareas duras, puedes definir con model y fallbackModel un respaldo más barato por si el modelo principal no está disponible.
8. Enganchar un servidor MCP
Aquí la cosa se pone interesante. Tu agente no solo puede usar las herramientas integradas, sino cualquier servidor MCP que le conectes. Con eso le das acceso a vuestra base de datos, a vuestra memoria, a vuestra API interna. Le pasas las configuraciones de servidor por mcpServers:
options: {
mcpServers: {
memory: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-memory"]
}
},
allowedTools: ["Read", "Grep", "mcp__memory__search"]
}
Importante: las herramientas de un servidor MCP se llaman mcp__<nombreservidor>__<nombreherramienta> y tienen que aparecer así de exactas en allowedTools, si no el agente no puede tocarlas. Si todavía no tienes un servidor MCP propio, constrúyelo antes, tenemos un playbook para eso (mira abajo). Con MCP el agente de código genérico se convierte en un agente que conoce vuestro stack.
9. Definir subagents por código
Para tareas más grandes no quieres un agente que lo haga todo, sino varios con papeles claros. El SDK te deja definir subagents directamente en el código, mediante la opción agents. Cada uno recibe su propia descripción y sus propias herramientas:
options: {
agents: {
reviewer: {
description: "Lee codigo y encuentra bugs, pero nunca escribe.",
tools: ["Read", "Grep", "Glob"]
},
fixer: {
description: "Arregla los bugs que ha reportado el reviewer.",
tools: ["Read", "Edit"]
}
}
}
Ese es el mismo patrón que conoces del CEO-worker, solo que vertido en código en vez de en ficheros markdown. El agente principal delega en los subagents, cada uno se queda en su carril. Mantener separados un reviewer que lee y un fixer que escribe evita que un agente analice mal y acto seguido arregle mal de una tacada.
10. Convertir el script en un job de verdad
El último paso convierte el juguete en un servicio. Necesitas tres cosas. Primero manejo de errores: el tipo result tiene un subtype que te dice si salió bien o si el agente chocó con un límite, eso hay que evaluarlo y no ignorarlo sin más. Segundo un AbortController por si quieres poder cancelar la tirada desde fuera. Tercero, para un job nocturno, un envoltorio fino que registre la salida y mande un aviso si hay errores. Si tu agente tiene que correr de forma periódica, combínalo con scheduled agents, y entonces tienes un agente que trabaja cada noche por su cuenta. Y si necesitas contexto de 1M porque tu agente lee bases de código grandes, lo activas con betas: ["context-1m-2025-08-07"] en las opciones.
Con eso tienes todo lo que necesitas: control de herramientas, permission mode, límite de presupuesto, conexión MCP y subagents. El resto es afinar para tu caso concreto.
Qué sigue
Cuando tengas el primer agente corriendo, lo que seguramente te falta es un servidor MCP propio que conozca tu stack. Para eso el siguiente paso es Primer servidor MCP en 90 minutos. Por el lado de los costes merece la pena Controles de coste de Claude Code para el daily driver, los principios valen igual para agentes del SDK. Y si tu agente tiene que correr solo, mira Scheduled agents con routines. Los fundamentos sobre el concepto de agente están en Nivel 5, qué es un agente, y el patrón CEO-worker del paso 9 se profundiza en Patrón CEO-worker.
Source
Las opciones y ejemplos usados aquí vienen de la documentación oficial del Agent SDK, https://docs.claude.com/en/api/agent-sdk/typescript y https://docs.claude.com/en/api/agent-sdk/overview. Versión de paquete 0.3.162 verificada por npm, npm view @anthropic-ai/claude-agent-sdk version. La variante de Python se llama claude_agent_sdk con query, ClaudeAgentOptions, AssistantMessage y ResultMessage.