Archive d’étiquettes pour : mcp python sdk

Construction d'un serveur MCP personnalisé visualisée par des modules empilés et un terminal de code

Créer serveur MCP est devenu en 2026 une compétence à part entière du développement assisté par IA. Chaque équipe qui industrialise Claude Code, Cursor ou un agent maison finit par exposer ses propres outils internes via le Model Context Protocol, plutôt que de réécrire des connecteurs ad hoc à chaque nouveau client. Ce guide pilier conduit pas à pas du tool de calculatrice trivial au serveur métier complet, en passant par l’authentification d’API privée. Trois exemples gradués, tous testés sur Claude Code et Cursor pour démontrer la portabilité, et deux extensions importantes : MCP avec Ollama pour un workflow 100 % local, MCP exposé en node n8n pour l’orchestration visuelle d’agents.

Construction d'un serveur MCP personnalisé visualisée par des modules empilés et un terminal de code

Pourquoi créer son propre serveur MCP

Le Model Context Protocol (MCP), publié par Anthropic fin 2024, standardise la communication entre un agent IA et les outils qu’il consomme. Si l’introduction au protocole reste floue pour vous, commencez par MCP expliqué simplement (introduction). La question pratique qui se pose ensuite est : pourquoi prendre le temps d’écrire un serveur soi-même quand des dizaines existent déjà ?

  • Exposer un outil métier interne : votre CRM maison, votre wiki d’entreprise, votre pipeline de données. Personne d’autre que vous ne le fera.
  • Encapsuler une logique propriétaire : un calcul tarifaire, une règle de validation, un workflow signé qui ne doit jamais quitter votre infrastructure.
  • Mutualiser un connecteur sur plusieurs clients : un serveur écrit une fois fonctionne avec Claude Code, Cursor, Zed et tout autre client compatible. C’est l’argument de capitalisation.
  • Contrôler la surface d’audit : votre serveur log ce qu’il veut, applique vos politiques d’autorisation, garde la main sur les secrets.

Un serveur MCP s’écrit en quelques heures pour un cas simple, en deux à trois jours pour un cas métier sérieux. L’investissement est limité, le levier est durable.

Les briques d’un serveur MCP

Composants internes d'un serveur MCP représentés par des modules logiciels distincts à l'écran

Avant le code, l’architecture. Un serveur MCP est composé de quatre éléments invariants : les primitives qu’il expose, le transport qui le relie au client, les schémas qui décrivent ses entrées-sorties, et le moteur JSON-RPC qui orchestre les messages.

Tools, resources, prompts

Trois primitives à connaître par cœur. Les tools sont des fonctions exécutables avec effet : créer une issue, requêter une base, appeler une API. Les resources sont des données identifiées par URI que l’agent peut lire à la demande. Les prompts sont des modèles de conversation que l’utilisateur peut déclencher pour orienter l’agent. Un serveur peut exposer une, deux ou les trois.

Transport stdio vs HTTP+SSE

Le transport est le canal physique d’échange. stdio est idéal pour un serveur local, lancé en sous-processus par le client. HTTP+SSE (Server-Sent Events) convient à un serveur partagé en équipe ou hébergé en cloud. Une bonne pratique en 2026 consiste à supporter les deux dans la même base de code, ce que les SDK officiels permettent par configuration.

Schémas JSON Schema et types

Chaque tool doit déclarer son schéma d’entrée en JSON Schema. C’est ce qui permet au modèle de comprendre ce qu’il doit fournir et de générer un appel valide. Un schéma trop large produit des erreurs silencieuses, un schéma précis guide le modèle vers le bon usage. Investir cinq minutes sur le schéma économise une heure de débogage.

Voici l’état des SDK officiels et communautaires en 2026.

SDKMaturitéCas d’usage recommandéMaintenance
TypeScriptStableServeur Node, intégration JS, distribution npmOfficielle Anthropic
PythonStableData, ML, intégrations scientifiques, scriptingOfficielle Anthropic
GoBêtaServeur HTTP haute perf, binaire portableCommunauté
RustBêtaPerformance critique, embarquéCommunauté
C#/.NETBêtaIntégration legacy entrepriseCommunauté

Pour démarrer, le choix raisonnable est TypeScript (si votre équipe vit côté JS) ou Python (si elle vit côté data). Les deux sont documentés sur le SDK TypeScript officiel et le SDK Python officiel.

Exemple 1 — Le tool « calculatrice » en 30 lignes

Premier exemple, intentionnellement trivial : exposer une fonction somme à l’agent. L’objectif est de voir l’ensemble du cycle, pas de produire de la valeur métier.

SDK TypeScript (référence)

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

const server = new Server(
  { name: "calc-server", version: "1.0.0" },
  { capabilities: { tools: {} } }
);

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [{
    name: "add",
    description: "Additionne deux nombres entiers ou décimaux.",
    inputSchema: {
      type: "object",
      properties: {
        a: { type: "number", description: "Premier opérande" },
        b: { type: "number", description: "Deuxième opérande" }
      },
      required: ["a", "b"]
    }
  }]
}));

server.setRequestHandler(CallToolRequestSchema, async (req) => {
  if (req.params.name === "add") {
    const { a, b } = req.params.arguments as { a: number; b: number };
    return { content: [{ type: "text", text: String(a + b) }] };
  }
  throw new Error("Tool inconnu");
});

const transport = new StdioServerTransport();
await server.connect(transport);

SDK Python (équivalent)

from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
import asyncio

server = Server("calc-server")

@server.list_tools()
async def list_tools() -> list[Tool]:
    return [Tool(
        name="add",
        description="Additionne deux nombres entiers ou décimaux.",
        inputSchema={
            "type": "object",
            "properties": {
                "a": {"type": "number"},
                "b": {"type": "number"},
            },
            "required": ["a", "b"],
        },
    )]

@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    if name == "add":
        return [TextContent(type="text", text=str(arguments["a"] + arguments["b"]))]
    raise ValueError("Tool inconnu")

async def main():
    async with stdio_server() as (read, write):
        await server.run(read, write, server.create_initialization_options())

asyncio.run(main())

Tester avec Claude Code

L’enregistrement côté client se fait via le fichier de configuration MCP de Claude Code, en pointant la commande qui démarre le serveur (node calc-server.js ou python calc_server.py). Au prochain démarrage, l’agent expose le tool add et l’appelle quand le besoin se présente. Sur Cursor, la procédure est identique : ajout dans le panneau MCP, redémarrage de la session, le tool est disponible. C’est cette portabilité qui justifie l’investissement.

Exemple 2 — Tool authentifié sur API privée

Deuxième exemple, plus réaliste : un tool qui interroge une API privée nécessitant un jeton d’authentification. C’est le cas typique d’un connecteur sur un CRM ou un ERP interne.

Variables d’env, secrets

Le jeton ne doit jamais être codé en dur. La pratique standard consiste à le lire depuis une variable d’environnement (process.env.API_TOKEN en Node, os.environ["API_TOKEN"] en Python). Si le serveur tourne en stdio, le client peut transmettre les variables d’environnement à la déclaration du serveur. Si le serveur tourne en HTTP, vous gérez les secrets via votre orchestrateur (Doppler, Vault, ou simple .env protégé).

const API_TOKEN = process.env.API_TOKEN;
if (!API_TOKEN) throw new Error("API_TOKEN manquant");

server.setRequestHandler(CallToolRequestSchema, async (req) => {
  if (req.params.name === "search_crm") {
    const { query } = req.params.arguments as { query: string };
    const res = await fetch(`https://api-interne/search?q=${encodeURIComponent(query)}`, {
      headers: { "Authorization": `Bearer ${API_TOKEN}` }
    });
    if (!res.ok) {
      return { content: [{ type: "text", text: `Erreur API: ${res.status}` }], isError: true };
    }
    const data = await res.json();
    return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
  }
  throw new Error("Tool inconnu");
});

Gestion des erreurs proprement

Trois règles utiles. Renvoyer isError: true dans la réponse plutôt que de lever une exception silencieuse permet à l’agent de comprendre l’échec et de tenter une autre stratégie. Logger côté serveur (stderr en stdio, fichier en HTTP) trace ce qui s’est passé sans polluer le canal. Ne jamais renvoyer le secret dans un message d’erreur : ce qui sort du tool peut finir dans une transcription.

Exemple 3 — Serveur complet avec resources

Troisième exemple : un serveur qui combine tools (recherche), resources (lecture de fiches), et prompts (modèle d’audit). Cas d’usage : exposer une base de connaissances interne à l’agent.

Cas métier : recherche dans une base interne

Le serveur expose : un tool search_kb(query) qui retourne une liste d’identifiants pertinents, des resources kb://article/{id} que l’agent peut ouvrir pour lire le contenu complet, et un prompt audit_doc qui injecte le bon contexte pour faire la revue d’un article. Cette répartition est volontaire : l’agent décide quoi consulter, quand, et avec quelle posture.

Resources dynamiques + prompts contextualisés

server.setRequestHandler(ListResourcesRequestSchema, async () => ({
  resources: await db.listArticles().then(arts => arts.map(a => ({
    uri: `kb://article/${a.id}`,
    name: a.title,
    mimeType: "text/markdown"
  })))
}));

server.setRequestHandler(ReadResourceRequestSchema, async (req) => {
  const id = req.params.uri.replace("kb://article/", "");
  const article = await db.getArticle(id);
  return { contents: [{ uri: req.params.uri, mimeType: "text/markdown", text: article.body }] };
});

server.setRequestHandler(GetPromptRequestSchema, async (req) => {
  if (req.params.name === "audit_doc") {
    return {
      messages: [{
        role: "user",
        content: { type: "text", text:
          "Vous êtes auditeur documentaire. Évaluez l'article fourni sur trois axes : exactitude, fraîcheur, actionnabilité. Renvoyez un verdict en trois lignes."
        }
      }]
    };
  }
  throw new Error("Prompt inconnu");
});

Cet exemple condense la logique d’un serveur métier mature : la recherche oriente, les resources nourrissent, les prompts cadrent l’analyse. Vous pouvez ajouter pagination, cache, journalisation sans changer l’architecture.

Déploiement et portabilité

Un serveur MCP n’est intéressant que s’il sort du laptop de son auteur. Voici les quatre cibles de déploiement à connaître en 2026.

Local (stdio) vs distant (HTTP+SSE)

Local en stdio : zéro infrastructure, l’utilisateur installe via npx ou pip, le client lance le sous-processus. Idéal pour un usage personnel ou une distribution open source. Distant en HTTP+SSE : un seul serveur partagé en équipe, gestion centralisée des secrets et des logs, scalable. Idéal pour un cas métier d’entreprise.

Tester sur Cursor et autres clients

La portabilité est l’argument fondamental de MCP. Avant de figer votre serveur, testez-le sur au moins deux clients : Claude Code et Cursor sont les plus matures. Les divergences éventuelles (gestion des erreurs, support des resources, prompts utilisateurs) se révèlent à ce moment-là. Voir aussi workflow Git d’équipe avec Claude Code pour intégrer le serveur dans le cycle de revue.

Brancher un serveur MCP sur Ollama (LLM local + tools personnalisés)

Pour le code sensible ou l’infrastructure isolée, brancher un serveur MCP sur un modèle Ollama local élimine toute fuite vers un fournisseur cloud. Plusieurs clients open source font le pont : ils consomment l’API Ollama d’un côté, parlent MCP de l’autre, traduisent les tool calls entre les deux formats. Configuration type :

{
  "llm": {
    "provider": "ollama",
    "model": "qwen3-coder:30b",
    "baseUrl": "http://localhost:11434"
  },
  "mcpServers": {
    "kb-internal": {
      "command": "node",
      "args": ["./kb-server/dist/index.js"],
      "env": { "API_TOKEN": "..." }
    }
  }
}

Le bénéfice est double : le code source et les requêtes ne quittent jamais la machine, et votre serveur MCP métier reste réutilisable le jour où vous repassez sur Claude. Le sujet est traité plus largement dans brancher MCP sur Ollama et dans notre pilier stack IA locale complète (pilier).

Exposer un serveur MCP comme node n8n pour l’orchestration d’agents

n8n est devenu en 2026 un orchestrateur d’agents IA visuels populaire chez les équipes ops et automation. Exposer votre serveur MCP comme node custom n8n permet d’utiliser vos tools dans des workflows déclenchés par événement (webhook, cron, message). Schéma minimal : un node n8n « MCP Tool Call » prend en entrée le nom du tool et les arguments, appelle le serveur MCP local ou distant, renvoie le résultat dans le flux. Extrait de configuration côté n8n :

{
  "node": "MCP Tool Call",
  "parameters": {
    "server": "kb-internal",
    "transport": "http",
    "endpoint": "https://mcp-internal.example.com/sse",
    "tool": "search_kb",
    "arguments": "={{ { query: $json.user_query } }}"
  }
}

Vous obtenez ainsi une orchestration visuelle des outils MCP que vous avez écrits, sans dupliquer la logique métier dans n8n. Pour aller plus loin sur l’orchestration : exposer un MCP en node n8n et notre panorama agents IA 2026.

Bonnes pratiques (logs, observabilité, sécurité)

Un serveur MCP en production demande la même rigueur qu’un microservice. Cinq règles à appliquer dès le premier déploiement.

  • Logger systématiquement les appels : tool, arguments anonymisés, durée, code de retour. Sans cette traçabilité, impossible d’auditer ce que les agents ont fait.
  • Limiter le rayon d’action : un tool de production ne doit faire qu’une chose. create_user ne doit pas pouvoir devenir delete_database par contournement de schéma.
  • Versionner le serveur : changer la signature d’un tool casse tous les agents qui l’utilisent. Adopter le versioning sémantique évite la mauvaise surprise.
  • Authentifier le client si distant : un serveur HTTP exposé sans auth est une porte ouverte. Token, mTLS, ou intégration SSO selon le contexte.
  • Tester en intégration : un test qui démarre le serveur, lance un client, exécute trois tools et vérifie les réponses. Indispensable avant chaque release. Le guide Claude Code (pilier) détaille les patterns d’intégration sur ce point.

L’observabilité reste le talon d’Achille des serveurs MCP en 2026. La spécification a anticipé le sujet via les notifications de progression et les logs structurés, mais les outils tiers (collecteurs OpenTelemetry, dashboards Grafana, alerteurs PagerDuty) ne sont pas encore standardisés. Une instrumentation maison couvre généralement le besoin : compter les appels, mesurer les latences, alerter sur les erreurs récurrentes. Voir aussi le site officiel modelcontextprotocol.io pour les évolutions de spécification.

Foire aux questions sur la création d’un serveur MCP

Comment créer un serveur MCP en 2026 ?

Choisir un SDK officiel (TypeScript ou Python), définir les tools que vous voulez exposer avec leurs schémas JSON, implémenter les handlers, choisir un transport (stdio pour usage local, HTTP+SSE pour usage partagé). Tester sur Claude Code et Cursor pour valider la portabilité, puis déployer selon votre cible. Un serveur simple se livre en quelques heures, un cas métier en deux à trois jours.

Quel SDK choisir : TypeScript ou Python ?

Les deux SDK sont officiels, stables et équivalents en couverture. Le critère dépend de votre stack existante. TypeScript si votre équipe vit côté Node ou navigateur, distribution npm immédiate. Python si vous intégrez avec de la data ou du machine learning, ou si vos opérations préfèrent ce langage. Évitez de mélanger les deux dans un même projet sauf nécessité claire.

Comment authentifier un serveur MCP qui expose une API privée ?

Lire le jeton depuis une variable d’environnement, jamais en dur dans le code. En transport stdio, le client peut transmettre les variables au lancement du serveur. En transport HTTP, gérer les secrets via votre orchestrateur ou un vault dédié. Côté API distante, utiliser Authorization: Bearer et journaliser les codes de retour pour faciliter le diagnostic.

Peut-on utiliser un serveur MCP avec Ollama au lieu de Claude ?

Oui, plusieurs clients open source font le pont entre l’API Ollama et le protocole MCP. La configuration consiste à pointer le client vers votre instance Ollama locale et à déclarer les serveurs MCP comme on le ferait avec Claude Code. Le bénéfice : vos tools métier restent réutilisables sans dépendre d’un fournisseur cloud, ce qui est précieux pour le code sensible ou les environnements isolés.

Comment exposer un serveur MCP comme node n8n ?

n8n propose désormais un node MCP capable d’appeler un serveur en HTTP+SSE ou en stdio. Vous configurez l’endpoint du serveur, le nom du tool à invoquer, et la mappe d’arguments depuis les données du flux. Le résultat alimente la suite du workflow. Cela permet d’orchestrer visuellement des agents qui utilisent vos tools métier sans dupliquer la logique.

Vous avez un outil interne, une API privée ou un workflow métier à exposer en MCP ? Nous prototypons un serveur opérationnel et portable en 2 à 3 jours, testé sur Claude Code et Cursor, livré avec sa documentation. Parlons-en chez WebCreatid.