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.
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.
// Le flux de communication MCP
Claude Code → JSON-RPC Request → /api/mcp
↓
Authentification
↓
Tool Selection
↓
Action Execution
↓
Claude Code ← JSON-RPC Response ←──┘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
| Composant | Description |
|---|---|
| Authentification | Login/Register avec NextAuth.js |
| Base de données | MongoDB Atlas (shared pour le tuto) |
| UI | Shadcn/ui + Tailwind CSS |
| Temps réel | SSE (Server-Sent Events) |
| API Keys | Gestion dans /settings |
// 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.
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 HTTP1. Authentification MCP
Le fichier mcp/auth.ts gère l’authentification des requêtes MCP via une clé API chiffrée.
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.
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.
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.
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
// ...
}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 :
claude mcp add todo-mcp \
--transport http \
--url http://localhost:3000/api/mcp \
--header x-api-key: YOUR_API_KEY_HEREScope Global
Avec --scope user, le MCP est disponible dans tous vos projets.
Scope Local
Sans scope, le MCP n’est actif que dans le dossier courant.
.claude/mcp.jsonVérification de la connexion
Dans Claude Code, tapez /mcp pour voir l’état de vos serveurs MCP :
> /mcp
MCP Servers:
todo-mcp ● Connected
Tools: list_todos, create_todo, move_todo, delete_todoDémonstration en Action
Voici ce qui se passe concrètement quand vous demandez à Claude Code d’interagir avec votre application.
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èsLa tâche apparaît instantanément dans votre application grâce au SSE (Server-Sent Events). Pas besoin de rafraîchir la page.
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é.
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
