Saltar al contenido
astorlm
Idioma: Español
← Mapa

Nivel 10

MCP

Hasta ahora cada herramienta era una función que escribías dentro de tu propio agente. MCP es un enchufe estándar: cualquier programa puede ofrecer herramientas a través de él, y cualquier agente puede usarlas.
1/19 Pliegues del bandoneón:
  • user
  • assistant
  • tool_result
Dream Land. Dos servidores MCP esperan frente a sus puertas: weather y maps, cada uno un programa aparte. Kirby es el cliente MCP dentro del agente, y le sirve a cualquier servidor con la misma boca.

EventBus

El problema

Cada servicio al que tu agente debería llegar (un calendario, un repositorio, una base de datos, un navegador) significa escribir una herramienta a mano: su esquema, su código, su manejo de errores. Después el próximo agente, o la próxima app, vuelve a escribir la misma herramienta. Y cuando el servicio cambia, cada copia se rompe por su lado.

La solución

El Model Context Protocol (MCP) separa los dos lados. Un servidor MCP es un programa que ofrece herramientas; lo escribe una vez quien construye el servicio. Un cliente MCP vive dentro del agente y habla el protocolo. Pueden correr en la misma máquina, con el servidor como proceso hijo que habla por stdin y stdout, o lejos, por HTTP. La conversación siempre tiene los mismos tres pasos:

  • initialize

    El saludo: el cliente y el servidor dicen quiénes son y qué versión del protocolo hablan.

  • tools/list

    El servidor describe sus herramientas: nombre, descripción y esquema de entrada, las mismas tres cosas del nivel 3.

  • tools/call

    Cada vez que el modelo pide una de ellas, el cliente manda su nombre y sus argumentos, y recibe el resultado.

Las herramientas que recibes son herramientas comunes. Se suman a la lista que va con cada pedido, el bucle las ejecuta como a cualquier otra y el modelo no puede saber de dónde vienen. Y como el enchufe es estándar, el mismo servidor funciona en Claude Code, Codex, Cursor, VS Code o tu propio agente.

El elenco

El mismo elenco de siempre, en Dream Land, con un amigo nuevo.

Kirby el cliente MCP
Parte de tu agente. Una boca que le sirve a cualquier servidor, y copia lo que cada uno sabe hacer.
Los enemigos servidores MCP
Programas aparte, cada uno en su puerta. Vuelven ahí después de que Kirby los copia: siguen funcionando.
Las habilidades tools/list
PARASOL y WHEEL: las herramientas que describió cada servidor, ahora en la barra de estado que lee el modelo.
Los cables el protocolo
El mismo tipo de enchufe para todos los servidores. Un tools/call baja por uno y su resultado vuelve.
Astor el bucle
Corre el bucle como siempre, y le pasa cada llamada MCP a Kirby.
El Oráculo el modelo
Elige de la caja de herramientas por nombre y descripción, sea MCP o no.

El código

Con astorlm: mountMcpServer() se conecta, lista las herramientas y las adapta, con el nombre <servidor>__<herramienta> para que dos servidores no choquen. Sus tools entran al agente como cualquier otra, y close() corta la conexión.

Desde cero: un cliente stdio es un proceso hijo y JSON-RPC, un objeto JSON por línea: el saludo, tools/list y una función por herramienta que manda tools/call. Después las herramientas entran al bucle del nivel 2.

import { OpenAIProvider, createLocalAgent, mountMcpServer } from 'astorlm'

// 1. Mount each MCP server: connect, ask for its tools (tools/list), adapt them.
//    Each one is a separate program; nobody wrote its schemas in your code.
const weather = await mountMcpServer({
  name: 'weather', // becomes the prefix: weather__forecast, weather__alerts
  transport: { type: 'stdio', command: 'npx', args: ['-y', 'dreamland-weather-mcp'] }, // runs it as a child process
})

const maps = await mountMcpServer({
  name: 'maps',
  transport: { type: 'http', url: 'https://maps.dreamland.example/mcp' }, // or a server that's already running
})

const agent = await createLocalAgent({
  // Any OpenAI-compatible endpoint: OpenAI, Ollama, LM Studio, vLLM, a proxy…
  provider: new OpenAIProvider({
    baseURL: 'http://localhost:11434/v1', // e.g. Ollama's default address
    model: 'your-model', // e.g. 'llama3.1', 'gpt-4o-mini'
    apiKey: 'YOUR_API_KEY', // local servers usually ignore it
  }),
  // 2. MCP tools are tools: mix them with your own, or keep only the ones you need.
  tools: [...weather.tools, ...maps.tools],
  maxTurns: 10,
})

agent.on('tool-start', ({ name }) => console.log('→', name)) // maps__route, then weather__forecast

try {
  await agent.run('Picnic at the Fountain of Dreams tomorrow. How do I get there from Cappy Town, and will it rain?')
} finally {
  // 3. Hang up when you're done: a stdio server is a process of yours.
  await Promise.all([weather.close(), maps.close()])
}

Qué vigilar

  • Cada herramienta viaja en cada pedido. Un servidor con cuarenta herramientas suma cuarenta esquemas a cada turno, y una lista larga hace más difícil elegir la correcta. Monta solo los servidores que necesitas, y pasa solo las herramientas que usas: weather.tools.filter(…).
  • Un servidor es código que ejecutas. Un servidor stdio corre con tus permisos, en tu máquina. Trátalo como una dependencia: instálalo de una fuente en la que confíes y fija su versión.
  • Las descripciones también son instrucciones. El modelo lee cada descripción de herramienta como si la hubieras escrito tú, y cada resultado como datos que pueden traer órdenes. Un servidor que no controlas puede manejar a tu agente por cualquiera de los dos caminos (nivel 18).
  • Los servidores remotos necesitan credenciales. Por HTTP, pasa un token en los headers, limitado a lo que el agente necesita, nunca tu propia clave todopoderosa.
  • Cierra lo que abres. Un servidor stdio vive mientras dura su conexión. Ciérralo cuando el agente termine, o sigue corriendo de fondo.