Déployer un Serveur MCP en Production
Sur cette page
Mise à jour du 2 novembre 2026 — Le Chat devient Vibe. Depuis le 28 mai 2026, Le Chat s’appelle Vibe (toujours sur chat.mistral.ai) : un seul agent pour le travail et le code, avec vos conversations, réglages et abonnements repris. L’ancienne expérience Le Chat reste accessible dans le mode Chat ; dans le mode Work, les agents sont devenus des skills (invoquées avec
@), les mémoires la base de connaissances et la recherche approfondie la skill Deep Research. Les offres s’appellent désormais Mistral Free, Pro, Team et Enterprise. Cette leçon emploie désormais le nom Vibe ; certains menus décrits ici ont pu changer de nom ou de place.
Mise à jour du 2 novembre 2026 — SDK Python MCP v2. Ce cours suit désormais la version 2 du SDK
mcp(2.3.0 au 2 octobre 2026) :MCPServerremplaceFastMCP, les réglages de transport passent àrun()ou àstreamable_http_app(), et une application exposée sous un vrai nom d’hôte doit déclarer ce nom (transport_security). C’est aussi la version qu’exige le SDK Mistral : l’extramistralai[agents]demandemcp>=2.2.0,<3.0. Sources : What’s new in v2 · Guide de migration · Deploy & scale.
Du prototype au serveur de production
Votre serveur tourne en local et ngrok l’expose au monde le temps d’une démonstration. Le problème apparaît dès que quelqu’un d’autre veut s’en servir : vous fermez votre terminal, l’URL meurt, et tous les connecteurs configurés chez vos collègues tombent en panne. Passer en production, c’est essentiellement obtenir une adresse stable, disponible en permanence, servie en HTTPS. Quatre options y mènent, de la plus immédiate à la plus maîtrisée, et le choix dépend surtout de la sensibilité de vos données et du contrôle que vous voulez garder sur l’infrastructure.
Option 1 : Hugging Face Spaces
Hugging Face Spaces met à disposition des machines virtuelles gratuites, sans GPU, largement suffisantes pour un serveur MCP qui relaie des appels d’API. C’est la voie la plus rapide vers un premier déploiement réel : trois fichiers et un git push.
mon-mcp-space/
├── app.py # Serveur FastAPI + MCP
├── requirements.txt # Dépendances
└── README.md # Metadata du Space
Le fichier app.py reprend exactement la structure vue jusqu’ici, à ceci près que les valeurs sensibles sont lues dans l’environnement — les Secrets HF les y injectent :
# app.py
"""Serveur MCP déployé sur Hugging Face Spaces."""
import os
from contextlib import asynccontextmanager
from fastapi import FastAPI
from mcp.server.mcpserver import MCPServer
from mcp.server.transport_security import TransportSecuritySettings
mcp = MCPServer("Mon Serveur Production")
@mcp.tool()
def hello(name: str) -> str:
"""Salue une personne.
Args:
name: Le prénom de la personne
Returns:
Message de salutation
"""
return f"Bonjour {name} depuis Hugging Face Spaces !"
@asynccontextmanager
async def lifespan(app: FastAPI):
async with mcp.session_manager.run():
yield
# Nom d'hôte du Space, de la forme <utilisateur>-<space>.hf.space
SPACE_HOST = os.environ.get("MCP_PUBLIC_HOST", "localhost")
securite = TransportSecuritySettings(allowed_hosts=[SPACE_HOST, f"{SPACE_HOST}:*"])
api = FastAPI(lifespan=lifespan)
api.mount("/mcp-endpoint", mcp.streamable_http_app(transport_security=securite))
# Pour les variables sensibles, utilisez les Secrets HF
API_KEY = os.environ.get("MY_API_KEY", "")
La particularité de la plateforme tient au README, dont l’en-tête YAML pilote la construction du Space. Le champ app_port doit correspondre au port réellement écouté par votre serveur, faute de quoi le déploiement réussit mais reste inaccessible :
---
title: Mon Serveur MCP
emoji: 🔧
colorFrom: blue
colorTo: green
sdk: docker
app_port: 7860
---
# Créer un Space sur huggingface.co
# Pousser le code
git push
# Le Space se déploie automatiquement
Votre endpoint devient alors https://votre-username-mon-mcp-space.hf.space/mcp-endpoint/mcp, en HTTPS. Une seule configuration reste à faire : déclarer ce nom d’hôte, votre-username-mon-mcp-space.hf.space, dans la variable MCP_PUBLIC_HOST des réglages du Space. Sans elle, le SDK refuse chaque requête avec une erreur 421 Invalid Host header.
Option 2 : Docker
Dès que le serveur touche à des données internes, l’hébergement sur votre propre infrastructure redevient la règle, et Docker en est le format standard. Le Dockerfile tient en quelques instructions, avec l’installation des dépendances placée avant la copie du code pour profiter du cache de couches lors des rebuilds :
FROM python:3.12-slim
WORKDIR /app
# Installer les dépendances
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copier le code
COPY . .
# Exposer le port
EXPOSE 8000
# Lancer le serveur
CMD ["uvicorn", "server:api", "--host", "0.0.0.0", "--port", "8000"]
fastapi>=0.115.0
uvicorn>=0.30.0
mcp>=2.2,<3
httpx>=0.27.0 # seulement si vos outils l'utilisent : le SDK v2 ne l'installe plus
Au lancement, l’option --restart unless-stopped est celle qui distingue un déploiement de production d’un simple essai : sans elle, le premier crash met votre serveur hors ligne jusqu’à ce que quelqu’un s’en aperçoive.
# Build l'image
docker build -t mon-mcp-server .
# Lancer le conteneur
docker run -d \
--name mcp-server \
-p 8000:8000 \
-e MY_API_KEY="secret" \
-e DATABASE_URL="postgresql://..." \
--restart unless-stopped \
mon-mcp-server
Docker Compose rend cette configuration reproductible et y ajoute un health check, que l’orchestrateur utilisera pour détecter un serveur figé — un processus vivant mais qui ne répond plus est le scénario que le simple redémarrage automatique ne couvre pas :
# docker-compose.yml
version: "3.8"
services:
mcp-server:
build: .
ports:
- "8000:8000"
environment:
- MY_API_KEY=${MY_API_KEY}
- DATABASE_URL=${DATABASE_URL}
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/"]
interval: 30s
retries: 3
Options 3 et 4 : déploiements managés
Prefect Horizon (anciennement FastMCP Cloud), la plateforme de l’équipe du framework indépendant FastMCP, supprime l’étape d’infrastructure : vous vous connectez sur horizon.prefect.io avec votre compte GitHub, vous choisissez le dépôt et le fichier du serveur, et la plateforme construit puis publie une URL, avec authentification intégrée. Elle vise les serveurs écrits avec ce framework (pip install fastmcp, from fastmcp import FastMCP), distinct du SDK officiel utilisé dans ce cours ; une offre gratuite existe pour les projets personnels.
Cloudflare Workers vise un autre profil d’usage : le serverless, avec une exécution au plus près de l’utilisateur et donc une latence réduite. Un template dédié amorce le projet :
# Utiliser le template MCP de Cloudflare
npm create cloudflare@latest -- remote-mcp-server-authless --template=cloudflare/ai/demos/remote-mcp-authless
Ces deux options vous dispensent de gérer les certificats et les redémarrages, au prix d’une dépendance à la plateforme et de contraintes d’exécution — un Worker serverless, par exemple, se marie mal avec un serveur stateful.
Sécuriser le déploiement
Le HTTPS n’est pas négociable : Vibe refuse les endpoints en clair, et un token transitant en HTTP est un token compromis. Trois chemins y mènent selon votre hébergement. Un reverse proxy Nginx ou Caddy placé devant votre serveur, avec un certificat Let’s Encrypt, couvre le cas du serveur dédié. Les plateformes cloud natives — Hugging Face, Cloudflare et la plupart des PaaS — fournissent le HTTPS automatiquement. Un tunnel, Cloudflare Tunnel par exemple, expose un serveur resté sur votre réseau interne sans ouvrir de port.
Aucun secret ne doit figurer dans le code. Notez la distinction entre les deux syntaxes ci-dessous : os.environ["MCP_API_TOKEN"] fait échouer le démarrage si la variable manque, ce qui est exactement le comportement souhaité pour un secret obligatoire, tandis que os.environ.get() tolère l’absence pour les valeurs optionnelles.
import os
# Configuration via variables d'environnement
API_TOKEN = os.environ["MCP_API_TOKEN"] # Obligatoire
DATABASE_URL = os.environ.get("DATABASE_URL") # Optionnel
DEBUG = os.environ.get("DEBUG", "false") == "true"
Un serveur public sans limitation de débit finit tôt ou tard saturé, volontairement ou non. Un limiteur par adresse IP suffit dans la plupart des cas :
from fastapi import FastAPI, Request
from slowapi import Limiter, _rate_limit_exceeded_handler
limiter = Limiter(key_func=lambda request: request.client.host)
api = FastAPI()
api.state.limiter = limiter
@api.middleware("http")
async def rate_limit(request: Request, call_next):
# 100 requêtes par minute par IP
...
Voir ce qui se passe
En production, vous n’avez plus votre terminal sous les yeux, et un tool qui échoue une fois sur dix ne se diagnostique qu’avec des traces. Instrumentez au minimum l’entrée, la sortie et la durée de chaque appel :
import logging
import time
logger = logging.getLogger("mcp-server")
@mcp.tool()
async def my_tool(param: str) -> str:
"""Mon tool avec logging."""
start = time.time()
logger.info(f"Tool appelé avec param={param}")
try:
result = await process(param)
duration = time.time() - start
logger.info(f"Tool terminé en {duration:.2f}s")
return result
except Exception as e:
logger.error(f"Erreur dans le tool : {e}")
raise
La mesure de durée n’est pas un luxe : un tool qui met douze secondes à répondre déclenche des timeouts côté client et donne l’impression d’un serveur cassé alors qu’il fonctionne. Avant d’annoncer votre serveur, passez en revue les six points de configuration suivants.
- HTTPS actif et certificat valide
- Variables d’environnement pour tous les secrets
- Logs structurés activés
- Health check endpoint (
/ou/health) - Restart automatique en cas de crash
- Rate limiting configuré
Restent deux vérifications, qu’on saute le plus volontiers et qui pourtant révèlent les vrais problèmes : un test avec MCP Inspector lancé depuis l’extérieur, puis un test depuis Vibe de Mistral. Un serveur qui répond parfaitement depuis votre machine peut être bloqué par un pare-feu ou une configuration CORS dès qu’on l’appelle d’ailleurs.
Points clés à retenir
- Hugging Face Spaces : le plus rapide, gratuit, idéal pour commencer
- Docker : contrôle total, adapté aux serveurs dédiés et au cloud
- Prefect Horizon (ex-FastMCP Cloud) : déploiement depuis GitHub, pour les serveurs écrits avec le framework FastMCP
- Cloudflare Workers : serverless, faible latence, scalable
- Sécurisez avec HTTPS, variables d’environnement, et rate limiting
- Ajoutez du monitoring et des logs pour le debugging en production