Deux SDK, un protocole, des expériences développeur très différentes
Le Model Context Protocol dispose de SDK officiels en Python et en TypeScript, et bien qu'ils implémentent tous deux le même protocole basé sur JSON-RPC, écrire un serveur MCP en Python ressemble à une activité réellement différente d'écrire le même serveur en TypeScript. Les différences vont au-delà de la syntaxe : elles touchent à la façon dont vous structurez la concurrence, à la quantité de code de plomberie que vous écrivez, et à l'allure de votre base de code existante.
Si vous évaluez lequel utiliser pour un nouveau serveur MCP, la décision relève rarement du protocole lui-même. Elle relève de l'écosystème environnant et des motifs que chaque SDK encourage.
Le socle asyncio dans le SDK Python
Le SDK MCP Python est bâti sur asyncio, le runtime asynchrone natif de Python. Chaque gestionnaire d'outil, de ressource et de prompt que vous écrivez est une fonction async def. Ce n'est pas du code de plomberie optionnel ; c'est le modèle d'exécution attendu par le SDK.
import asyncio
from mcp.server import Server
from mcp.server.stdio import stdio_server
app = Server("my-server")
@app.call_tool()
async def handle_tool(name: str, arguments: dict):
result = await some_async_operation(arguments)
return [TextContent(type="text", text=result)]
async def main():
async with stdio_server() as (read, write):
await app.run(read, write, app.create_initialization_options())
asyncio.run(main())L'appel asyncio.run() en bas est le point d'entrée. Le SDK utilise anyio en interne, ce qui veut dire qu'il peut tourner aussi bien au-dessus d'asyncio que de Trio, mais en pratique presque tout le monde utilise asyncio. Cela compte parce que cela signifie que vos gestionnaires d'outils peuvent await des requêtes HTTP, des requêtes en base de données ou des I/O fichier sans bloquer la boucle d'événements.
Comparez cela au SDK TypeScript, qui utilise la boucle d'événements de Node.js et les Promises. Les deux sont non bloquants, mais la version Python exige que vous soyez plus explicite sur votre contexte asynchrone. En TypeScript, on peut souvent s'en sortir en mélangeant code synchrone et asynchrone de manière plus décontractée. En Python, si vous appelez par accident une fonction bloquante à l'intérieur d'un gestionnaire async, vous bloquez l'ensemble du serveur jusqu'au retour de l'appel.
Là où FastMCP change la donne
Le SDK Python de bas niveau exige une bonne dose de cérémonie : enregistrer les gestionnaires, construire les objets de réponse, gérer manuellement le cycle de vie du serveur. FastMCP, désormais intégré au SDK MCP Python officiel depuis la version 1.0, condense l'essentiel de cela en raccourcis basés sur des décorateurs qui ressemblent davantage à l'écriture d'une route Flask qu'à un serveur de protocole.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather-server")
@mcp.tool()
async def get_forecast(city: str, days: int = 3) -> str:
"""Get weather forecast for a city."""
data = await fetch_weather_api(city, days)
return format_forecast(data)
if __name__ == "__main__":
mcp.run()FastMCP infère le schéma d'entrée de l'outil directement à partir de la signature de la fonction et des annotations de type. La docstring devient la description de l'outil que voit le LLM. Vous ne construisez pas manuellement les objets ListToolsResult ou CallToolResult ; FastMCP gère la couche de sérialisation.
C'est un gain de productivité significatif. Un serveur d'outil simple qui prendrait 60 à 80 lignes avec le SDK de bas niveau en prend environ 15 à 20 avec FastMCP. Pour les équipes qui prototypent vite ou qui construisent des outils internes, cette compression compte.
Le SDK TypeScript dispose d'un motif de haut niveau similaire avec server.tool(), mais l'intégration de FastMCP avec le système de types Python, en particulier Pydantic pour la validation d'entrée, lui donne un avantage quand vos outils ont des schémas d'arguments complexes. Vous pouvez utiliser des types Annotated et des validateurs Pydantic directement dans la signature de fonction et FastMCP générera automatiquement le JSON Schema correspondant.
Motifs de concurrence à connaître
Un domaine où le modèle asyncio de Python crée de vraies différences est la gestion des appels d'outils concurrents. Le protocole MCP autorise les clients à envoyer plusieurs requêtes sans attendre l'aboutissement des précédentes. Dans le SDK Python, chaque requête tourne comme coroutine sur la boucle d'événements, donc vous obtenez du multitâche coopératif par défaut.
Si vous avez besoin d'un véritable parallélisme pour du travail à dominante CPU, vous tendrez la main vers asyncio.to_thread() pour décharger sur un pool de threads, ou vers ProcessPoolExecutor pour des calculs plus lourds. C'est de la pratique asyncio standard, mais cela vaut la peine d'y penser dès le départ si votre serveur MCP enveloppe quelque chose comme un modèle de machine learning ou un pipeline de traitement d'images.
import asyncio
from concurrent.futures import ProcessPoolExecutor
executor = ProcessPoolExecutor(max_workers=4)
@mcp.tool()
async def run_model_inference(input_data: str) -> str:
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(executor, cpu_bound_model, input_data)
return resultLe SDK TypeScript gère cela différemment parce que Node.js utilise des worker threads pour le parallélisme CPU. Aucune approche n'est strictement meilleure ; elles reflètent le modèle de concurrence du runtime sous-jacent. Mais si vous pensez déjà en termes asyncio, les motifs Python vous sembleront plus naturels.
Quand Python a plus de sens que TypeScript
La réponse honnête, c'est que pour de nombreux serveurs MCP, l'un ou l'autre SDK fait l'affaire. Mais il existe des situations spécifiques où Python a un avantage clair.
Premièrement, si votre serveur MCP enveloppe des bibliothèques natives Python, il n'y a pas de bonne raison d'utiliser TypeScript. Le calcul scientifique avec NumPy ou Pandas, l'inférence ML avec PyTorch ou Hugging Face Transformers, le traitement de données avec Polars, ou tout ce qui appartient à l'écosystème SciPy, tout cela vit en Python. Écrire un serveur MCP TypeScript qui appelle un sous-processus Python pour utiliser ces bibliothèques, c'est ajouter de la complexité inutile.
Deuxièmement, si votre équipe dispose déjà d'une infrastructure backend Python, partager des helpers d'authentification, des pools de connexions à la base ou des clients d'API internes est bien plus propre quand votre serveur MCP est dans le même langage. La réutilisation de code à travers une base mixte Python/TypeScript est possible, mais lourde en frottements.
Troisièmement, l'intégration Pydantic de FastMCP est réellement utile aux équipes qui se soucient de la validation d'entrée au niveau de l'outil. Quand un LLM passe des arguments mal formés à un outil, les erreurs de validation Pydantic remontent proprement plutôt que de provoquer des défaillances inattendues plus profond dans votre code.
TypeScript tend à l'emporter quand vous construisez des serveurs MCP pour des contextes adjacents au navigateur, quand votre équipe est principalement orientée frontend, ou quand vous vous intégrez étroitement à l'outillage Node.js. Le SDK TypeScript bénéficie également d'un solide soutien dans l'écosystème Claude Desktop, et de nombreux répertoires MCP listent les serveurs TypeScript avec des indicateurs d'adoption supérieurs, en partie parce que l'écosystème y a démarré plus tôt.
Notes pratiques sur le déploiement
Les serveurs MCP Python tournent typiquement comme processus stdio ou comme serveurs HTTP utilisant SSE (Server-Sent Events) pour le transport. FastMCP prend en charge les deux avec un minimum de changement de configuration : mcp.run(transport="stdio") pour le mode processus local ou mcp.run(transport="sse", host="0.0.0.0", port=8000) pour le déploiement réseau.
La gestion des dépendances mérite réflexion dès le début. La situation des paquets en Python est plus fragmentée que celle de Node.js, donc utiliser uv ou poetry pour les fichiers de verrouillage et les environnements virtuels vous épargnera du temps de débogage lors de déploiements vers différentes machines ou différents conteneurs. Le SDK Python MCP lui-même est distribué via PyPI sous le nom mcp, et FastMCP est inclus dans le même paquet à partir de la version 1.0.
Lorsque vous évaluez des serveurs MCP Python sur Skillful.sh, le système de notation de sécurité vérifie les vulnérabilités de dépendances dans le graphe de paquets Python, ce qui peut faire remonter des risques transitifs dans des dépendances de calcul scientifique faciles à manquer manuellement. Cela vaut la peine de l'exécuter avant d'expédier quoi que ce soit en production.
Les deux SDK sont solides. Le choix se ramène à ce que font réellement vos outils et à ce que votre équipe maîtrise déjà bien.
Lectures complémentaires
- Ce que fait réellement le Model Context Protocol
- En quoi les serveurs MCP diffèrent des API traditionnelles
- MCP contre function calling : comprendre les compromis
- Pourquoi les serveurs MCP open source dominent l'écosystème
Parcourez les serveurs MCP sur Skillful.sh. Cherchez plus de 137 000 outils IA sur Skillful.sh.