Créer un Serveur MCP pour Claude Code : Le Guide Complet
Tutoriel Complet

Créer un Serveur MCP pour Claude Code : Le Guide Complet

Découvrez comment transformer Claude Code en un assistant capable d’interagir directement avec votre application. Un pattern production-ready que j’utilise personnellement sur mon CRM.

35 min de lecture Niveau Intermédiaire Next.js + MCP
01

Qu’est-ce que MCP ?

MCP (Model Context Protocol) est ce que j’appelle l’USB pour l’IA. C’est un standard ouvert créé par Anthropic qui permet à Claude Code de communiquer avec des applications externes : sites web, APIs, bases de données…

Le problème que MCP résout

Claude Code est enfermé. Il ne peut pas toucher à vos données, ni interagir avec vos applications. En créant un simple fichier MCP, vous lui donnez le pouvoir de lire, modifier et supprimer des données directement dans votre application.

Les trois couches du MCP

Tools

Les actions que Claude peut exécuter : lister, créer, supprimer… Chaque outil a un nom, une description et un schéma de validation.

Transport HTTP

Claude envoie des requêtes JSON-RPC à votre app via HTTP. Rien de magique, c’est du standard.

Route API

Le point d’entrée /api/mcp reçoit les requêtes, authentifie l’utilisateur et route vers le bon tool.

mcp-flow.ts
// Le flux de communication MCP
Claude Code → JSON-RPC Request → /api/mcp
                                    ↓
                            Authentification
                                    ↓
                            Tool Selection
                                    ↓
                            Action Execution
                                    ↓
Claude Code ← JSON-RPC Response ←──┘
02

Création de l’Application Todo

Pour cet exemple, nous allons créer une application de gestion de tâches complète de type Kanban. L’objectif est d’avoir une base grand public qui servira de support pour notre serveur MCP.

Architecture de l’application

ComposantDescription
AuthentificationLogin/Register avec NextAuth.js
Base de donnéesMongoDB Atlas (shared pour le tuto)
UIShadcn/ui + Tailwind CSS
Temps réelSSE (Server-Sent Events)
API KeysGestion dans /settings
Prompt pour Claude Code
// Exemple de prompt structuré pour générer l'app
"Créer une application Todo complète de type Kanban avec :
- Authentification email/mot de passe
- Drag and drop pour les colonnes
- Mise à jour temps réel via SSE
- Page /settings pour gérer les clés API
- Style moderne avec Shadcn/ui

Stack : Next.js 14, MongoDB, NextAuth.js"

Astuce Agent Team

Activez le mode « Agent Team » dans Claude Code pour créer votre application beaucoup plus rapidement. Claude va orchestrer plusieurs agents spécialisés qui travaillent en parallèle.

03

Implémentation du Serveur MCP

Passons maintenant au cœur du sujet : la création de notre serveur MCP. Nous allons créer 4 fichiers essentiels qui composeront notre infrastructure MCP.

Structure des fichiers

lib/
└── mcp/
    ├── auth.ts      ← Authentification API Key
    ├── tools/
    │   └── todo.ts  ← Définition des outils MCP
    └── factory.ts   ← Création du serveur MCP

app/
└── api/
    └── mcp/
        └── route.ts ← Point d'entrée HTTP

1. Authentification MCP

Le fichier mcp/auth.ts gère l’authentification des requêtes MCP via une clé API chiffrée.

lib/mcp/auth.ts
import { createHash } from 'crypto';
import { ApiKey } from '@/models/ApiKey';

export async function authenticateMCP(request: Request): Promise {
  const apiKey = request.headers.get('x-api-key');
  
  if (!apiKey) return null;
  
  // Hash SHA-256 de la clé (jamais stockée en clair)
  const hashedKey = createHash('sha256').update(apiKey).digest('hex');
  
  const keyDoc = await ApiKey.findOneAndUpdate(
    { keyHash: hashedKey },
    { $set: { lastUsedAt: new Date() } }
  );
  
  return keyDoc ? keyDoc.userId : null;
}

Sécurité

La clé API n’est jamais stockée en base. Seul son hash SHA-256 est conservé.

Traçabilité

Le champ lastUsedAt permet de suivre l’utilisation des clés.

2. Définition des Tools

Le fichier mcp/tools/todo.ts définit les actions que Claude pourra exécuter. Chaque tool suit le même pattern : nom, description, schéma Zod, et handler.

lib/mcp/tools/todo.ts
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';

export function registerTodoTools(server: McpServer, userId: string) {
  
  // Tool: Lister les tâches
  server.tool('list_todos', 
    'Liste toutes les tâches de l\'utilisateur avec filtres optionnels',
    {
      status: z.enum(['todo', 'in_progress', 'done']).optional(),
      priority: z.enum(['low', 'medium', 'high']).optional(),
      search: z.string().optional()
    },
    async ({ status, priority, search }) => {
      const filter: any = { userId };
      if (status) filter.status = status;
      if (priority) filter.priority = priority;
      if (search) filter.title = { $regex: search, $options: 'i' };
      
      const todos = await Todo.find(filter);
      return { content: [{ type: 'text', text: JSON.stringify(todos) }] };
    }
  );

  // Tool: Créer une tâche
  server.tool('create_todo',
    'Crée une nouvelle tâche',
    {
      title: z.string(),
      priority: z.enum(['low', 'medium', 'high']).default('medium')
    },
    async ({ title, priority }) => {
      const todo = await Todo.create({
        userId, title, priority, status: 'todo'
      });
      emitChange(userId); // SSE notification
      return { content: [{ type: 'text', text: JSON.stringify(todo) }] };
    }
  );

  // Tool: Déplacer une tâche
  server.tool('move_todo',
    'Déplace une tâche vers une autre colonne',
    {
      todoId: z.string(),
      newStatus: z.enum(['todo', 'in_progress', 'done'])
    },
    async ({ todoId, newStatus }) => {
      await Todo.findByIdAndUpdate(todoId, { status: newStatus });
      emitChange(userId);
      return { content: [{ type: 'text', text: 'Tâche déplacée' }] };
    }
  );

  // Tool: Supprimer une tâche
  server.tool('delete_todo',
    'Supprime une tâche de manière permanente',
    { todoId: z.string() },
    async ({ todoId }) => {
      const todo = await Todo.findById(todoId);
      if (!todo || todo.userId !== userId) {
        throw new Error('Tâche non trouvée');
      }
      await Todo.findByIdAndDelete(todoId);
      emitChange(userId);
      return { content: [{ type: 'text', text: 'Tâche supprimée' }] };
    }
  );
}

3. Factory du Serveur MCP

Le factory crée une instance fraîche du serveur MCP pour chaque utilisateur.

lib/mcp/factory.ts
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { registerTodoTools } from './tools/todo';

export function createMCPServer(userId: string): McpServer {
  const server = new McpServer({
    name: 'todo-mcp',
    version: '1.0.0'
  });
  
  // Enregistrer les tools
  registerTodoTools(server, userId);
  
  // Ajouter d'autres modules ici au besoin
  // registerClientTools(server, userId);
  // registerCalendarTools(server, userId);
  
  return server;
}

4. Route API MCP

Le point d’entrée HTTP qui reçoit les requêtes de Claude Code.

app/api/mcp/route.ts
import { authenticateMCP } from '@/lib/mcp/auth';
import { createMCPServer } from '@/lib/mcp/factory';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';

export async function POST(request: Request) {
  // 1. Authentification
  const userId = await authenticateMCP(request);
  if (!userId) {
    return new Response('Non autorisé', { status: 401 });
  }
  
  // 2. Créer le serveur MCP pour cet utilisateur
  const server = createMCPServer(userId);
  
  // 3. Connecter le transport HTTP
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined
  });
  await server.connect(transport);
  
  // 4. Traiter la requête
  const response = await transport.handleRequest(request);
  
  return response;
}

export async function GET(request: Request) {
  // Même logique pour les requêtes GET (découverte)
  // ...
}

export async function DELETE(request: Request) {
  // Fermeture propre des sessions MCP
  // ...
}
04

Connexion à Claude Code

Une fois votre serveur MCP déployé, il ne reste qu’à le connecter à Claude Code. C’est une simple commande qui ajoute votre MCP à la configuration.

Génération de la clé API

Dans votre application, générez une clé API depuis la page /settings. L’interface doit afficher la commande prête à copier :

Commande à exécuter
claude mcp add todo-mcp \
  --transport http \
  --url http://localhost:3000/api/mcp \
  --header x-api-key: YOUR_API_KEY_HERE

Scope Global

Avec --scope user, le MCP est disponible dans tous vos projets.

~/.claude.json

Scope Local

Sans scope, le MCP n’est actif que dans le dossier courant.

.claude/mcp.json

Vérification de la connexion

Dans Claude Code, tapez /mcp pour voir l’état de vos serveurs MCP :

Claude Code – /mcp
> /mcp

MCP Servers:
  todo-mcp ● Connected
    Tools: list_todos, create_todo, move_todo, delete_todo
05

Démonstration en Action

Voici ce qui se passe concrètement quand vous demandez à Claude Code d’interagir avec votre application.

30:09

Créer une tâche

> Ajoute une tâche "Déployer l'application en production"

Claude utilise: todo-mcp.create_todo
├── title: "Déployer l'application en production"
├── priority: "medium"
└── ✓ Tâche créée avec succès

La tâche apparaît instantanément dans votre application grâce au SSE (Server-Sent Events). Pas besoin de rafraîchir la page.

30:42

Déplacer une tâche

> Move la tâche "Créer le serveur MCP" dans done

Claude utilise: todo-mcp.list_todos
├── search: "Créer le serveur MCP"
└── Trouvé: 1 tâche

Claude utilise: todo-mcp.move_todo
├── todoId: "abc123"
├── newStatus: "done"
└── ✓ Tâche déplacée

Claude suit un workflow intelligent : il cherche d’abord la tâche avec search, puis utilise l’ID retourné pour la déplacer.

La puissance du MCP

Vous donnez des outils simples à Claude, et lui orchestre automatiquement les workflows. Plus besoin de quitter votre terminal pour gérer votre application. C’est un game-changer pour la productivité.

06

Ce que nous avons appris

Protocole MCP

JSON-RPC + HTTP + validation Zod. Un standard propre et bien documenté par Anthropic.

Pattern API Key

Clé chiffrée SHA-256, isolation par userId. Production-ready, c’est ce que j’utilise sur mon CRM.

Connexion Simple

Une seule commande claude mcp add et vous pilotez votre app depuis le terminal.

Prochaines étapes

Ce que nous avons vu est la base. MCP offre des fonctionnalités plus avancées :

  • 1 Resources : Donner du contexte à Claude (dashboards, résumés de données)
  • 2 Prompts : Templates réutilisables pour des interactions standardisées
  • 3 Sampling : Permettre à Claude de demander des clarifications via votre app

Intéressé par une vidéo avancée ?

Dites-le en commentaire sur la vidéo YouTube si vous voulez un tutoriel sur les Resources et Prompts MCP !

Voir la vidéo
Ressources

Liens et Ressources

Vidéo

Sommaire de la Vidéo

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Retour en haut