Construire et auto-héberger un serveur MCP sur un VPS
Construisez un serveur MCP en TypeScript, déployez-le sur un VPS avec systemd derrière Nginx et TLS. Connectez Claude Desktop, Claude Code et Cursor à votre serveur auto-hébergé.
Tous les tutoriels MCP s'arrêtent à « lancer en local avec stdio ». Celui-ci couvre le parcours complet : construire un serveur MCP en TypeScript, le déployer sur un VPS derrière Nginx avec TLS, le sécuriser avec authentification et règles de pare-feu, et connecter des clients MCP via internet.
Que construisez-vous ?
Les clients MCP envoient des requêtes JSON-RPC via HTTPS. Nginx termine le TLS et proxifie les requêtes vers le processus MCP qui tourne sur un port local. Le serveur MCP valide un bearer token, traite la requête et renvoie le résultat.
MCP Client (Claude, Cursor, ...)
|
| HTTPS (port 443)
v
Nginx (TLS termination + reverse proxy)
|
| HTTP (port 3000, localhost only)
v
MCP Server (Node.js + Express)
|
v
SQLite database
L'exemple est un serveur de notes. Il expose deux tools (rechercher des notes, créer une note) et une resource (lister toutes les notes). Assez simple pour suivre, assez utile pour être étendu.
Quel transport utiliser pour un serveur MCP distant ?
Streamable HTTP est le standard actuel de la spécification MCP pour les déploiements distants. Il remplace le transport SSE déprécié et fonctionne avec des requêtes HTTP POST classiques. Stdio reste le transport pour les serveurs locaux où le client lance le serveur en sous-processus.
| Transport | Cas d'usage | Compatible distant | Support client |
|---|---|---|---|
| stdio | Outils locaux, intégrations CLI | Non | Tous les clients |
| SSE (déprécié) | Serveurs distants legacy | Oui | La plupart (en cours d'abandon) |
| Streamable HTTP | Serveurs distants, production | Oui | Claude Desktop, Claude Code, Cursor |
Streamable HTTP envoie chaque message client en HTTP POST vers un endpoint unique (ex : /mcp). Le serveur répond en application/json pour les réponses simples ou en text/event-stream quand il doit streamer plusieurs messages. Cela fonctionne avec l'infrastructure HTTP standard, y compris les reverse proxies et les load balancers.
Prérequis
- Un VPS sous Debian 12 ou Ubuntu 24.04 (ce guide utilise Debian 12)
- Un nom de domaine avec un enregistrement DNS pointant vers votre VPS (ex :
mcp.example.com) - Node.js 20+ installé sur le VPS
- Connaissance de base de TypeScript et Linux
Héberger des agents IA sur un VPS
Comment configurer un projet de serveur MCP en TypeScript ?
Commencez sur votre machine locale ou directement sur le VPS. Initialisez le projet, installez le SDK MCP et configurez TypeScript.
mkdir mcp-notes-server && cd mcp-notes-server
npm init -y
npm install @modelcontextprotocol/sdk zod express better-sqlite3
npm install -D typescript @types/node @types/express @types/better-sqlite3
Créez la configuration TypeScript :
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}
Mettez à jour package.json pour ajouter les scripts de build et de démarrage et définir le type de module :
{
"type": "module",
"scripts": {
"build": "tsc",
"start": "node build/index.js"
}
}
Créez le répertoire source :
mkdir src
Comment implémenter des tools MCP avec validation des entrées ?
Un serveur MCP expose des tools, des resources et des prompts aux clients IA. Les tools sont des fonctions que l'IA peut appeler. Les resources sont des données en lecture seule que l'IA peut consulter. Nous allons implémenter les deux.
Créez src/index.ts avec la configuration de la base de données et une fonction factory qui construit un nouveau serveur MCP pour chaque requête. Le Streamable HTTP stateless nécessite une nouvelle instance McpServer par requête car le SDK ne permet pas de reconnecter le même serveur à un transport différent.
import express from "express";
import { randomUUID } from "crypto";
import Database from "better-sqlite3";
import { z } from "zod";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
// --- Database setup ---
const db = new Database("notes.db");
db.pragma("journal_mode = WAL");
db.exec(`
CREATE TABLE IF NOT EXISTS notes (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
created_at TEXT DEFAULT (datetime('now'))
)
`);
// --- MCP Server factory ---
// Each stateless request needs its own McpServer + transport pair.
// The SDK binds a server to a single transport on connect() and
// throws if you try to reuse it. A factory function keeps it clean.
function createServer(): McpServer {
const server = new McpServer({
name: "notes-server",
version: "1.0.0",
});
Enregistrez maintenant les tools dans la factory. Chaque tool utilise Zod pour la validation des entrées. Le SDK valide automatiquement les inputs avant l'exécution du handler.
// --- Tools ---
server.tool(
"search_notes",
"Search notes by keyword in title or content",
{
query: z.string().min(1).describe("Search keyword"),
},
async ({ query }) => {
const stmt = db.prepare(
"SELECT id, title, content, created_at FROM notes WHERE title LIKE ? OR content LIKE ? ORDER BY created_at DESC LIMIT 20"
);
const rows = stmt.all(`%${query}%`, `%${query}%`);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(rows, null, 2),
},
],
};
}
);
server.tool(
"create_note",
"Create a new note with a title and content",
{
title: z.string().min(1).max(200).describe("Note title"),
content: z.string().min(1).describe("Note content"),
},
async ({ title, content }) => {
const id = randomUUID();
const stmt = db.prepare(
"INSERT INTO notes (id, title, content) VALUES (?, ?, ?)"
);
stmt.run(id, title, content);
return {
content: [
{
type: "text" as const,
text: `Note created with id: ${id}`,
},
],
};
}
);
Comment ajouter des resources à un serveur MCP ?
Les resources donnent aux clients IA un accès en lecture seule aux données. Elles sont référencées par URI. Ajoutez une resource qui liste toutes les notes, toujours dans la factory createServer :
// --- Resources ---
server.resource(
"all-notes",
"notes://all",
{
description: "List all notes in the database",
mimeType: "application/json",
},
async (uri) => {
const rows = db.prepare(
"SELECT id, title, created_at FROM notes ORDER BY created_at DESC LIMIT 100"
).all();
return {
contents: [
{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify(rows, null, 2),
},
],
};
}
);
return server;
}
Les clients MCP peuvent découvrir cette resource et la lire sans appeler un tool. Claude Desktop affiche les resources dans le menu des pièces jointes. Claude Code les expose via les mentions @.
Comment sécuriser un serveur MCP avec un token d'authentification ?
Un serveur MCP en production nécessite une authentification. Sans elle, quiconque découvre votre endpoint peut appeler vos tools. Utilisez un bearer token vérifié dans un middleware Express avant que les requêtes n'atteignent le transport MCP.
Générez un token solide :
openssl rand -base64 32
Conservez le résultat. Vous en aurez besoin pour la configuration du serveur et des clients.
Ajoutez le middleware d'authentification et les routes Express dans src/index.ts :
// --- Auth middleware ---
const AUTH_TOKEN = process.env.MCP_AUTH_TOKEN;
if (!AUTH_TOKEN) {
console.error("MCP_AUTH_TOKEN environment variable is required");
process.exit(1);
}
function authenticateRequest(
req: express.Request,
res: express.Response,
next: express.NextFunction
): void {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith("Bearer ")) {
res.status(401).json({
jsonrpc: "2.0",
error: { code: -32001, message: "Missing or invalid authorization" },
id: null,
});
return;
}
const token = authHeader.slice(7);
if (token !== AUTH_TOKEN) {
res.status(403).json({
jsonrpc: "2.0",
error: { code: -32001, message: "Invalid token" },
id: null,
});
return;
}
next();
}
// --- Express app ---
const app = express();
app.use(express.json());
app.use("/mcp", authenticateRequest);
Le middleware s'exécute avant chaque requête vers /mcp. Il vérifie la présence d'un token Bearer dans le header Authorization et rejette les requêtes non autorisées avec une erreur JSON-RPC.
Comment configurer le transport Streamable HTTP ?
Ajoutez la configuration du transport et les handlers de routes. Chaque requête crée un nouveau McpServer depuis la factory et une nouvelle instance de transport :
// --- Streamable HTTP transport ---
app.post("/mcp", async (req, res) => {
const server = createServer();
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
await server.connect(transport);
try {
await transport.handleRequest(req, res, req.body);
} catch (error) {
console.error("MCP request error:", error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: "2.0",
error: { code: -32603, message: "Internal server error" },
id: null,
});
}
}
});
app.get("/mcp", (_req, res) => {
res.status(405).json({
jsonrpc: "2.0",
error: { code: -32000, message: "Method not allowed. Use POST." },
id: null,
});
});
app.delete("/mcp", (_req, res) => {
res.status(405).json({
jsonrpc: "2.0",
error: { code: -32000, message: "Method not allowed." },
id: null,
});
});
// --- Health check ---
app.get("/health", (_req, res) => {
res.json({ status: "ok" });
});
// --- Start ---
const PORT = parseInt(process.env.PORT || "3000", 10);
app.listen(PORT, "127.0.0.1", () => {
console.log(`MCP server listening on http://127.0.0.1:${PORT}/mcp`);
});
sessionIdGenerator: undefined crée un serveur stateless. Chaque requête est indépendante, avec sa propre paire McpServer + transport. C'est plus simple à déployer et fonctionne bien derrière un reverse proxy sans session sticky. La connexion à la base de données (db) est au scope du module et partagée entre les requêtes, donc les données persistent entre les appels.
Le serveur écoute sur 127.0.0.1, pas 0.0.0.0. Il n'accepte que les connexions locales. Nginx sera le seul moyen d'y accéder depuis l'extérieur.
Compilez et testez en local :
npm run build
Contrôlez que le build réussit sans erreur.
Comment tester un serveur MCP en local ?
MCP Inspector est l'outil de test officiel. Il se connecte à votre serveur et vous permet d'appeler les tools de façon interactive.
Démarrez votre serveur dans un terminal :
MCP_AUTH_TOKEN=test-token-local npm start
Dans un autre terminal, testez avec curl :
curl -X POST http://127.0.0.1:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer test-token-local" \
-d '{
"jsonrpc": "2.0",
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": { "name": "test-client", "version": "1.0.0" }
},
"id": 1
}'
Vous devriez voir une réponse SSE (event: message suivie d'une ligne data:) contenant les capacités du serveur, y compris les objets tools et resources. Cela confirme que le serveur accepte les connexions et répond au handshake d'initialisation MCP.
Testez le tool create_note :
curl -X POST http://127.0.0.1:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer test-token-local" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "create_note",
"arguments": { "title": "Test Note", "content": "Hello from curl" }
},
"id": 2
}'
La réponse devrait contenir "Note created with id: ...". Testez maintenant le tool de recherche :
curl -X POST http://127.0.0.1:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer test-token-local" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "search_notes",
"arguments": { "query": "Test" }
},
"id": 3
}'
Vous devriez voir la note que vous venez de créer dans les résultats. Vérifiez qu'une requête sans header Authorization retourne une erreur 401 :
curl -s -o /dev/null -w "%{http_code}" -X POST http://127.0.0.1:3000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}'
Cela devrait afficher 401. Si c'est le cas, votre middleware d'authentification fonctionne.
Vous pouvez aussi utiliser le MCP Inspector pour des tests interactifs avec une interface web :
npx @modelcontextprotocol/inspector
L'Inspector ouvre une interface dans le navigateur où vous pouvez vous connecter au serveur, parcourir les tools et resources, et tester les appels.
Comment déployer un serveur MCP sur un VPS ?
Transférez votre projet sur le VPS avec rsync, scp, ou poussez vers un dépôt Git et clonez sur le serveur. Les étapes suivantes supposent que vous êtes connecté au VPS.
Créer un utilisateur dédié
Ne lancez jamais de processus applicatifs en root. Créez un utilisateur de service :
sudo useradd -r -m -s /usr/sbin/nologin mcpserver
Installer Node.js
Si Node.js 20+ n'est pas déjà installé :
curl -fsSL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh
sudo bash nodesource_setup.sh
sudo apt-get install -y nodejs
node --version
npm --version
La première commande télécharge le script d'installation dans un fichier pour que vous puissiez l'inspecter avant de l'exécuter. Vérifiez que la sortie affiche v20.x.x ou supérieur pour Node.js et 10.x.x pour npm. Le SDK MCP nécessite Node.js 18+ mais la version 20 LTS est recommandée en production.
Configurer le répertoire du projet
sudo mkdir -p /opt/mcp-notes-server
sudo cp -r /path/to/your/project/* /opt/mcp-notes-server/
cd /opt/mcp-notes-server
sudo npm ci --omit=dev
sudo npm run build
sudo chown -R mcpserver:mcpserver /opt/mcp-notes-server
Assurez-vous les droits :
ls -la /opt/mcp-notes-server/
Tous les fichiers doivent appartenir à mcpserver:mcpserver.
Créer le fichier d'environnement
Stockez le token d'authentification dans un fichier d'environnement restreint :
sudo mkdir -p /etc/mcp-notes-server
echo "MCP_AUTH_TOKEN=$(openssl rand -base64 32)" | sudo tee /etc/mcp-notes-server/env > /dev/null
sudo chmod 600 /etc/mcp-notes-server/env
sudo chown mcpserver:mcpserver /etc/mcp-notes-server/env
Lisez le token généré et conservez-le en lieu sûr. Vous en aurez besoin pour la configuration des clients :
sudo cat /etc/mcp-notes-server/env
Créer le service systemd
sudo tee /etc/systemd/system/mcp-notes-server.service > /dev/null << 'EOF'
[Unit]
Description=MCP Notes Server
After=network.target
[Service]
Type=simple
User=mcpserver
Group=mcpserver
WorkingDirectory=/opt/mcp-notes-server
EnvironmentFile=/etc/mcp-notes-server/env
ExecStart=/usr/bin/node build/index.js
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
# Hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/mcp-notes-server
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
EnvironmentFile charge MCP_AUTH_TOKEN depuis le fichier restreint. La section hardening limite les actions du processus. NoNewPrivileges empêche l'escalade de privilèges. ProtectSystem=strict rend le système de fichiers en lecture seule sauf pour les chemins listés dans ReadWritePaths. ProtectHome bloque l'accès aux répertoires home des utilisateurs.
Activez et démarrez le service :
sudo systemctl enable --now mcp-notes-server
enable fait démarrer le service au boot. --now le lance immédiatement.
Confirmez le statut :
sudo systemctl status mcp-notes-server
Vous devriez voir active (running). Si le service a échoué, consultez les logs :
journalctl -u mcp-notes-server -n 50 --no-pager
Contrôlez que le serveur répond en local :
TOKEN=$(sudo grep MCP_AUTH_TOKEN /etc/mcp-notes-server/env | cut -d= -f2)
curl -s http://127.0.0.1:3000/health
Cela devrait retourner {"status":"ok"}.
Comment faire tourner un serveur MCP derrière Nginx avec TLS ?
Nginx termine le TLS et proxifie les requêtes vers le serveur MCP. Le serveur MCP ne gère jamais le TLS directement. C'est le schéma standard pour les déploiements Node.js en production.
Configurer Nginx comme reverse proxy
Installer Nginx et Certbot
sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx
Configurer le server block Nginx
sudo tee /etc/nginx/sites-available/mcp.example.com.conf > /dev/null << 'NGINX'
server {
listen 80;
listen [::]:80;
server_name mcp.example.com;
# Certbot will add the redirect to HTTPS
location / {
return 444;
}
}
NGINX
Remplacez mcp.example.com par votre domaine réel.
Activez le site et obtenez un certificat TLS :
sudo ln -s /etc/nginx/sites-available/mcp.example.com.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d mcp.example.com
Certbot modifie la configuration pour ajouter les paramètres TLS et une redirection HTTP vers HTTPS. Mettez maintenant à jour la configuration pour ajouter le reverse proxy vers l'endpoint MCP :
sudo tee /etc/nginx/sites-available/mcp.example.com.conf > /dev/null << 'NGINX'
server {
listen 80;
listen [::]:80;
server_name mcp.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name mcp.example.com;
ssl_certificate /etc/letsencrypt/live/mcp.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mcp.example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Hide Nginx version
server_tokens off;
# MCP endpoint
location /mcp {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
# Required for Streamable HTTP / SSE responses
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding off;
# Keep connection open for streaming responses
proxy_set_header Connection "";
# Extended timeouts for long-running tool calls
proxy_read_timeout 300s;
proxy_send_timeout 300s;
# Forward client info
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Pass through Authorization header
proxy_set_header Authorization $http_authorization;
}
# Health check (no auth required)
location /health {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
}
# Block everything else
location / {
return 444;
}
}
NGINX
Les directives clés pour la compatibilité MCP :
proxy_buffering offempêche Nginx de mettre en tampon les réponses SSE. Sans cela, les réponses en streaming restent bloquées jusqu'à la fermeture de la connexion.proxy_cache offgarantit qu'aucune réponse dynamique n'est mise en cache.chunked_transfer_encoding offévite les problèmes de chunking avec les flux SSE.Connection ""maintient la connexion ouverte sans déclencher de comportement d'upgrade WebSocket.proxy_read_timeout 300sautorise les appels de tools à prendre jusqu'à 5 minutes. Le défaut de 60s est trop court pour des opérations longues.
Configurer Let's Encrypt SSL/TLS pour Nginx sur Debian 12 et Ubuntu 24.04
Testez et rechargez :
sudo nginx -t
sudo systemctl reload nginx
Vérifiez depuis votre machine locale (pas le serveur) :
curl -s https://mcp.example.com/health
Cela devrait retourner {"status":"ok"}. Si c'est le cas, Nginx proxifie correctement vers votre serveur MCP avec TLS.
Règles de pare-feu
Bloquez l'accès direct au port 3000 depuis l'extérieur. Seul Nginx (sur localhost) doit atteindre le serveur MCP :
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Assurez-vous que le port 3000 n'est pas accessible depuis l'extérieur :
# From your local machine, this should time out or be refused:
curl -s --connect-timeout 5 http://YOUR_VPS_IP:3000/health
La connexion devrait échouer. Votre serveur MCP n'est accessible que via Nginx sur le port 443.
Sécuriser votre serveur d'agents IA : sandboxing, pare-feu et supervision
Comment connecter des clients MCP à un serveur distant ?
Avec le serveur en fonctionnement derrière Nginx avec TLS, configurez vos clients MCP.
Claude Code
Ajoutez le serveur distant via le CLI :
claude mcp add --transport http \
--header "Authorization: Bearer YOUR_TOKEN_HERE" \
notes-server https://mcp.example.com/mcp
Remplacez YOUR_TOKEN_HERE par le token de /etc/mcp-notes-server/env.
Confirmez la connexion :
claude mcp list
Dans Claude Code, tapez /mcp pour vérifier le statut du serveur. Le notes-server devrait apparaître comme connecté avec les tools search_notes et create_note disponibles.
Exécuter Claude Code sur un VPS : installer, sécuriser et persister les sessions
Claude Desktop
Claude Desktop se connecte aux serveurs MCP distants via l'interface Settings. Allez dans Settings > Connectors et ajoutez un nouveau serveur distant avec l'URL https://mcp.example.com/mcp.
Si vous devez passer le bearer token, vous pouvez aussi le configurer via un fichier .mcp.json local ou la commande CLI claude mcp add montrée ci-dessus et importer le serveur dans Claude Desktop :
claude mcp add-from-claude-desktop
Cursor
Ouvrez les paramètres de Cursor et naviguez vers la configuration MCP. Ajoutez un nouveau serveur dans le fichier mcp.json (ou via l'interface des paramètres Cursor) :
{
"mcpServers": {
"notes-server": {
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_TOKEN_HERE"
}
}
}
}
Cursor tente Streamable HTTP en premier lors de la connexion à une URL, donc aucune configuration de transport supplémentaire n'est nécessaire.
Vérifier la connexion de bout en bout
Depuis n'importe quel client connecté, demandez à l'IA de :
- Créer une note : « Crée une note intitulée 'Server Test' avec le contenu 'Connected successfully' »
- La rechercher : « Cherche dans mes notes 'Server Test' »
Si les deux opérations retournent des résultats, la chaîne complète fonctionne : client vers Nginx vers serveur MCP vers SQLite et retour.
Référence des primitives MCP
| Primitive | Fonction | Exemple |
|---|---|---|
| Tools | Fonctions que l'IA peut appeler avec des entrées structurées | search_notes, create_note |
| Resources | Données en lecture seule que l'IA peut consulter | listing de notes notes://all |
| Prompts | Templates pré-écrits pour des tâches courantes | Non utilisé dans ce tutoriel |
Les tools sont la primitive la plus souvent implémentée. Les resources servent à exposer des données de référence sans calcul. Les prompts permettent de créer des templates réutilisables qui guident l'IA à travers des workflows spécifiques.
Protocoles pour agents IA : MCP, A2A et ANP
Quelque chose ne fonctionne pas ?
Le serveur ne démarre pas : Vérifiez le journal pour les erreurs :
journalctl -u mcp-notes-server -n 50 --no-pager
Causes fréquentes : variable d'environnement MCP_AUTH_TOKEN manquante, permissions incorrectes sur notes.db, version de Node.js trop ancienne.
Nginx retourne 502 Bad Gateway : Le serveur MCP ne tourne pas ou n'écoute pas sur le port 3000. Vérifiez :
sudo systemctl status mcp-notes-server
curl -s http://127.0.0.1:3000/health
Le client reçoit 401 Unauthorized : Le token dans la configuration du client ne correspond pas au token sur le serveur. Vérifiez :
sudo cat /etc/mcp-notes-server/env
Les réponses en streaming expirent : Augmentez proxy_read_timeout dans la configuration Nginx. Les 300s par défaut couvrent la plupart des cas, mais des tools longs peuvent nécessiter plus.
Erreurs de certificat : Vérifiez que le certificat est valide et couvre votre domaine :
sudo certbot certificates
Si le certificat a expiré, renouvelez-le :
sudo certbot renew
Erreurs de base de données verrouillée : Le mode WAL de SQLite gère bien les lectures concurrentes, mais les écritures concurrentes peuvent entrer en conflit. Pour les serveurs à fort trafic, envisagez PostgreSQL.
Permission refusée sur notes.db : L'utilisateur mcpserver a besoin d'un accès en écriture au répertoire de travail pour SQLite. Vérifiez :
ls -la /opt/mcp-notes-server/notes.db
Le fichier doit appartenir à mcpserver:mcpserver. S'il a été créé par root lors des tests, corrigez :
sudo chown mcpserver:mcpserver /opt/mcp-notes-server/notes.db
sudo chmod 640 /opt/mcp-notes-server/notes.db
Le client affiche « connection refused » ou « timeout » : Vérifiez que votre enregistrement DNS A pointe vers l'IP du VPS et que les ports 80 et 443 sont ouverts dans le pare-feu :
sudo ufw status
dig +short mcp.example.com
La sortie de dig doit afficher l'adresse IP de votre VPS. Si ce n'est pas le cas, mettez à jour vos enregistrements DNS et attendez la propagation.
Prochaines étapes
Votre serveur MCP est en ligne et sécurisé. Pistes pour la suite :
- Ajouter des tools qui se connectent à vos bases de données, API ou systèmes de fichiers
- Implémenter OAuth 2.1 au lieu des bearer tokens pour un accès multi-utilisateurs
- Ajouter du rate limiting dans Express ou Nginx pour protéger contre les abus
- Mettre en place du monitoring avec
journalctl -u mcp-notes-server -fet de l'alerting - Déployer plusieurs serveurs MCP derrière la même instance Nginx sur des chemins différents
La documentation officielle du SDK MCP couvre les patterns avancés, y compris les sessions stateful, le reporting de progression et les schémas de sortie structurés.
Prêt à essayer ?
Construisez et deployez des outils IA sur votre propre VPS. →