Cómo construir un agente de IA y su MCP server paso a paso
Hace tres semanas un dev me escribió por Telegram con un MCP server funcionando. Lo había construido siguiendo un tutorial. Arrancaba, registraba sus tools, Claude Code lo detectaba. Todo perfecto.
Su pregunta era: "¿y ahora cómo hago que mi agente lo use?".
No supo responderse porque el tutorial terminaba justo ahí. Y ese es el problema con casi todo el material que hay sobre MCP: te enseñan a construir el enchufe, pero nunca el aparato que se enchufa. O al revés — te enseñan a montar un agente con tools locales y jamás mencionan por qué querrías sacarlas a un servidor.
Son dos mitades de la misma pieza. Y separadas no sirven de mucho.
Este post construye las dos. Un MCP server real en TypeScript, un agente que lo consume, y el puente entre ambos. Código verificado contra el SDK, no de memoria. Al final sabrás también cuándo no deberías montar un MCP server, que es una decisión que mucha gente se salta.
Las dos mitades: quién expone y quién consume
Un MCP server expone capacidades: tools, resources y prompts. No tiene inteligencia. No decide nada. Es un catálogo de funciones con un contrato estándar delante. Si no tienes claro el concepto de fondo, este post explica qué es Model Context Protocol antes de meterte en código.
Un agente es lo contrario: tiene el modelo, tiene el bucle, y decide qué llamar y cuándo. Lo que no tiene es acceso a tu mundo — a tu base de datos, a tu API interna, a tus postmortems.
MCP es el estándar que une las dos cosas sin que se conozcan entre sí. Escribes el server una vez, y lo consumen Claude Code, Claude Desktop, tu agente propio y el agente que escriba tu compañero el mes que viene.
Esa reutilización es todo el valor de MCP. Recuérdalo, porque en la última sección lo usaremos para decidir si te hace falta.
Vamos a construir un server sobre un caso que a cualquiera con sistemas en producción le suena: un histórico de incidencias. Datos internos, API que nadie más va a integrar, y consultas que un modelo puede hacer mucho mejor que un dashboard.
Paso 1: el MCP server en TypeScript
Construir un MCP server en TypeScript requiere tres piezas: el paquete @modelcontextprotocol/sdk con zod como peer dependency, una instancia de McpServer, y un transporte stdio. Este paso monta las tres sobre un caso real.
Primero, versiones. Y aquí hay que ser preciso porque el ecosistema está en transición.
La versión de producción hoy es la v1, en el paquete @modelcontextprotocol/sdk (última: 1.29.0). Es sobre la que vas a construir. Hay una v2 en beta que lo cambia bastante, y le dedico una sección entera más abajo — pero no construyas sobre ella todavía.
mkdir mcp-incidencias && cd mcp-incidencias
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx
zod es peer dependency obligatoria del SDK v1, no es opcional.
En tu package.json añade "type": "module", y en el tsconfig.json usa "module": "NodeNext" y "target": "ES2022". Sin eso los imports con extensión .js te van a dar guerra.
Ahora el servidor. Archivo src/server.ts:
import { McpServer } from 39;@modelcontextprotocol/sdk/server/mcp.js39;;
import { StdioServerTransport } from 39;@modelcontextprotocol/sdk/server/stdio.js39;;
import { z } from 39;zod39;;
type Severidad = 39;baja39; | 39;media39; | 39;alta39;;
interface Incidencia {
id: string;
servicio: string;
fecha: string;
severidad: Severidad;
titulo: string;
causaRaiz: string;
}
// En producción esto sale de tu base de datos.
const INCIDENCIAS: Incidencia[] = [
{
id: 39;INC-10139;,
servicio: 39;checkout-api39;,
fecha: 39;2026-05-1439;,
severidad: 39;alta39;,
titulo: 39;Timeouts masivos en pasarela de pago39;,
causaRaiz: 39;Pool de conexiones agotado tras un deploy sin migrar el límite.39;
},
{
id: 39;INC-11839;,
servicio: 39;checkout-api39;,
fecha: 39;2026-06-0239;,
severidad: 39;media39;,
titulo: 39;Latencia elevada en cálculo de impuestos39;,
causaRaiz: 39;Consulta N+1 introducida al añadir el desglose por región.39;
},
{
id: 39;INC-12439;,
servicio: 39;auth-service39;,
fecha: 39;2026-06-2139;,
severidad: 39;alta39;,
titulo: 39;Sesiones invalidadas de forma masiva39;,
causaRaiz: 39;Rotación de claves JWT desplegada sin periodo de solapamiento.39;
}
];
const server = new McpServer({ name: 39;incidencias39;, version: 39;1.0.039; });
Fíjate en los imports: llevan la extensión .js y la ruta interna del paquete (/server/mcp.js). No es @modelcontextprotocol/sdk a secas. Es el error más habitual al empezar.
Ahora registramos la primera tool:
const ORDEN: Record<Severidad, number> = { baja: 0, media: 1, alta: 2 };
server.registerTool(
39;buscar_incidencias39;,
{
title: 39;Buscar incidencias39;,
description:
39;Busca incidencias de producción de un servicio, filtrando por severidad mínima. 39; +
39;Úsala cuando necesites el histórico de fallos de un servicio concreto.39;,
inputSchema: {
servicio: z.string().describe(39;Nombre del servicio, por ejemplo: checkout-api39;),
severidadMinima: z.enum([39;baja39;, 39;media39;, 39;alta39;]).default(39;baja39;)
},
outputSchema: {
total: z.number(),
incidencias: z.array(
z.object({
id: z.string(),
fecha: z.string(),
severidad: z.string(),
titulo: z.string()
})
)
}
},
async ({ servicio, severidadMinima }) => {
const encontradas = INCIDENCIAS.filter(
(i) => i.servicio === servicio && ORDEN[i.severidad] >= ORDEN[severidadMinima]
).map(({ id, fecha, severidad, titulo }) => ({ id, fecha, severidad, titulo }));
const output = { total: encontradas.length, incidencias: encontradas };
return {
content: [{ type: 39;text39;, text: JSON.stringify(output, null, 2) }],
structuredContent: output
};
}
);
Un detalle que ahorra tardes: inputSchema acepta tanto la forma en crudo ({ servicio: z.string() }) como un z.object() completo. El SDK normaliza las dos por dentro y el JSON Schema que acaba llegando al modelo es idéntico. Uso la forma cruda porque es menos ruido, pero si vienes de otra librería y te sale envolver, no rompes nada.
Guárdalo, porque dentro de un momento vamos a ver otra librería donde esa flexibilidad no existe.
Lo segundo: la description no es documentación, es prompt. Es literalmente lo único que el modelo lee para decidir si usa esta tool. Una descripción vaga es una tool que nunca se llama, o que se llama cuando no toca. Escríbela pensando en el modelo, incluyendo cuándo usarla.
Segunda tool, con manejo de errores:
server.registerTool(
39;detalle_incidencia39;,
{
title: 39;Detalle de incidencia39;,
description: 39;Devuelve la causa raíz completa de una incidencia por su ID (formato INC-XXX).39;,
inputSchema: {
id: z.string().describe(39;Identificador, por ejemplo: INC-10139;)
}
},
async ({ id }) => {
const incidencia = INCIDENCIAS.find((i) => i.id === id);
if (!incidencia) {
return {
content: [{ type: 39;text39;, text: `No existe ninguna incidencia con ID ${id}.` }],
isError: true
};
}
return {
content: [
{
type: 39;text39;,
text: `${incidencia.id} — ${incidencia.titulo}\nServicio: ${incidencia.servicio}\nFecha: ${incidencia.fecha}\nSeveridad: ${incidencia.severidad}\nCausa raíz: ${incidencia.causaRaiz}`
}
]
};
}
);
isError: true en lugar de lanzar una excepción. La diferencia importa: con isError el modelo recibe el mensaje y puede corregirse solo — reintentar con otro ID, o decirle al usuario que no existe. Si lanzas, revientas la conexión y el agente se queda ciego.
Y el arranque:
const transport = new StdioServerTransport();
await server.connect(transport);
console.error(39;MCP server de incidencias escuchando en stdio39;);
console.error, nunca console.log. En transporte stdio, stdout es el canal JSON-RPC. Un solo console.log mete texto suelto en la tubería y rompe el protocolo con un error de parseo que no dice nada útil. Todo tu logging va a stderr.
Ya tienes la mitad de la pieza. Si quieres comprobar que funciona antes de seguir, no hace falta registrarlo en ningún cliente: npx @modelcontextprotocol/inspector npx tsx src/server.ts levanta MCP Inspector, la herramienta oficial, y te deja ver las tools registradas e invocarlas a mano desde el navegador.
Si además quieres usarlo desde Claude Code, tengo aparte las notas sobre registrar un MCP server en Claude Code — es el complemento natural de esta sección, no un camino alternativo.
Paso 2: el agente que consume las tools
El agente se construye con el Tool Runner del SDK de Anthropic (client.beta.messages.toolRunner), que ejecuta por ti el bucle completo: llama al modelo, ejecuta la tool que pida, le devuelve el resultado, y repite hasta obtener una respuesta final.
Aquí hay una confusión que veo constantemente y conviene despejarla antes de escribir una línea, porque son dos productos distintos de Anthropic:
- Tool Runner (
client.beta.messages.toolRunner, dentro del SDK normal@anthropic-ai/sdk): automatiza el bucle sobre las tools que tú defines. Sin tools integradas, sin sandbox. Tú pones todo. - Claude Agent SDK (
@anthropic-ai/claude-agent-sdk): es Claude Code empaquetado como librería, con tools integradas de serie — leer y escribir ficheros, bash, grep.
No son versiones distintas de lo mismo. Para este caso queremos el Tool Runner, porque lo que nos interesa es controlar exactamente qué tools existen.
npm install @anthropic-ai/sdk
Un agente mínimo con una tool local:
import Anthropic from 39;@anthropic-ai/sdk39;;
import { betaZodTool } from 39;@anthropic-ai/sdk/helpers/beta/zod39;;
import { z } from 39;zod39;;
const client = new Anthropic(); // lee ANTHROPIC_API_KEY del entorno
const buscarIncidencias = betaZodTool({
name: 39;buscar_incidencias39;,
description: 39;Busca incidencias de producción de un servicio por severidad mínima.39;,
inputSchema: z.object({
servicio: z.string().describe(39;Nombre del servicio, por ejemplo: checkout-api39;),
severidadMinima: z.enum([39;baja39;, 39;media39;, 39;alta39;]).default(39;baja39;)
}),
run: async (input) => {
// aquí llamarías a tu API real
return JSON.stringify({ servicio: input.servicio, total: 0, incidencias: [] });
}
});
const respuesta = await client.beta.messages.toolRunner({
model: 39;claude-opus-4-839;,
max_tokens: 16000,
thinking: { type: 39;adaptive39; },
messages: [
{
role: 39;user39;,
content: 39;¿Qué incidencias graves ha tenido checkout-api? Resume el patrón que veas.39;
}
],
tools: [buscarIncidencias]
});
console.log(respuesta.content);
Fíjate en la diferencia con el server: en betaZodTool el inputSchema tiene que ser un z.object() completo. Aquí no hay normalización que te salve — pasarle la forma en crudo no funciona.
Las tres convenciones de schema que se confunden entre sí
El mismo concepto cambia de formato según la librería. Es la causa más frecuente de tools que se registran pero nunca se llaman bien:
| Librería y función | Propiedad | Formato esperado |
|---|---|---|
MCP SDK v1 — registerTool |
inputSchema |
Forma cruda o z.object(); el SDK normaliza las dos |
Anthropic SDK — betaZodTool |
inputSchema |
z.object() completo, obligatorio |
Anthropic SDK — betaTool |
inputSchema |
JSON Schema plano (el que devuelve listTools()) |
Las tres reciben inputSchema en camelCase. El input_schema en snake_case que quizá tengas visto es lo que viaja por la red hacia la API, no lo que le pasas al helper. Escribir snake_case en cualquiera de los tres revienta con un TypeError.
Tres cosas más sobre los parámetros, que están cambiadas respecto a lo que quizá tengas memorizado:
- El modelo es
claude-opus-4-8. Sin sufijo de fecha. thinkingva con{ type: 'adaptive' }.budget_tokensestá eliminado en Opus 4.8 y devuelve un 400.temperature,top_pytop_krechazan cualquier valor que no sea el por defecto y devuelven 400. Si arrastras untemperature: 0de un proyecto viejo, esa llamada falla. Se dirige el comportamiento por prompt, no por sampling.
max_tokens alrededor de 16000 para peticiones normales, hasta ~64000 si haces streaming.
El Tool Runner ejecuta el bucle completo por ti: llama al modelo, si pide una tool la ejecuta, le devuelve el resultado, y repite hasta que el modelo da una respuesta final. Ese bucle es el corazón de cualquier agente — y si quieres entender por qué la calidad del bucle importa más que el modelo que metas dentro, lo desarrollo aquí. Para los fundamentos de la API, este crash course te cubre.
Paso 3: conectar las dos mitades
Conectar el agente con el MCP server consiste en levantar un cliente MCP, pedirle sus tools con listTools() y traducirlas al formato del Tool Runner con betaTool. Así el agente ejecuta las tools reales del server en vez de copias locales.
Ahora lo que casi nadie enseña. El agente del paso anterior tiene la tool duplicada en local. Queremos que consuma las tools reales del MCP server, sin reescribirlas.
Para eso montamos un cliente MCP, le preguntamos qué tools tiene, y las traducimos al formato del Tool Runner:
import Anthropic from 39;@anthropic-ai/sdk39;;
import { betaTool } from 39;@anthropic-ai/sdk/helpers/beta/json-schema39;;
import { Client } from 39;@modelcontextprotocol/sdk/client/index.js39;;
import { StdioClientTransport } from 39;@modelcontextprotocol/sdk/client/stdio.js39;;
const transport = new StdioClientTransport({
command: 39;npx39;,
args: [39;tsx39;, 39;src/server.ts39;]
});
const mcp = new Client({ name: 39;agente-incidencias39;, version: 39;1.0.039; });
await mcp.connect(transport);
// 1. Descubrimos las tools que expone el server
const { tools } = await mcp.listTools();
// 2. Las convertimos en tools ejecutables para el Tool Runner
const puente = tools.map((tool) =>
betaTool({
name: tool.name,
description: tool.description ?? 39;39;,
inputSchema: tool.inputSchema as any,
run: async (input) => {
const resultado = await mcp.callTool({
name: tool.name,
arguments: input as Record<string, unknown>
});
return JSON.stringify(resultado.content);
}
})
);
// 3. El agente ya usa las tools reales del server
const respuesta = await new Anthropic().beta.messages.toolRunner({
model: 39;claude-opus-4-839;,
max_tokens: 16000,
thinking: { type: 39;adaptive39; },
messages: [
{
role: 39;user39;,
content:
39;Revisa las incidencias graves de checkout-api, mira el detalle de cada una 39; +
39;y dime si hay un patrón común en las causas raíz.39;
}
],
tools: puente
});
console.log(respuesta.content);
await mcp.close();
Eso es el circuito completo. Aquí usamos betaTool en lugar de betaZodTool porque listTools() devuelve JSON Schema, no Zod. Encaja directo: le pasas el inputSchema tal cual llega del server.
Y ojo con el detalle que más despista de todo el post: los helpers reciben inputSchema en camelCase, pero lo que viaja a la API es input_schema en snake_case. Si escribes tools a mano contra la API cruda usas snake_case; con los helpers, siempre camelCase. Escribir input_schema: dentro de betaTool no da un error de validación bonito — revienta con un TypeError antes de tocar la red.
Cuando entiendas el mecanismo, el SDK ya trae ese puente hecho:
import { mcpTools } from 39;@anthropic-ai/sdk/helpers/beta/mcp39;;
const puente = mcpTools(tools, mcp);
Merece la pena haber escrito el map a mano una vez: cuando el helper falle, sabrás qué está haciendo por dentro.
Lo potente es que ese map no sabe nada de tus tools. Añade una tercera tool al server y el agente la tiene disponible en el siguiente arranque, sin tocar el código del agente. Ahí es donde MCP paga lo que cuesta.
Al ejecutarlo verás al agente encadenar solo: llama a buscar_incidencias, recibe dos IDs, llama a detalle_incidencia con cada uno, y razona sobre las causas raíz. Nadie le dijo el orden.
La otra vía: el conector MCP remoto
Si en vez de stdio despliegas el server sobre HTTP, la API de Claude puede conectarse a él directamente, sin cliente MCP en tu código:
const message = await client.beta.messages.create({
model: 39;claude-opus-4-839;,
max_tokens: 16000,
betas: [39;mcp-client-2025-11-2039;],
mcp_servers: [
{
type: 39;url39;,
url: 39;https://incidencias.tudominio.com/mcp',
name: 39;incidencias39;
}
],
tools: [{ type: 39;mcp_toolset39;, mcp_server_name: 39;incidencias39; }],
messages: [{ role: 39;user39;, content: 39;¿Qué incidencias graves tuvo checkout-api?39; }]
});
El conector MCP remoto exige declarar mcp_servers y tools a la vez. Declarar solo mcp_servers hace que la petición se rechace con un error de validación, aunque parezca redundante — ya has dicho dónde está el server, ¿para qué repetirlo? Cada server declarado en mcp_servers necesita su entrada { type: 'mcp_toolset', mcp_server_name: '<nombre>' } dentro de tools, y el mcp_server_name debe coincidir exactamente con el name del server.
Ojo también: esta vía requiere un server con URL pública. Un server stdio no sirve aquí, para eso está el puente de arriba. La documentación del conector MCP de la API de Anthropic detalla el resto de campos disponibles.
MCP v2 y la spec 2026-07-28: qué cambia y por qué no tienes que migrar
El 28 de julio de 2026 salen la spec MCP 2026-07-28 y las SDK estables de la v2. Vas a ver posts en tono de urgencia. Ignóralos.
La documentación oficial es explícita en dos puntos. Sobre las versiones, la v1.x sigue siendo "the supported release for production" y mantiene bugfixes y parches de seguridad al menos 6 meses después de que v2 sea estable. Y sobre el protocolo, la guía de la revisión lo cierra: "Nothing in v2 puts a 2026-07-28 byte on the wire by default" — hablar la revisión nueva es siempre un opt-in explícito. Migrar a v2 es opcional y va separado de la fecha del protocolo.
Puedes seguir las dos fuentes de primera mano: la especificación del protocolo y el SDK de TypeScript en GitHub.
El servidor que acabas de construir sigue funcionando. No hay nada que correr a arreglar.
Dicho eso, la v2 no es un cambio cosmético y merece que sepas qué trae, porque cambia decisiones de arquitectura:
Se parte el paquete. El monolítico @modelcontextprotocol/sdk desaparece en favor de @modelcontextprotocol/server, @modelcontextprotocol/client y @modelcontextprotocol/core. La v2 no sale como versión nueva del paquete viejo: son paquetes distintos. Por eso no hay riesgo de que te llegue sola en un npm update.
Protocolo stateless. Cuando activas la revisión nueva, desaparecen el handshake initialize y la gestión de sesión. Traducido a infraestructura: escalas con un round-robin normal, sin sticky sessions. Si has sufrido balanceo con sesiones MCP, esta es la razón para migrar. Ojo: en la v2 el modo de 2025 sigue siendo el por defecto; la revisión 2026-07-28 se activa explícitamente.
Multi Round-Trip Requests. Una tool puede pedir input al usuario a mitad de llamada, sin mantener un stream abierto — con inputRequired() y acceptedContent(). Confirmaciones y flujos de autorización dejan de ser un apaño.
Cabeceras enrutables Mcp-Method y Mcp-Name, para que gateways y rate limiters enruten sin parsear el body. Si expones MCP detrás de un API gateway, esto te ahorra trabajo.
Bring-your-own-schema. inputSchema y outputSchema aceptan cualquier Standard Schema: Zod v4 y ArkType directos, Valibot vía adaptador, o JSON Schema plano con fromJsonSchema. Se acabó estar atado a Zod. El registro pasa a server.registerTool(name, config, handler).
Si vas a experimentar con la beta, el consejo oficial es fijar versiones exactas y poner cotas superiores en las dependencias, para no comerte un major por sorpresa.
Mi recomendación: construye en v1, lee la guía de v2, y migra cuando tengas un motivo concreto — escalado horizontal o flujos que necesiten input a media llamada. No antes.
Cuándo NO necesitas un MCP server
Esta sección te puede ahorrar una semana.
Si tu agente va a usar solo tus propias tools, dentro de tu propio proceso, no montes un MCP server. El Tool Runner con tools locales (betaZodTool y punto) es más simple, más rápido de depurar y no añade un proceso extra ni serialización por medio. Todo el paso 1 de este post sobra en ese escenario.
MCP gana cuando aparece la palabra reutilización:
- Quieres las mismas tools en Claude Code, en Claude Desktop y en tu agente.
- Varios equipos van a consumir la misma capacidad y no quieres que cada uno la reimplemente.
- Quieres una frontera de permisos clara: el server decide qué se puede hacer, el agente solo pide.
- Necesitas versionar y desplegar las capacidades por separado del agente.
Si no marcas ninguna, tu MCP server es una capa de indirección que no compra nada.
Y una consecuencia que se ve poco: en cuanto varios clientes consumen tus tools, las descripciones dejan de ser tuyas y pasan a ser una API pública. Cambiar una description puede romper el comportamiento del agente de otro equipo sin que nada falle en rojo. Trátalas con el mismo cuidado que un contrato.
Qué hacer con esto hoy
Coge el código del paso 1, cámbiale el array INCIDENCIAS por una consulta real a tu base de datos, y ejecuta el puente del paso 3. En una tarde tienes un agente hablando con tus datos internos.
Y cuando lo tengas funcionando, la parte difícil no será el código. Será decidir qué tools expones y cómo las describes — porque ahí es donde un agente pasa de demo a herramienta que usas todos los días.
Ese salto, el de convertir una prueba de concepto en producto, es justo lo que trabajamos en el curso Construye con IA: De la Idea al Producto con Claude Code, con este mismo flujo de specs, tools y agentes. Si prefieres el método antes que la herramienta, en el libro Spec-Driven Development está el sistema completo para definir qué construyes antes de escribir la primera línea.
Y si quieres los proyectos completos y las versiones de esto que corren en producción, están en Dominicode Labs.
FAQ
¿Puedo usar el mismo MCP server con Claude Code y con mi agente propio a la vez?
Sí, y es exactamente para lo que sirve MCP. El server no sabe quién le llama. Claude Code lo lanza como proceso hijo por stdio, y tu agente hace lo mismo con StdioClientTransport. Mismo binario, dos consumidores, cero código duplicado.
¿Tengo que migrar mi server a la v2 el 28 de julio?
No. La v2 llega en paquetes nuevos (@modelcontextprotocol/server, /client y /core), no como actualización del paquete actual, así que no te va a llegar por un npm update. La v1.x sigue siendo la versión soportada para producción y mantiene bugfixes y parches de seguridad al menos 6 meses tras la salida de v2. Además, hablar la revisión 2026-07-28 es siempre un opt-in explícito: nada la pone en el cable por defecto.
¿Cuál es la diferencia real entre el Tool Runner y el Claude Agent SDK?
El Tool Runner automatiza el bucle sobre tools que defines tú, y nada más: sin tools integradas, sin sandbox. El Claude Agent SDK es Claude Code como librería, y viene con tools de ficheros, bash y grep de serie. Si quieres control total sobre qué puede hacer el agente, Tool Runner. Si quieres un agente que opere sobre un repositorio desde el minuto uno, Agent SDK.
Mi server arranca pero el cliente da error de parseo JSON. ¿Qué pasa?
Casi seguro tienes un console.log en algún sitio. En stdio, stdout es el canal JSON-RPC exclusivo del protocolo. Cualquier texto que escribas ahí corrompe el flujo. Cambia todos los console.log por console.error y vuelve a probar.
¿Por qué mi tool aparece registrada pero el modelo nunca la llama?
Dos causas, por frecuencia. La primera es la description: si es vaga, el modelo no sabe cuándo aplica. Escríbela diciendo explícitamente en qué situación usarla. La segunda es que el schema no describa bien los campos — añade .describe() a cada uno, porque el modelo los lee para saber con qué rellenarlos.
¿Cómo pruebo mi MCP server sin registrarlo en un cliente?
Con MCP Inspector, la herramienta oficial: npx @modelcontextprotocol/inspector npx tsx src/server.ts. Abre una interfaz web donde ves las tools registradas, su schema, y puedes invocarlas con argumentos a mano. Es la forma más rápida de saber si el fallo está en el server o en cómo lo consume el cliente.
¿Puedo usar temperature para que el agente sea más determinista?
No con Opus 4.8. temperature, top_p y top_k rechazan cualquier valor que no sea el por defecto y devuelven un 400. Tampoco existe ya budget_tokens para thinking — se usa thinking: { type: 'adaptive' }. Si migras código de modelos anteriores, revisa esos parámetros primero. El comportamiento se dirige por prompt.
¿El conector MCP de la API sirve para un server local por stdio?
No. mcp_servers con type: 'url' necesita un endpoint HTTP accesible desde la API de Anthropic. Para un server local usas el puente del paso 3: cliente MCP por stdio y las tools traducidas al Tool Runner.
Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.
Más contenido sobre agentes e IA aplicada al desarrollo en el canal de YouTube de Dominicode. Y si estás empezando con agentes, esta guía es el punto de partida.
