Aller au contenu
astorlm
Langue: Français
← Carte

Niveau 10

MCP

Jusqu'ici, chaque outil était une fonction que vous écriviez dans votre propre agent. MCP est une prise standard : n'importe quel programme peut proposer des outils par elle, et n'importe quel agent peut les utiliser.
1/19 Plis du bandonéon :
  • user
  • assistant
  • tool_result
Dream Land. Deux serveurs MCP attendent devant leurs portes : weather et maps, chacun un programme à part. Kirby est le client MCP à l'intérieur de l'agent, et il s'adapte à tous les serveurs avec la même bouche.

EventBus

Le problème

Chaque service que votre agent devrait atteindre (un agenda, un dépôt, une base de données, un navigateur) veut dire écrire un outil à la main : son schéma, son code, sa gestion d'erreurs. Puis l'agent suivant, ou l'app suivante, réécrit le même outil. Et quand le service change, chaque copie casse de son côté.

La solution

Le Model Context Protocol (MCP) sépare les deux côtés. Un serveur MCP est un programme qui propose des outils ; celui qui construit le service l'écrit une fois. Un client MCP vit dans l'agent et parle le protocole. Ils peuvent tourner sur la même machine, le serveur en processus enfant qui parle par stdin et stdout, ou loin l'un de l'autre, par HTTP. La conversation a toujours les trois mêmes étapes :

  • initialize

    La poignée de main : le client et le serveur disent qui ils sont et quelle version du protocole ils parlent.

  • tools/list

    Le serveur décrit ses outils : nom, description et schéma d'entrée, les trois mêmes choses qu'au niveau 3.

  • tools/call

    Chaque fois que le modèle demande l'un d'eux, le client envoie son nom et ses arguments, et reçoit le résultat.

Les outils que vous obtenez sont des outils ordinaires. Ils rejoignent la liste envoyée avec chaque requête, la boucle les exécute comme les autres et le modèle ne peut pas savoir d'où ils viennent. Et comme la prise est standard, le même serveur fonctionne dans Claude Code, Codex, Cursor, VS Code ou votre propre agent.

Les personnages

Les mêmes personnages que d'habitude, à Dream Land, avec un nouvel ami.

Kirby le client MCP
Une partie de votre agent. Une bouche qui va à tous les serveurs, et copie ce que chacun sait faire.
Les ennemis serveurs MCP
Des programmes à part, chacun à sa porte. Ils y retournent après que Kirby les a copiés : ils continuent de tourner.
Les pouvoirs tools/list
PARASOL et WHEEL : les outils que chaque serveur a décrits, désormais dans la barre d'état que lit le modèle.
Les câbles le protocole
Le même genre de prise pour tous les serveurs. Un tools/call descend par l'un, et son résultat remonte.
Astor la boucle
Fait tourner la boucle comme d'habitude, et passe chaque appel MCP à Kirby.
L'Oracle le modèle
Choisit dans la boîte à outils par nom et description, MCP ou non.

Le code

Avec astorlm : mountMcpServer() se connecte, liste les outils et les adapte, nommés <serveur>__<outil> pour que deux serveurs n'entrent pas en collision. Ses tools entrent dans l'agent comme les autres, et close() raccroche.

À partir de zéro : un client stdio, c'est un processus enfant et du JSON-RPC, un objet JSON par ligne : la poignée de main, tools/list, et une fonction par outil qui envoie tools/call. Les outils entrent ensuite dans la boucle du niveau 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()])
}

Points de vigilance

  • Chaque outil voyage dans chaque requête. Un serveur à quarante outils ajoute quarante schémas à chaque tour, et une longue liste rend le bon choix plus difficile. Ne montez que les serveurs nécessaires, et ne transmettez que les outils utilisés : weather.tools.filter(…).
  • Un serveur est du code que vous exécutez. Un serveur stdio tourne avec vos permissions, sur votre machine. Traitez-le comme une dépendance : installez-le depuis une source fiable et figez sa version.
  • Les descriptions sont aussi des instructions. Le modèle lit chaque description d'outil comme si vous l'aviez écrite, et chaque résultat comme des données qui peuvent porter des ordres. Un serveur que vous ne contrôlez pas peut piloter votre agent par l'un ou l'autre chemin (niveau 18).
  • Les serveurs distants demandent des identifiants. En HTTP, passez un token dans les headers, limité à ce dont l'agent a besoin, jamais votre propre clé toute-puissante.
  • Fermez ce que vous ouvrez. Un serveur stdio vit aussi longtemps que sa connexion. Fermez-le quand l'agent a fini, sinon il continue de tourner en arrière-plan.