Présentation : les trois primitives du protocole MCP
Dans le premier article de cette série nous avons présenté le Protocole de contexte de modèle (MCP) et son architecture Hôte/Client/Serveur. Il est désormais temps de les analyser en détail trois primitives qu'un serveur MCP peut exposer : Outils, Ressources e Invites.
Chaque primitive joue un rôle distinct dans l’interaction entre l’IA et le monde extérieur. Comprendre les différences, les cas d'utilisation et la structure interne de chacun sont essentiels à la conception de serveurs MCP efficaces et bien structuré. Dans cet article nous verrons la théorie, les schémas de validation avec Zod, Charges utiles JSON-RPC et gestionnaires TypeScript, analysant des exemples concrets du projet Tech-MCP.
Ce que Vous Apprendrez dans Cet Article
- La différence entre les outils, les ressources et les invites : rôle, contrôle et cas d'utilisation
- Comment définir un outil avec validation Zod et gestionnaire asynchrone
- Comment exposer des ressources avec un modèle d'URI et des données en lecture seule
- Comment créer des invites paramétrées et réutilisables
- Le format des charges utiles JSON-RPC pour chaque primitive
- Le cycle de vie d'une session MCP de la découverte à la fermeture
- Meilleures pratiques pour les descriptions d'outils et la convention de dénomination
Comparaison des trois primitifs
Avant d'entrer dans le détail de chaque primitive, il est utile d'avoir un aperçu leurs différences fondamentales. Chaque primitive répond à un besoin précis dans l'écosystème MCP :
Reprise des primitives MCP
| Primitive | Ruolo | Qui contrôle | Effets Collaterali | Exemple |
|---|---|---|---|---|
| Tools | Fonctions pouvant être invoquées par l'IA | L'AI decide autonomamente | Oui (peut changer de statut) | create-sprint, analyze-diff |
| Resources | Dati accessibili in lettura | L'applicazione host | No (read-only) | sprint://{id}, file:///config |
| Prompts | Modele predefiniti riutilizzabili | L'utente seleziona | No (generano messaggi) | sprint-review, code-analysis |
Cette distinction est importante : je Outils ils sont le cœur opérationnel du protocole, le Ressources ils fournissent du contexte et des données, je Invites ils pilotent l'IA tâches structurées. Examinons chaque primitive en détail.
1. Outils : fonctions que l'IA peut invoquer
I Outils ils représentent le cœur de l’interaction MCP. Ce sont des fonctions que l'IA peut appelez-vous lors d'une conversation pour réaliser des actions concrètes dans le monde réel. Contrairement à un simple appel API, un outil MCP déclare explicitement ses paramètres avec un schéma typé, permettant à l'IA de comprendre Quand e comme invoquez-le.
Caractéristiques fondamentales des outils
- L'IA décide quand les appeler: en fonction du contexte de la conversation, le modèle linguistique choisit de manière autonome quel outil invoquer et avec quels paramètres
- Paramètres saisis avec Zod: chaque outil déclare ses entrées avec un schéma Zod, assurant une validation automatique au moment de l'exécution
- Résultats structurés: le résultat est toujours un tableau de
contentavec typetext,imageoresource - Ils peuvent avoir des effets secondaires: créer des fichiers, écrire dans la base de données, appeler des API externes, envoyer des notifications
- Composable: L'IA peut combiner plusieurs outils de manière séquentielle pour accomplir des tâches complexes
Anatomie d'un outil en TypeScript
L'enregistrement d'un outil suit une structure précise avec quatre éléments : nom unique, description de l'IA, du schéma de paramètres Zod et du gestionnaire asynchrone. Voici un exemple compléter à partir du projet Tech-MCP:
import { z } from 'zod';
server.tool(
'create-sprint', // Nome univoco del tool
'Create a new sprint with a name, date range, and goals. ' +
'Returns the created sprint object with id, status, and dates. ' +
'Use this when the user wants to start planning a new iteration.',
{ // Schema parametri (Zod)
name: z.string().describe('Sprint name, e.g. Sprint-15'),
startDate: z.string().describe('Start date in ISO format'),
endDate: z.string().describe('End date in ISO format'),
goals: z.array(z.string()).describe('List of sprint goals'),
},
async ({ name, startDate, endDate, goals }) => { // Handler
const sprint = store.createSprint({
name,
startDate,
endDate,
goals
});
return {
content: [{
type: 'text',
text: JSON.stringify(sprint, null, 2)
}]
};
}
);
pourquoi Zod pour la Validation ?
Zod et une bibliothèque de validation TypeScript-first qui offre une sécurité de type complète au moment de la compilation et de la validation au moment de l'exécution. Le SDK MCP convertit automatiquement les schémas Zod dans Schéma JSON, le format que l'IA utilise pour comprendre les paramètres d'un outil. Cela signifie qu'en déclarant un schéma Zod vous obtenez : la validation automatique des entrées, Génération de documentation pour l'IA et l'inférence de type dans TypeScript, tout en un définition.
Le format de réponse d'un outil
Chaque gestionnaire d'outils doit renvoyer un objet avec un tableau content. Chaque élément
du tableau a un type qui indique le format du contenu :
// Risposta testuale (più comune)
return {
content: [{
type: 'text',
text: 'Sprint creato con successo: Sprint-15 (ID: 42)'
}]
};
// Risposta con immagine
return {
content: [{
type: 'image',
data: base64EncodedImage,
mimeType: 'image/png'
}]
};
// Risposta con errore
return {
content: [{
type: 'text',
text: 'Errore: sprint non trovato'
}],
isError: true
};
Catégories d'outils dans le projet Tech-MCP
Dans le projet Tech-MCP, les plus de 85 outils sont organisés en catégories fonctionnelles en fonction du type d'opération qu'ils effectuent :
Classification des outils par type d'opération
| Categorie | Exemple Tool | Effets | Description |
|---|---|---|---|
| Creazione | create-sprint, save-snippet |
Ils écrivent dans la base de données | Creano nuove entita persistenti |
| Lettura | get-sprint, search-snippets |
Lecture seule | Recuperano dati esistenti |
| Analyses | analyze-diff, find-bottlenecks |
Nessun side effect | Elaborano input e generano insight |
| Generazione | generate-unit-tests, generate-compose |
Producono output | Generano codice, configurazioni, template |
| Monitoraggio | list-pipelines, get-budget-status |
Ils lisent l'état externe | Ils vérifient l'état des systèmes externes |
2. Resources: Dati Accessibili in Lettura
Le Ressources ils constituent la deuxième primitive MCP. Ils représentent les données que l'application héberge il peut lire et fournir comme contexte à l'IA. Contrairement aux Outils, les Ressources ne sont pas appelées directement depuis l'IA : et l'application hôte (Claude Desktop, Cursor, etc.) qui décide quand et quoi les ressources se chargent dans le contexte de la conversation.
Caractéristiques fondamentales des ressources
- Identifié par URI: Chaque ressource possède un identifiant unique, tel que
file:///path/to/file,db://schema/tableosprint://{id} - L'application les nécessite: contrairement aux outils où l'IA décide, pour les ressources et l'application hôte de contrôler l'accès
- Lecture seule: les ressources ne modifient pas l'état du serveur, elles servent exclusivement à fournir des données
- Ils prennent en charge le modèle URI: pour les ressources paramétriques vous pouvez définir des modèles comme
sprint://{id} - Type MIME explicite: chaque ressource déclare le type de contenu (
application/json,text/plain, etc.)
Définition d'une ressource avec modèle URI
Voici comment définir une ressource paramétrique qui expose les détails d'un sprint identifié par votre pièce d'identité :
server.resource(
'sprint://{id}', // URI template
'Get sprint details by ID', // Description
async (uri) => { // Handler
const id = extractIdFromUri(uri);
const sprint = store.getSprint(id);
if (!sprint) {
throw new Error(`Sprint ${id} not found`);
}
return {
contents: [{
uri: uri.href,
mimeType: 'application/json',
text: JSON.stringify(sprint, null, 2)
}]
};
}
);
Resource Statiche vs Dinamiche
Les ressources MCP sont divisées en deux catégories : statique e dynamique. Les ressources statiques ont un URI fixe et renvoient toujours les données du même point de terminaison. Les ressources dynamiques utilisent des modèles d'URI pour accepter les paramètres.
// Resource statica: URI fisso, dati globali
server.resource(
'config://app-settings',
'Application configuration settings',
async (uri) => {
return {
contents: [{
uri: uri.href,
mimeType: 'application/json',
text: JSON.stringify(config.getAll())
}]
};
}
);
// Resource dinamica: URI template con parametro
server.resource(
'user://{userId}/profile',
'User profile data',
async (uri) => {
const userId = extractParam(uri, 'userId');
const profile = await db.getProfile(userId);
return {
contents: [{
uri: uri.href,
mimeType: 'application/json',
text: JSON.stringify(profile)
}]
};
}
);
La charge utile JSON-RPC pour les ressources
Lorsque l'application hôte demande une ressource, le protocole MCP utilise deux méthodes JSON-RPC :
resources/list pour découvrir les ressources disponibles e resources/read
pour lire son contenu.
// Richiesta: elenco delle resources disponibili
{ "method": "resources/list" }
// Risposta del server
{
"resources": [
{
"uri": "config://app-settings",
"name": "App Settings",
"mimeType": "application/json"
}
],
"resourceModeles": [
{
"uriModele": "sprint://{id}",
"name": "Sprint Details",
"mimeType": "application/json"
}
]
}
// Richiesta: lettura di una resource specifica
{ "method": "resources/read",
"params": { "uri": "sprint://42" } }
// Risposta del server
{
"contents": [{
"uri": "sprint://42",
"mimeType": "application/json",
"text": "{ \"id\": 42, \"name\": \"Sprint-15\" }"
}]
}
Note sur le projet Tech-MCP
Dans le projet Tech-MCP, l'interaction avec les données se produit principalement via i Outils. Les Ressources sont prévues pour des développements futurs, par exemple pour exposer des configurations de projets, schémas de base de données ou documentation API comme contexte en lecture seule pour l'IA.
3. Prompts: Modele Predefiniti Riutilizzabili
I Invites ils constituent la troisième primitive MCP. Ils représentent des modèles prédéfinis qui guident L'IA dans l'exécution de tâches complexes et structurées. Contrairement aux outils (où l'IA décide) et ressources (là où l'application décide), les invites sont sélectionné par l'utilisateur pour démarrer des flux de travail spécifiques.
Caractéristiques fondamentales des invites
- Ils pilotent l'IA: Fournir des instructions structurées qui orientent le modèle de langage vers un objectif spécifique
- Ils acceptent les arguments: Peut être paramétré avec la saisie de l'utilisateur
- Peut être combiné avec des outils: une invite peut suggérer à l'IA une séquence d'outils à appeler dans l'ordre
- Réutilisable: Une fois définis, ils peuvent être utilisés dans différentes conversations avec différents paramètres
- Sélectionné par l'utilisateur: L'utilisateur choisit quelle invite activer, pas l'IA
Définition d'une invite avec des arguments
Une invite MCP est définie avec un nom, une description, une liste d'arguments et une fonction qui génère les messages à envoyer à l'IA :
server.prompt(
'sprint-review', // Nome univoco
'Generate a comprehensive sprint review report', // Description
[ // Argomenti
{
name: 'sprintId',
description: 'ID of the sprint to review',
required: true
},
{
name: 'format',
description: 'Output format: summary, detailed, or metrics-only',
required: false
}
],
async ({ sprintId, format }) => ({ // Handler
messages: [{
role: 'user',
content: {
type: 'text',
text: `Analizza lo sprint ${sprintId} con i seguenti passaggi:
1. Usa il tool get-sprint per recuperare i dati dello sprint
2. Usa calculate-velocity per calcolare la velocity del team
3. Usa get-sprint-stories per l'elenco delle storie completate
4. Genera un report in formato ${format || 'detailed'} con:
- Obiettivi raggiunti vs pianificati
- Velocity e trend rispetto agli sprint precedenti
- Storie completate e non completate
- Raccomandazioni per il prossimo sprint`
}
}]
}))
);
La charge utile JSON-RPC pour les invites
Comme pour les autres primitives, les invites utilisent des méthodes JSON-RPC dédiées pour la découverte et invocation :
// Discovery: elenco dei prompts disponibili
{ "method": "prompts/list" }
// Risposta del server
{
"prompts": [
{
"name": "sprint-review",
"description": "Generate a comprehensive sprint review report",
"arguments": [
{
"name": "sprintId",
"description": "ID of the sprint to review",
"required": true
},
{
"name": "format",
"description": "Output format: summary, detailed, or metrics-only",
"required": false
}
]
}
]
}
// Invocazione di un prompt
{ "method": "prompts/get",
"params": {
"name": "sprint-review",
"arguments": { "sprintId": "42", "format": "detailed" }
}
}
// Risposta: messaggi generati dal prompt
{
"messages": [{
"role": "user",
"content": {
"type": "text",
"text": "Analizza lo sprint 42 con i seguenti passaggi..."
}
}]
}
Invites qui orchestrent l'outil
Le véritable pouvoir des invites apparaît lorsqu'elles sont utilisées pour orchestrer des séquences complexes d'outils. Une invite bien conçue peut guider l'IA à travers un flux de travail en plusieurs étapes :
server.prompt(
'full-code-review',
'Perform a comprehensive code review workflow',
[
{ name: 'filePath', description: 'Path to the file to review', required: true },
{ name: 'language', description: 'Programming language', required: true }
],
async ({ filePath, language }) => ({
messages: [{
role: 'user',
content: {
type: 'text',
text: `Esegui una code review completa del file ${filePath} (${language}):
STEP 1 - Analisi statica:
Usa analyze-diff per identificare problemi nel codice
STEP 2 - Generazione test:
Usa generate-unit-tests per creare test per le funzioni trovate
STEP 3 - Verifica stile:
Controlla che il codice segua le convenzioni del progetto
STEP 4 - Report finale:
Genera un report con: problemi trovati, test suggeriti,
miglioramenti proposti, severity di ogni issue`
}
}]
}))
);
Remarque : invites dans le projet Tech-MCP
Comme pour les Ressources, le projet Tech-MCP utilise actuellement je Outils comme primitive principale. Des invites sont prévues pour un développement futur, dans le but de créer des workflows prédéfinis pour des scénarios récurrents tels que des revues de sprint, des intégrations de nouveaux développeurs et analyse des performances des équipes.
Comment l'IA choisit les outils : le rôle des descriptions
Lorsqu'un serveur MCP s'enregistre auprès d'un client, il expose la liste des outils disponibles via
la méthode tools/list. Pour chaque outil, l’IA reçoit trois informations clés :
- Nome: identificativo univoco (es.
create-sprint) - Description: texte en langage naturel qui explique ce que fait l'outil
- Schéma de paramètres: Structure des paramètres d'entrée avec types et descriptions
La description et l'élément le plus critique : une description bien rédigée permet à l'IA comprendre Quand utiliser l'outil, Quoi attendez-vous à un résultat e dans lesquels scénarios et approprié de l'invoquer.
Meilleures pratiques pour les descriptions d'outils
OTTIMO (spiega cosa fa, cosa ritorna, quando usarlo):
"Create a new sprint with a name, date range, and goals.
Returns the created sprint object with id, name, dates, status.
Use this when the user wants to start planning a new iteration."
BUONO (spiega cosa fa e gli input):
"Create a new sprint with a name, date range, and goals"
VAGO (l'AI potrebbe non capire quando usarlo):
"Sprint creation tool"
Liste de contrôle pour des descriptions efficaces
| Elemento | Domanda | Exemple |
|---|---|---|
| Azione | A quoi sert l'outil ? | "Create a new sprint..." |
| Input | Quali parametri servono? | "...with a name, date range, and goals" |
| Output | Qu'est-ce qui revient ? | "Returns the created sprint object with id..." |
| Contesto | Quand l'utiliser ? | "Use when the user wants to plan a new iteration" |
Le cycle de vie d'une session MCP
Chaque interaction MCP suit un cycle de vie structuré en quatre phases. Comprenez ceci le flux est essentiel pour concevoir des serveurs qui se comportent correctement dans tous les scénarios :
[1] INIZIALIZZAZIONE
Client --> Server: initialize (versione protocollo, capabilities)
Server --> Client: capabilities (tool list, resource templates, prompts)
[2] DISCOVERY
Client --> Server: tools/list
Server --> Client: [{ name, description, inputSchema }, ...]
Client --> Server: resources/list
Server --> Client: [{ uri, name, mimeType }, ...]
Client --> Server: prompts/list
Server --> Client: [{ name, description, arguments }, ...]
[3] UTILIZZO (ripetuto N volte durante la sessione)
Client --> Server: tools/call { name, arguments }
Server --> Client: { content: [...] }
Client --> Server: resources/read { uri }
Server --> Client: { contents: [...] }
Client --> Server: prompts/get { name, arguments }
Server --> Client: { messages: [...] }
[4] CHIUSURA
Client --> Server: close
Détail des phases
- Initialisation: le client envoie la version du protocole et ses capacités. Le serveur répond en déclarant les primitives qu'il prend en charge (outils, ressources, invites) ainsi que les siennes. fonctionnalités (notifications, journalisation, etc.).
- Découverte: Le client interroge le serveur pour découvrir toutes les primitives disponibles. Cette phase est fondamentale car elle fournit à l'IA les informations nécessaires pour décider quels outils utiliser.
- Usage: la phase opérationnelle, répétée N fois au cours de la séance. Le client peut invoquer des outils, lire des ressources et déclencher des invites dans n’importe quel ordre et combinaison.
- Fermeture: Le client signale la fin de la séance. Le serveur libère des ressources et ferme les connexions.
Validation des paramètres avec Zod : exemples avancés
Zod propose une large gamme de validateurs qui vous permettent de définir des modèles précis pour les paramètres des outils. Voici quelques modèles avancés utilisés dans le projet Tech-MCP:
import { z } from 'zod';
// Schema con enum e valori opzionali
const createTaskSchema = {
title: z.string().min(1).max(200)
.describe('Task title'),
priority: z.enum(['low', 'medium', 'high', 'critical'])
.describe('Task priority level'),
assignee: z.string().optional()
.describe('Username of the assignee'),
labels: z.array(z.string()).default([])
.describe('List of labels to apply'),
estimate: z.number().positive().optional()
.describe('Estimated hours to complete'),
};
// Schema con oggetti nested
const deployConfigSchema = {
environment: z.enum(['staging', 'production']),
version: z.string().regex(/^\d+\.\d+\.\d+$/),
options: z.object({
rollback: z.boolean().default(true),
healthCheck: z.boolean().default(true),
notifySlack: z.boolean().default(false),
}).optional(),
};
// Schema con union types
const searchSchema = {
query: z.string().min(1),
scope: z.union([
z.literal('code'),
z.literal('docs'),
z.literal('issues'),
z.literal('all'),
]).default('all'),
limit: z.number().int().min(1).max(100).default(20),
};
Interaction entre primitives : un exemple complet
Les trois primitives MCP ne fonctionnent pas de manière isolée. Dans un scénario réel, un workflow peut combiner les trois primitives de manière synergique :
- L'utilisateur sélectionne une invite: "Sprint Review" avec paramètre
sprintId: 42 - L'invite génère des instructions: le message suggère à l'IA d'utiliser des outils spécifiques
- L'AI chiama i Tool: invoca
get-sprint,calculate-velocity,get-sprint-stories - L'application charge les ressources: Ajouter comme contexte
config://team-settings - L'IA génère le rapport: Combinez toutes les données collectées dans un rapport structuré
Cette composabilité est l'une des forces du protocole MCP : chaque primitive contribue avec son rôle spécifique dans des flux de travail complexes et articulés.
Conclusions
Les trois primitives MCP -- Outils, Ressources e Invites -- constituent le vocabulaire fondamental du protocole. Chaque primitive a un rôle distinct : Les outils effectuent des actions, les ressources fournissent des données, les invites guident l'IA dans des tâches structurées.
Validation avec Zod garantit la sécurité de type et la documentation automatique, tout en Le cycle de vie de la session MCP garantit une interaction ordonnée et prévisible entre le client et le serveur. La composabilité entre primitives vous permet de créer des workflows complexes à partir de des éléments de base simples et bien définis.
Dans le prochain article, nous approfondironsarchitecture monorepo et moi modèle de projet utilisé dans Tech-MCP: comment organiser 31 serveurs MCP dans un seul référentiel, gérer les dépendances partagées avec Turborepo et pnpm, et structurer le code pour une réutilisabilité et une maintenabilité maximales.
Le code complet de tous les exemples est disponible au dépôt Tech-MCP sur GitHub.







