iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
Formations
Node.js · Intermédiaire

Créer un serveur MCP en Node.js

Construire un serveur MCP de A à Z : tools, resources, prompts, validation, transports stdio et HTTP — pour connecter Claude à n'importe quel système externe.

Node.jsTypeScriptMCPClaude Code
01Comprendre MCP02Premier serveur MCP03Tools avancés — validation, erreurs, structure04Resources — exposer du contenu05Prompts — templates réutilisables06Transports et déploiement07Projet complet — MCP de gestion de projet
Chapitre 5·15 min

Prompts — templates réutilisables

Les prompts MCP sont des templates de messages que le serveur expose et que les clients peuvent instancier. Moins courants que les tools et resources, ils deviennent utiles quand vous avez des workflows de conversation répétitifs — revue de code avec un contexte précis, analyse de logs selon un format défini, génération de rapport avec des paramètres.

Quand utiliser des prompts

Un prompt MCP est utile quand :

  • La même série de messages revient souvent avec des variables différentes
  • Vous voulez standardiser comment Claude est instruit pour une tâche
  • Le workflow nécessite un contexte spécifique que le serveur peut construire dynamiquement

Exemple : un prompt analyze_error qui récupère les logs autour d'une erreur, les formate, et demande à Claude une analyse précise.

Activer les prompts

const server = new Server(
  { name: 'mon-mcp', version: '1.0.0' },
  {
    capabilities: {
      tools: {},
      resources: {},
      prompts: {},   // ← activer les prompts
    },
  }
)

Déclarer les prompts disponibles

import {
  ListPromptsRequestSchema,
  GetPromptRequestSchema,
} from '@modelcontextprotocol/sdk/types.js'
 
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
  prompts: [
    {
      name: 'analyze_error',
      description: 'Analyse une erreur avec le contexte des logs environnants',
      arguments: [
        {
          name: 'error_id',
          description: 'ID de l\'erreur dans le système de logs',
          required: true,
        },
        {
          name: 'context_lines',
          description: 'Nombre de lignes de contexte avant/après (défaut: 20)',
          required: false,
        },
      ],
    },
    {
      name: 'code_review',
      description: 'Revue de code avec focus configurable',
      arguments: [
        {
          name: 'file_path',
          description: 'Chemin du fichier à reviewer',
          required: true,
        },
        {
          name: 'focus',
          description: 'Focus de la review : security | performance | readability | all',
          required: false,
        },
      ],
    },
    {
      name: 'weekly_report',
      description: 'Génère un rapport hebdomadaire depuis les données du projet',
      arguments: [
        {
          name: 'week',
          description: 'Semaine au format YYYY-WNN (ex: 2026-W25)',
          required: false,
        },
      ],
    },
  ],
}))

Implémenter les prompts

Le handler retourne une liste de messages prêts à être envoyés à Claude.

server.setRequestHandler(GetPromptRequestSchema, async (request) => {
  const { name, arguments: args } = request.params
 
  if (name === 'analyze_error') {
    const errorId = args?.error_id as string
    const contextLines = parseInt(args?.context_lines as string ?? '20')
 
    // Récupérer les données depuis votre système
    const error = await logsService.getError(errorId)
    const context = await logsService.getContext(errorId, contextLines)
 
    if (!error) {
      throw new McpError(ErrorCode.InvalidParams, `Erreur ${errorId} introuvable`)
    }
 
    return {
      description: `Analyse de l'erreur ${errorId}`,
      messages: [
        {
          role: 'user',
          content: {
            type: 'text',
            text: `Analyse cette erreur :
 
**Erreur :** ${error.message}
**Timestamp :** ${error.timestamp}
**Service :** ${error.service}
**Stack trace :**
\`\`\`
${error.stackTrace}
\`\`\`
 
**Contexte (${contextLines} lignes avant/après) :**
\`\`\`
${context}
\`\`\`
 
Identifie la cause racine, explique pourquoi ça s'est produit, et propose des solutions.`,
          },
        },
      ],
    }
  }
 
  if (name === 'code_review') {
    const filePath = args?.file_path as string
    const focus = (args?.focus as string) ?? 'all'
 
    const fileContent = await readFile(filePath, 'utf-8')
    const extension = filePath.split('.').pop()
 
    const focusInstructions: Record<string, string> = {
      security: 'Focus sur les vulnérabilités de sécurité : injection, exposition de données, authentification manquante, validation insuffisante.',
      performance: 'Focus sur les problèmes de performance : requêtes N+1, algorithmes inefficaces, fuites mémoire, calculs inutiles.',
      readability: 'Focus sur la lisibilité : nommage, complexité cyclomatique, duplication, abstractions manquées.',
      all: 'Analyse complète : sécurité, performance, lisibilité, et maintenabilité.',
    }
 
    return {
      description: `Review de ${filePath} (focus: ${focus})`,
      messages: [
        {
          role: 'user',
          content: {
            type: 'text',
            text: `Review ce fichier :
 
**Fichier :** ${filePath}
**Focus :** ${focusInstructions[focus] ?? focusInstructions.all}
 
\`\`\`${extension}
${fileContent}
\`\`\`
 
Présente tes findings par sévérité : Critique / Warning / Suggestion. Pour chaque finding : ligne concernée, problème, correction proposée.`,
          },
        },
      ],
    }
  }
 
  if (name === 'weekly_report') {
    const week = args?.week as string ?? getCurrentWeek()
 
    // Récupérer les données du projet pour la semaine
    const commits = await gitService.getCommitsForWeek(week)
    const closedTickets = await ticketsService.getClosedForWeek(week)
    const deployments = await deployService.getForWeek(week)
 
    return {
      description: `Rapport hebdomadaire ${week}`,
      messages: [
        {
          role: 'user',
          content: {
            type: 'text',
            text: `Génère un rapport hebdomadaire structuré à partir de ces données.
 
**Semaine :** ${week}
 
**Commits (${commits.length}) :**
${commits.map(c => `- ${c.hash.slice(0,7)} ${c.message} (${c.author})`).join('\n')}
 
**Tickets fermés (${closedTickets.length}) :**
${closedTickets.map(t => `- [${t.id}] ${t.title} (${t.type})`).join('\n')}
 
**Déploiements (${deployments.length}) :**
${deployments.map(d => `- ${d.service} → ${d.environment} (${d.status})`).join('\n')}
 
Format : résumé exécutif (3 phrases), travail accompli, incidents / problèmes, plan semaine suivante.`,
          },
        },
      ],
    }
  }
 
  throw new McpError(ErrorCode.MethodNotFound, `Prompt inconnu : ${name}`)
})

Prompts avec messages multiples

Un prompt peut contenir plusieurs messages pour simuler un historique de conversation :

return {
  messages: [
    {
      role: 'user',
      content: {
        type: 'text',
        text: 'Tu es un expert en sécurité web. Je vais te montrer du code à auditer.',
      },
    },
    {
      role: 'assistant',
      content: {
        type: 'text',
        text: 'Je suis prêt. Montre-moi le code à analyser.',
      },
    },
    {
      role: 'user',
      content: {
        type: 'text',
        text: `Voici le code à auditer :\n\n\`\`\`${code}\`\`\``,
      },
    },
  ],
}

Le faux échange "user/assistant" au début configure le comportement de Claude sans que ce soit visible comme une instruction système.

Inclure des resources dans un prompt

Un prompt peut référencer une resource du même serveur :

return {
  messages: [
    {
      role: 'user',
      content: {
        type: 'resource',
        resource: {
          uri: `db://users/${userId}`,
          mimeType: 'application/json',
          text: JSON.stringify(await getUserById(userId), null, 2),
        },
      },
    },
    {
      role: 'user',
      content: {
        type: 'text',
        text: 'Analyse le profil de cet utilisateur et identifie les données manquantes ou incohérentes.',
      },
    },
  ],
}

Utiliser un prompt depuis Claude Code

Les clients MCP qui supportent les prompts peuvent les instancier via une commande. En pratique, depuis Claude Code :

> utilise le prompt analyze_error avec l'erreur ERR-2026-0624-001

Claude récupère le prompt, les messages sont envoyés, Claude analyse et répond.


Tools, resources, prompts — les trois primitives MCP sont couvertes. Le chapitre suivant traite des transports : comment exposer votre serveur via stdio (local) ou HTTP (remote), et comment déployer en production.

Précédent
Resources — exposer du contenu
Suivant
Transports et déploiement

Développeur fullstack passionné. J'apprends en construisant et je documente tout — front, back, outils. Le code s'apprend mieux en public.

Naviguer

IndexTous les articlesFormationsProfilOutilsBibliothech

Ailleurs

GitHub RSS

Newsletter

Les articles, libs et découvertes. Une fois par semaine, pas plus.

© 2026 William LoreeConçu & codé à la main