Aller au contenu principal
Leçon 7 sur 14 · MCP pour Développeurs — Serveurs et Intégrations

Configurer un Serveur SSE Distant

Leçon 7 sur 14 Mis à jour le 3 novembre 2026 Développeur
Sur cette page
  1. Passer du local au distant
  2. Le serveur ne change presque pas
  3. Obtenir une URL publique avec ngrok
  4. Connecter un client Python
  5. Plusieurs serveurs sur un seul hôte
  6. Points clés à retenir

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. Complément du 3 novembre : le résultat d’un run_async se lit dans result.output_as_text ; le SDK mistralai 3.7.0 n’a pas d’attribut output.

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) : MCPServer remplace FastMCP, 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’extra mistralai[agents] demande mcp>=2.2.0,<3.0. Sources : What’s new in v2 · Guide de migration · Deploy & scale.

Passer du local au distant

Jusqu’ici, votre serveur MCP vivait sur votre machine et communiquait par STDIO. Ce mode est idéal pour développer, mais il enferme votre travail : personne d’autre que vous ne peut l’utiliser, et Vibe de Mistral ne pourra jamais lancer un processus sur votre poste. Pour franchir cette frontière, il faut exposer le serveur en HTTP.

Le changement est plus léger qu’on ne l’imagine. Un serveur MCP distant publie ses tools sur une URL ; le client — Vibe, un SDK, un IDE — s’y connecte par le réseau au lieu de démarrer un processus. Le code de vos tools, lui, ne bouge pas.

Le serveur ne change presque pas

MCPServer prend en charge le transport Streamable HTTP nativement. Le fichier ci-dessous est écrit exactement comme un serveur local : mêmes décorateurs, mêmes docstrings, mêmes signatures typées.

# serveur_distant.py
"""Serveur MCP distant avec transport HTTP."""

from mcp.server.mcpserver import MCPServer

# Le serveur est le même qu'en local
app = MCPServer("Serveur Distant Démo")

@app.tool()
def analyze_text(text: str, language: str = "fr") -> str:
    """Analyse un texte et retourne des statistiques.

    Args:
        text: Le texte à analyser
        language: Code langue (fr, en, es). Défaut : fr

    Returns:
        Statistiques du texte : nombre de mots, caractères, phrases
    """
    words = len(text.split())
    chars = len(text)
    sentences = text.count(".") + text.count("!") + text.count("?")
    return (
        f"Langue : {language}\n"
        f"Mots : {words}\n"
        f"Caractères : {chars}\n"
        f"Phrases : {sentences}"
    )

@app.tool()
def summarize_key_points(text: str, max_points: int = 5) -> str:
    """Extrait les points clés d'un texte (version simplifiée).

    Args:
        text: Le texte source
        max_points: Nombre maximum de points à extraire (1-10)

    Returns:
        Liste des points clés identifiés
    """
    sentences = [s.strip() for s in text.split(".") if len(s.strip()) > 20]
    points = sentences[:max_points]
    return "\n".join(f"- {p}" for p in points) if points else "Aucun point clé identifié."

Ce qui change tient en un bloc de lancement, ajouté à la fin du fichier : le transport HTTP, le port, et la liste des noms d’hôte que le serveur accepte.

import os
from mcp.server.transport_security import TransportSecuritySettings

if __name__ == "__main__":
    # Nom d'hôte public, par exemple celui que ngrok vous attribue (sans https://)
    hote_public = os.environ.get("MCP_PUBLIC_HOST")
    hotes = ["localhost:*", "127.0.0.1:*"]
    if hote_public:
        hotes += [hote_public, f"{hote_public}:*"]
    app.run(
        transport="streamable-http",
        port=8000,
        transport_security=TransportSecuritySettings(allowed_hosts=hotes),
    )
python serveur_distant.py

Votre serveur écoute désormais sur http://localhost:8000/mcp. La liste allowed_hosts n’est pas un détail : par défaut, le SDK v2 n’accepte que les requêtes adressées à localhost ou 127.0.0.1, une protection contre le DNS rebinding. Derrière un tunnel ou un vrai nom de domaine, toute requête reçoit sinon une erreur 421 Invalid Host header, que le client affiche comme une simple erreur de transport ; seul le journal du serveur en donne la raison.

Obtenir une URL publique avec ngrok

Pour tester votre serveur depuis Vibe sans passer par un vrai déploiement, ngrok crée un tunnel entre une URL publique et votre port local. C’est l’outil qui raccourcit le plus la boucle de développement : vous modifiez un tool, vous relancez, et le connecteur distant voit immédiatement la nouvelle version.

# Installer l'agent ngrok depuis https://ngrok.com/download, puis l'authentifier (une seule fois)
ngrok config add-authtoken VOTRE_JETON_NGROK

# Exposer le port 8000
ngrok http 8000

ngrok vous attribue une adresse du type https://abc123.ngrok-free.app. Relancez le serveur en déclarant ce nom d’hôte (MCP_PUBLIC_HOST=abc123.ngrok-free.app python serveur_distant.py). Votre endpoint MCP devient celui-ci, en ajoutant simplement le chemin /mcp :

https://abc123.ngrok-free.app/mcp

Cette URL s’ajoute telle quelle dans Vibe de Mistral comme connecteur custom. Souvenez-vous qu’elle est temporaire et qu’elle expose votre machine : ne laissez pas un tunnel ouvert sur un serveur qui touche à des données réelles.

Connecter un client Python

Côté client, la structure du code reste celle de la leçon sur le RunContext. Seule la classe de connexion diffère : MCPClientSSE avec SSEServerParams remplace le duo STDIO, et vous fournissez une URL plutôt qu’une commande.

# client_distant.py
import asyncio
from mistralai.client import Mistral
from mistralai.extra.run.context import RunContext
from mistralai.extra.mcp.streamable_http import (
    MCPClientStreamableHTTP,
    StreamableHTTPServerParams,
)

async def main():
    client = Mistral(api_key="VOTRE_CLE_API")

    agent = client.beta.agents.create(
        model="mistral-medium-latest",
        name="assistant-distant",
        instructions="Vous utilisez des outils distants pour analyser du texte.",
    )

    # Connexion au serveur distant
    server_url = "https://abc123.ngrok-free.app/mcp"
    mcp_client = MCPClientStreamableHTTP(
        params=StreamableHTTPServerParams(
            url=server_url,
            timeout=100,  # Timeout en secondes
        )
    )

    async with RunContext(
        agent_id=agent.id,
        continue_on_fn_error=True,
    ) as run_ctx:
        await run_ctx.register_mcp_client(mcp_client=mcp_client)

        result = await client.beta.conversations.run_async(
            run_ctx=run_ctx,
            inputs="Analyse ce texte : Le MCP est un protocole ouvert.",
        )
        print(result.output_as_text)

asyncio.run(main())

Le paramètre timeout mérite un instant de réflexion. En STDIO, l’appel était quasi instantané ; sur le réseau, un tool qui interroge une API tierce ou traite un gros document peut prendre plusieurs dizaines de secondes. Un timeout trop court se manifeste par des erreurs intermittentes et difficiles à reproduire, généralement sur les requêtes les plus utiles.

Quand le serveur attend des en-têtes particuliers — un jeton d’API, une clé de routage, une contrainte CORS —, vous les passez dans headers :

mcp_client = MCPClientStreamableHTTP(
    params=StreamableHTTPServerParams(
        url="https://mon-serveur.example.com/mcp",
        timeout=100,
        headers={
            "Authorization": "Bearer mon_token_api",
            "X-Custom-Header": "valeur",
        },
    )
)

Plusieurs serveurs sur un seul hôte

La leçon 3 recommandait des serveurs focalisés plutôt qu’un catalogue fourre-tout. Cette recommandation ne vous condamne pas à louer une machine par serveur : avec FastAPI, vous montez plusieurs serveurs MCP sur des routes distinctes d’un même hôte.

# server.py — Plusieurs serveurs MCP sur un seul hôte
from contextlib import asynccontextmanager

from fastapi import FastAPI
from mcp.server.mcpserver import MCPServer
from mcp.server.transport_security import TransportSecuritySettings

# Serveur MCP pour l'analyse de texte
text_mcp = MCPServer("Text Analysis")

@text_mcp.tool()
def analyze(text: str) -> str:
    """Analyse un texte."""
    return f"Mots: {len(text.split())}"

# Serveur MCP pour les calculs
math_mcp = MCPServer("Math Tools")

@math_mcp.tool()
def calculate(expression: str) -> str:
    """Évalue une expression mathématique."""
    return str(eval(expression))  # Attention : eval en prod !

# Chaque serveur MCP produit une application ASGI autonome,
# qui doit connaître le nom d'hôte sous lequel elle est servie
securite = TransportSecuritySettings(allowed_hosts=["mon-serveur.com", "mon-serveur.com:*"])
text_app = text_mcp.streamable_http_app(transport_security=securite)
math_app = math_mcp.streamable_http_app(transport_security=securite)

# Lifespan combiné : chaque serveur doit démarrer son gestionnaire de sessions
@asynccontextmanager
async def lifespan(app: FastAPI):
    async with text_mcp.session_manager.run(), math_mcp.session_manager.run():
        yield

api = FastAPI(lifespan=lifespan)
api.mount("/text", text_app)
api.mount("/math", math_app)

Vous obtenez deux endpoints indépendants, https://mon-serveur.com/text/mcp pour les outils d’analyse de texte et https://mon-serveur.com/math/mcp pour les outils mathématiques, que l’on ajoute séparément dans Vibe. Le point à ne pas manquer est le lifespan : chaque serveur MCP possède un gestionnaire de sessions qu’il faut démarrer explicitement, et si vous montez les applications sans transmettre ce lifespan à FastAPI, le serveur répond mais chaque appel d’outil échoue sur une erreur de tâche non initialisée. Un utilisateur qui n’a besoin que du calcul n’encombrera pas son contexte avec les tools de texte. Le commentaire sur eval n’est pas une plaisanterie : sur un endpoint public, cette ligne exécute n’importe quel code envoyé par l’appelant — c’est un exemple pédagogique, jamais un patron de production.

Un réflexe pour terminer : avant d’ajouter votre URL dans un chat, repassez-la à l’Inspector. Un endpoint distant ajoute des sources de panne que le local ignorait — tunnel fermé, en-tête manquant, port occupé — et il vaut mieux les découvrir en dehors d’une conversation.

Points clés à retenir

  • Un serveur MCP distant expose ses tools via HTTP sur un endpoint /mcp
  • ngrok permet d’obtenir une URL publique pour le développement
  • MCPClientStreamableHTTP avec StreamableHTTPServerParams connecte le client au serveur distant (MCPClientSSE ne sert plus qu’aux anciens endpoints /sse)
  • Le paramètre timeout est important pour les serveurs lents
  • Vous pouvez monter plusieurs serveurs MCP sur un même hôte FastAPI, à condition de transmettre leur lifespan
  • Testez toujours avec l’Inspector avant d’intégrer dans un chat