MCP pour fournir des capacités supplémentaires à l'Agent IA
Fait partie de la série Agents IA et serveur MCP au service du web agentique
Nous avons construit notre premier Agent IA avec un outil d'addition. Dans cet article, nous allons déplacer cet outil dans un serveur MCP, où il pourra être découvert et utilisé grâce à un protocole standard.
Petit rappel sur MCP : MCP est un standard open-source qui connecte les applications IA à des systèmes externes. Un serveur MCP fournit des outils, tandis qu'un client MCP se connecte à ce serveur et appelle ses outils pour le compte de l'Agent IA. Dans cette série, notre application IA contient l'Agent et son client MCP ; le serveur MCP expose les capacités dont l'Agent a besoin. Visuellement, cela ressemble à ceci :

Vous vous demandez peut-être pourquoi nous avons besoin d'un serveur MCP. Nous n'en avons pas strictement besoin pour ce petit outil d'addition : un outil direct est plus simple lorsqu'une capacité n'appartient qu'à une seule application étroitement couplée. MCP devient utile lorsqu'une capacité doit être partagée, déployée indépendamment ou consommée par des clients compatibles.
- Prendre en charge des clients compatibles : en fournissant MCP, vous permettez aux applications IA et aux outils de développement qui prennent en charge le protocole d'utiliser vos capacités. Par exemple, un serveur MCP pour une bibliothèque de composants peut rendre sa documentation et ses outils disponibles dans un éditeur de code.
- Utiliser des serveurs MCP externes : votre Agent peut aussi se connecter à un serveur MCP que vous n'avez pas créé afin de s'intégrer à un système existant ou à une capacité tierce.
- Découpler les capacités : l'Agent n'a besoin de connaître que le nom, la description, les entrées et les sorties d'un outil. Le serveur MCP possède son implémentation et peut évoluer indépendamment.
Dans cette série, MCP établit une frontière claire entre l'Agent et les capacités qu'il peut utiliser.
Construire le serveur MCP
Dans notre application Nitro, nous pouvons créer une nouvelle route pour le serveur MCP.
mkdir -p server/routes
touch server/routes/mcp.tsEnsuite, nous devons installer le SDK MCP :
pnpm add @modelcontextprotocol/sdk@^1.29.0C'est le SDK MCP officiel pour construire des Model Context Protocols en TypeScript.
Maintenant, nous pouvons créer notre serveur MCP dans le fichier server/routes/mcp.ts :
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { defineEventHandler } from 'h3'
export default defineEventHandler(async (event) => {
const server = new McpServer({
name: 'ai-agent',
version: '1.0.0'
})
})Nous avons maintenant un objet serveur MCP, mais il ne peut pas encore recevoir de requêtes. MCP sépare le serveur, qui définit les capacités et les outils du protocole, du transport, qui achemine les requêtes et les réponses. Dans notre cas, la route Nitro hébergera un transport Streamable HTTP afin qu'un client MCP puisse atteindre le serveur via HTTP.
Note
Streamable HTTP est utile ici, car il permet à un serveur MCP hébergé à distance de communiquer à travers des requêtes et réponses HTTP classiques.
Heureusement, le SDK MCP fournit tout ce dont nous avons besoin pour ajouter une couche de transport HTTP.
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'
import { defineEventHandler, readBody } from 'h3'
export default defineEventHandler(async (event) => {
const server = new McpServer({
name: 'ai-agent',
version: '1.0.0'
})
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined
})
event.node.res.on('close', () => {
transport.close()
server.close()
})
await server.connect(transport)
const body = await readBody(event)
await transport.handleRequest(event.node.req, event.node.res, body)
})Avec server.connect(transport), nous attachons le serveur au transport HTTP. Avec transport.handleRequest(event.node.req, event.node.res, body), nous transmettons la requête entrante à ce transport, qui renvoie ensuite la réponse au client. Cet exemple crée un transport sans état pour chaque requête, donc sessionIdGenerator: undefined désactive les identifiants de session. Lorsque la réponse se termine ou est interrompue prématurément, nous fermons le transport et le serveur pour libérer leurs ressources.
Le corps de la requête est important car les outils peuvent avoir des paramètres d'entrée.
Avec cette configuration, nous pouvons maintenant essayer le MCP.
Essayer le MCP
Pour essayer le MCP, nous pouvons utiliser l'Inspector MCP officiel :
npx @modelcontextprotocol/inspector@latestNote
Utilisez l'Inspector pour vérifier un serveur MCP avant de le connecter à une application IA. Un modèle peut décider de ne pas appeler un outil donné, tandis que l'Inspector permet de tester directement le protocole et les outils.
Ensuite, nous pouvons saisir l'URL du MCP et ping le serveur pour vérifier qu'il fonctionne.
Le serveur est maintenant accessible via son transport HTTP.
Ajouter un outil
Maintenant que nous avons un serveur MCP opérationnel, nous pouvons déplacer notre outil d'addition de l'Agent IA vers le serveur MCP.
Dans le fichier server/api/chat.ts, retirez tool de l'import de l'AI SDK, supprimez l'import Zod et effacez l'enregistrement de l'outil d'addition :
import { createOpenAI } from '@ai-sdk/openai'
import { convertToModelMessages, stepCountIs, streamText } from 'ai'
import { defineEventHandler, defineLazyEventHandler, readBody } from 'h3'
import { useRuntimeConfig } from 'nitropack/runtime'
import { z } from 'zod'
export default defineLazyEventHandler(() => {
const runtimeConfig = useRuntimeConfig()
const model = createOpenAI({
apiKey: runtimeConfig.openAiApiKey,
})
return defineEventHandler(async (event) => {
const { messages } = await readBody(event)
return streamText({
model: model('gpt-5-nano'),
system: `You are a helpful assistant. You can use the tool to add two numbers together.`,
tools: {
addition: tool({
description: 'Adds two numbers',
inputSchema: z.object({
a: z.number().describe('The first number'),
b: z.number().describe('The second number'),
}),
execute: ({ a, b }) => ({
a,
b,
result: a + b
}),
}),
},
stopWhen: stepCountIs(2),
messages: convertToModelMessages(messages),
}).toUIMessageStreamResponse()
})
})Dans le fichier server/routes/mcp.ts, enregistrez l'outil d'addition auprès du serveur MCP.
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { defineEventHandler } from 'h3'
import { z } from 'zod'
export default defineEventHandler(async (event) => {
const server = new McpServer({
name: 'ai-agent',
version: '1.0.0'
})
server.tool(
'addition',
'Adds two numbers',
{
a: z.number().describe('The first number'),
b: z.number().describe('The second number')
},
async (params) => {
return {
content: [
{ type: 'text', text: String(params.a + params.b) }
]
}
}
)
// ...
})L'enregistrement de l'outil est volontairement proche de celui de l'outil direct utilisé dans la première partie. Son implémentation et son schéma d'entrée ont été déplacés vers le serveur MCP, tandis que sa sortie suit maintenant le format standardisé content de MCP. L'Agent n'est pas encore connecté à ce serveur ; nous le ferons dans l'article suivant.
Nous pouvons maintenant utiliser manuellement notre outil d'addition :
Nous avons maintenant un serveur MCP fonctionnel qui expose l'outil d'addition. Dans l'article suivant, nous donnerons à notre Agent IA un client MCP afin qu'il puisse découvrir et utiliser cet outil.
Merci de me lire ! Je m'appelle Estéban, et j'adore écrire sur le développement web et le parcours humain qui l'entoure.
Je code depuis plusieurs années maintenant, et j'apprends encore de nouvelles choses chaque jour. J'aime partager mes connaissances avec les autres, car j'aurais aimé avoir accès à des ressources aussi claires et complètes lorsque j'ai commencé à apprendre la programmation.
Si vous avez des questions ou souhaitez discuter, n'hésitez pas à commenter ci-dessous ou à me contacter sur Bluesky, X, et LinkedIn.
J'espère que vous avez apprécié cet article et appris quelque chose de nouveau. N'hésitez pas à le partager avec vos amis ou sur les réseaux sociaux, et laissez un commentaire ou une réaction ci-dessous, cela me ferait très plaisir ! Si vous souhaitez soutenir mon travail, vous pouvez me sponsoriser sur GitHub !
Discussions
Ajouter un commentaire
Vous devez être connecté pour accéder à cette fonctionnalité.