Derniere mise a jour : Janvier 2025 | Temps de lecture : 12 minutes | Niveau : Avance
Introduction : Le scenario d'erreur qui m'a pousse a tout重构
Il etait 3h47 du matin quand mon telephone a vibre. L'alertePagerDuty indiquait : "ConnectionError: timeout exceeded 30s — MCP Server cluster-03 unavailable". En me connectant au dashboard, j'ai decouvert que notre serveur MCP etait down depuis 23 minutes, et que nous n'avions aucun moyen de savoir ce qui s'etait passe. Aucun metric, aucune trace, rien.
Cette nuit-la, j'ai compris l'importance capitale d'un systeme de monitoring robuste pour les serveurs MCP. Aujourd'hui, je vais vous montrer comment exposer des Prometheus metrics depuis votre serveur MCP, comment configurer des alertes intelligentes, et comment eviter les pieges qui m'ont coute des heures de debugging.
Pourquoi exposer des Metrics Prometheus pour votre MCP Server ?
Un serveur MCP (Model Context Protocol) peut traiter des centaines de requetes par minute. Sans monitoring, vous etes aveugle face aux :
- Pics de latence : Une latence anormale peut indiquer un probleme de performance ou une saturation du service
- Erreurs 5xx en cascade : Le premier signe d'un service en detresse
- Fuite memoire : Les processus Node.js non surveilles peuvent consommer toute la RAM
- Taux de requetes anormal : Peut-etre une attaque ou un bug dans le client
Architecture de Monitoring MCP avec Prometheus
+------------------+ +-------------------+ +------------------+
| MCP Server | | Prometheus | | Grafana |
| :9100/metrics |---->| :9090 |---->| :3000 |
+------------------+ +-------------------+ +------------------+
| |
v v
+------------------+ +-------------------+
| AlertManager | | Webhook/API |
| :9093 | | Notifications |
+------------------+ +-------------------+
Implementation Complete : Le Code
1. Installation des Dependances
# Installation de prom-client pour l'exposition des metrics
npm install prom-client prometheus-api-metrics express
ou avec Yarn
yarn add prom-client prometheus-api-metrics express
Verifier la version de Node.js (minimum 18+ requis)
node --version
v20.10.0
2. Configuration du Serveur MCP avec Metrics
const express = require('express');
const client = require('prom-client');
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
// --- Configuration Prometheus ---
const register = new client.Registry();
// Ajouter des labels par defaut
register.setDefaultLabels({
app: 'mcp-server-production',
environment: process.env.NODE_ENV || 'development'
});
// Collecter les metrics par defaut (CPU, memoire, event loop)
client.collectDefaultMetrics({ register });
// --- Counter : Nombre total de requetes par endpoint ---
const httpRequestsTotal = new client.Counter({
name: 'mcp_http_requests_total',
help: 'Total number of HTTP requests',
labelNames: ['method', 'path', 'status'],
registers: [register]
});
// --- Histogram : Latence des requetes en millisecondes ---
const httpRequestDuration = new client.Histogram({
name: 'mcp_http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'path'],
buckets: [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
registers: [register]
});
// --- Gauge : Nombre de connexions actives ---
const activeConnections = new client.Gauge({
name: 'mcp_active_connections',
help: 'Number of active connections',
registers: [register]
});
// --- Counter : Erreurs par type ---
const errorCounter = new client.Counter({
name: 'mcp_errors_total',
help: 'Total number of errors by type',
labelNames: ['error_type', 'endpoint'],
registers: [register]
});
// --- Gauge : Queue de traitement ---
const requestQueueSize = new client.Gauge({
name: 'mcp_request_queue_size',
help: 'Current size of the request queue',
registers: [register]
});
// --- Historique des operations MCP ---
const mcpOperationDuration = new client.Histogram({
name: 'mcp_operation_duration_seconds',
help: 'Duration of MCP operations',
labelNames: ['operation', 'status'],
buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5],
registers: [register]
});
// --- Counter : Tokens utilises (pour la facturation) ---
const tokensUsed = new client.Counter({
name: 'mcp_tokens_used_total',
help: 'Total tokens processed',
labelNames: ['model', 'type'], // type: prompt/completion
registers: [register]
});
// --- Express App pour le endpoint /metrics ---
const app = express();
// Middleware pour mesurer la latence
app.use((req, res, next) => {
const start = Date.now();
activeConnections.inc();
res.on('finish', () => {
const duration = (Date.now() - start) / 1000;
httpRequestsTotal.inc({
method: req.method,
path: req.route?.path || req.path,
status: res.statusCode
});
httpRequestDuration.observe(
{ method: req.method, path: req.path },
duration
);
activeConnections.dec();
});
next();
});
// Endpoint Prometheus
app.get('/metrics', async (req, res) => {
try {
res.set('Content-Type', register.contentType);
res.end(await register.metrics());
} catch (err) {
res.status(500).end(err.message);
}
});
// Endpoint de sante
app.get('/health', (req, res) => {
res.json({ status: 'healthy', uptime: process.uptime() });
});
// --- Serveur MCP avec Stdio ---
const mcpServer = new Server(
{
name: 'mcp-server-monitored',
version: '1.0.0',
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
// Exemple de handler d'outils avec metrics
mcpServer.setRequestHandler('tools/list', async () => {
return {
tools: [
{
name: 'ai_complete',
description: 'Completion AI via HolySheep',
inputSchema: {
type: 'object',
properties: {
prompt: { type: 'string' },
model: { type: 'string', default: 'deepseek-v3.2' }
}
}
}
]
};
});
// Exemple d'appel API avec tracking des metrics
async function callAIService(prompt, model = 'deepseek-v3.2') {
const end = mcpOperationDuration.startTimer({ operation: 'ai_complete' });
try {
const startTokenCount = Date.now();
const response = await fetch('https://api.holysheep.ai