AI Cert Prep
Saisissez un mot-clé pour rechercher dans la documentation.

Annexes · Claude

Aide-mémoire MCP

Architecture du Model Context Protocol, primitives, transports, cycle de vie, sécurité, écriture de serveurs en Python et TypeScript, et quand utiliser MCP plutôt que ses alternatives.

Architecture

text
┌──────────────── Host (Claude Desktop / Claude Code / your app) ────────────────┐
│ │
│ ┌─────────────┐ 1:1 ┌─────────────┐ ┌─────────────┐ │
│ │ MCP Client │◄──────────►│ MCP Server │ │ MCP Server │ │
│ │ (per server)│ JSON-RPC │ github │ │ postgres │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ▲ transport: stdio transport: Streamable HTTP │
│ │ (local subprocess) (remote, OAuth 2.1) │
│ Claude model ── sees tools/resources/prompts exposed by all servers │
└────────────────────────────────────────────────────────────────────────────────┘
  • Le host embarque un client par serveur ; les clients parlent JSON-RPC 2.0 aux serveurs.
  • Les serveurs exposent des capacités ; le host décide ce que le modèle voit et applique les permissions.

Primitives

PrimitiveContrôlée parCe que c’estExemple
ToolsModèleFonctions appelables avec entrées en JSON Schemacreate_issue, query_db
ResourcesApplicationDonnées en lecture seule adressées par URIfile:///docs/spec.md, db://schema
PromptsUtilisateurModèles de prompt réutilisables avec arguments/summarise-pr
SamplingServeur → clientLe serveur demande au modèle du host de compléter quelque choseRésumé côté serveur
RootsClient → serveurFrontières filesystem/URI dans lesquelles le serveur peut opérerRépertoire de projet
Logging / progressServeur → clientDiagnostics et progression de tâches longuesProgression d’indexation

Cycle de vie

text
client ──initialize (protocolVersion, capabilities, clientInfo)──► server
client ◄──result (capabilities, serverInfo)────────────────────── server
client ──notifications/initialized──────────────────────────────► server
client ──tools/list ──► server client ──resources/list ──► server
client ──tools/call {name, arguments} ──► server ──► result {content[], isError}

La négociation des capacités à initialize indique à chaque partie quelles primitives (tools, resources, prompts, sampling, logging) sont supportées.

Transports

TransportOùAuthNotes
stdioSous-processus localPermissions processus/utilisateurLe plus simple ; défaut de Claude Desktop/Code pour les serveurs locaux
Streamable HTTPServeur distantOAuth 2.1 (PKCE), bearer tokensStandard distant actuel ; supporte les réponses en streaming
HTTP + SSEDistant (ancien)OAuth / tokensRemplacé par Streamable HTTP ; encore rencontré

Écrire un serveur

python
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("orders")
@mcp.tool()
def get_order(order_id: str) -> dict:
"""Look up one order by ID. Use when the user references an order number.
Returns status, eta and items. Read-only."""
order = db.fetch_order(order_id)
if order is None:
raise ValueError(f"not_found: no order {order_id}") # surfaces as isError with message
return order
@mcp.resource("orders://schema")
def schema() -> str:
"""Orders table schema (read-only reference)."""
return open("schema.sql").read()
@mcp.prompt()
def triage(order_id: str) -> str:
return f"Triage order {order_id}: check status, delays and next action."
if __name__ == "__main__":
mcp.run(transport="stdio") # or transport="streamable-http"

Checklist de conception de serveur

  • Un objectif étroit par outil ; 4–8 outils par serveur est typique. Au-delà de ~10 exposés à un agent, appuyez-vous sur la recherche d’outils / defer_loading.
  • Les descriptions énoncent le quoi, le quand, le quand-pas, et la forme de retour.
  • Erreurs structurées (isError: true avec category, retryable, message) — jamais de succès vide.
  • Idempotence pour tout ce qui écrit ; acceptez une clé d’idempotence.
  • Pagination pour les opérations de liste ; plafonnez la taille des pages.
  • Moindre privilège : exposez les outils de lecture par défaut ; placez les outils destructifs derrière des serveurs séparés ou une confirmation.
  • Propagation d’identité : pour les applications multi-utilisateurs, les outils doivent agir en tant qu’utilisateur final (OAuth pour le compte de), pas en tant que super-utilisateur partagé.
  • Traitez la sortie d’outil comme non fiable en aval (injection indirecte).
  • Versionnez le serveur ; ajoutez des outils plutôt que de changer la sémantique.

Se connecter depuis Claude

Terminal window
claude mcp add orders -- python orders_server.py # stdio, local scope
claude mcp add --scope project orders -- python orders_server.py # .mcp.json, shared
claude mcp add --transport http linear https://mcp.linear.app/mcp # remote
/mcp # inspect, authenticate

MCP vs alternatives

BesoinPréférerRaison
Connecteur réutilisable vers un système externe utilisé par plusieurs agents/hostsServeur MCPInterface standard, découvrable, permissions gérées par le host
Fonction ponctuelle dans une seule applicationOutil personnalisé dans la requête APIMoins d’infrastructure
Une procédure/connaissance que Claude doit suivreSkillDivulgation progressive, aucun runtime
Étape scriptée déterministe sans jugement du modèleSimple appel API/CLI dans le codeMoins cher, testable
Deux systèmes autonomes qui négocientProtocole agent-à-agent / couche d’orchestrationMCP est modèle↔outil, pas agent↔agent

Liste rapide de sécurité

RisqueContrôle
Outils trop larges (delete/refund exposés)Les supprimer ; serveurs séparés ; hooks
Injection indirecte via les tool resultsFrontières (XML), traiter comme des données, validation de sortie
Identifiants partagésOAuth par utilisateur ; tokens éphémères ; scopes
Fuite de secretsEnv/gestionnaire de secrets ; jamais dans les prompts, CLAUDE.md ou logs
Serveurs non fiablesAllowlist de serveurs ; épingler les versions ; relire la source
Agence excessiveApprobation humaine pour les actions irréversibles ; permissions.ask

Négociation des capacités (le JSON)

À initialize, chaque partie annonce ce qu’elle supporte. Le host n’expose que les primitives négociées des deux côtés.

json
// client → server
{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {
"protocolVersion": "2025-06-18",
"capabilities": { "roots": { "listChanged": true }, "sampling": {} },
"clientInfo": { "name": "claude-code", "version": "2.1.0" } } }
// server → client
{ "jsonrpc": "2.0", "id": 1, "result": {
"protocolVersion": "2025-06-18",
"capabilities": {
"tools": { "listChanged": true },
"resources": { "subscribe": true, "listChanged": true },
"prompts": { "listChanged": true },
"logging": {} },
"serverInfo": { "name": "orders", "version": "1.4.0" } } }
// client → server (handshake complete)
{ "jsonrpc": "2.0", "method": "notifications/initialized" }

Si le serveur n’annonce pas sampling, le host ne lui routera pas de requêtes de sampling — et inversement pour les roots du client.

Resources, prompts et sampling — exemples détaillés

Resources (contrôlées par l’application, en lecture seule)

json
// list
{ "jsonrpc": "2.0", "id": 2, "method": "resources/list" }
{ "jsonrpc": "2.0", "id": 2, "result": { "resources": [
{ "uri": "orders://schema", "name": "Orders schema", "mimeType": "text/sql" },
{ "uri": "orders://policy/refunds", "name": "Refund policy", "mimeType": "text/markdown" } ] } }
// read
{ "jsonrpc": "2.0", "id": 3, "method": "resources/read", "params": { "uri": "orders://schema" } }
{ "jsonrpc": "2.0", "id": 3, "result": { "contents": [
{ "uri": "orders://schema", "mimeType": "text/sql", "text": "CREATE TABLE orders (…)" } ] } }

Les resources sont des données, pas des actions : aucun effet de bord, adressées par URI, choisies par l’application (pas le modèle). Utilisez-les pour les schémas, les politiques et les docs de référence.

Prompts (modèles contrôlés par l’utilisateur)

json
{ "jsonrpc": "2.0", "id": 4, "method": "prompts/get",
"params": { "name": "triage", "arguments": { "order_id": "ORD-12345" } } }
{ "jsonrpc": "2.0", "id": 4, "result": { "messages": [
{ "role": "user", "content": { "type": "text",
"text": "Triage order ORD-12345: check status, delays and next action." } } ] } }

Les prompts apparaissent comme des slash commands (/triage) — c’est l’utilisateur qui les invoque, contrairement aux tools (invoqués par le modèle) ou aux resources (sélectionnées par l’application).

Sampling (le serveur sollicite le modèle du host)

Le serveur peut demander une complétion au modèle du host — p. ex. pour résumer avant de renvoyer. Le host garde le contrôle et peut refuser, caviarder ou limiter le débit.

json
// server → client
{ "jsonrpc": "2.0", "id": 5, "method": "sampling/createMessage", "params": {
"messages": [{ "role": "user", "content": { "type": "text", "text": "Summarise: <500 rows>" } }],
"maxTokens": 300, "modelPreferences": { "intelligencePriority": 0.3, "speedPriority": 0.8 } } }
// client → server (after the host runs its model, with user approval)
{ "jsonrpc": "2.0", "id": 5, "result": {
"role": "assistant", "content": { "type": "text", "text": "12 orders delayed, avg 3 days…" },
"model": "claude-haiku-4-5", "stopReason": "endTurn" } }

Le sampling est une frontière de confiance

Le sampling permet à un serveur de dépenser les tokens du host et de voir la sortie du modèle. Le host doit le contrôler (approbation, limites de débit) et ne jamais auto-approuver pour des serveurs non fiables.

Exemple de serveur Streamable HTTP

python
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("orders")
@mcp.tool()
def get_order(order_id: str) -> dict:
"""Look up one order by ID. Read-only."""
return db.fetch_order(order_id)
if __name__ == "__main__":
# Serves POST /mcp with streaming responses; put OAuth 2.1 in front (reverse proxy / gateway)
mcp.run(transport="streamable-http", host="0.0.0.0", port=8080, path="/mcp")
text
Client Reverse proxy / gateway MCP server
│ POST /mcp (Bearer token) │ │
├────────────────────────────────► validate token, scopes │
│ ├────────────────────────────────► initialize / tools/call
│ │ │
│ ◄─────── streamed JSON-RPC responses (chunked) ─────────────────┤

Streamable HTTP est un endpoint unique qui supporte requête/réponse et messages streamés par le serveur. Il remplace l’ancien transport HTTP+SSE à deux endpoints.

Flux OAuth 2.1 (serveurs distants)

text
┌── Host (MCP client) ──┐ ┌── Authorization server ──┐ ┌── MCP server ──┐
│ 1. discover metadata │────────►│ /.well-known/oauth-* │ │ (resource) │
│ 2. PKCE: code_verifier│ │ │ │ │
│ + code_challenge │ │ │ │ │
│ 3. authorize (browser)│────────►│ user logs in, consents │ │ │
│ 4. redirect w/ code │◄────────│ auth code │ │ │
│ 5. token (code + │────────►│ /token │ │ │
│ code_verifier) │◄────────│ access + refresh token │ │ │
│ 6. call with Bearer │───────────────────────────────────┼─────►│ validate scope │
│ 7. refresh on expiry │────────►│ /token (refresh_token) │ │ │
└───────────────────────┘ └──────────────────────────┘ └────────────────┘
  • PKCE est obligatoire dans OAuth 2.1 (pas de flux implicite).
  • Les tokens sont éphémères ; rafraîchissez silencieusement.
  • Les scopes correspondent aux permissions d’outils ; le token porte l’identité de l’utilisateur final pour que les outils agissent en tant que cet utilisateur.
  • Le serveur MCP est un serveur de ressources ; un serveur d’autorisation distinct émet les tokens.

Formes d’erreur

MCP distingue les erreurs de protocole (niveau JSON-RPC) des erreurs d’exécution d’outil (un appel réussi dont le résultat dit qu’il a échoué).

json
// Protocol / JSON-RPC error (method missing, bad params)
{ "jsonrpc": "2.0", "id": 7, "error": { "code": -32602, "message": "Invalid params: order_id required" } }
// Tool execution error (call succeeded, tool failed) — isError on the result
{ "jsonrpc": "2.0", "id": 8, "result": {
"isError": true,
"content": [{ "type": "text", "text": "{\"category\":\"not_found\",\"retryable\":false,\"message\":\"No order ORD-999\"}" }] } }
Code JSON-RPCSignification
-32700Erreur de parsing
-32600Requête invalide
-32601Méthode non trouvée
-32602Paramètres invalides
-32603Erreur interne

Règle : les échecs métier utilisent isError: true sur le résultat (le modèle peut les voir et réagir), pas une erreur JSON-RPC. Réservez les erreurs JSON-RPC aux appels réellement malformés.

Tester avec le MCP Inspector

Terminal window
# Launch the inspector against a local stdio server
npx @modelcontextprotocol/inspector python orders_server.py
# Against a remote Streamable HTTP server (walks the OAuth flow)
npx @modelcontextprotocol/inspector --transport http https://mcp.example.com/mcp

Checklist dans l’inspector : initialize renvoie les capacités attendues ; tools/list affiche les bons noms, descriptions et schémas ; chaque appel d’outil renvoie du contenu structuré ; les chemins d’erreur positionnent isError ; les resources se lisent proprement ; les prompts s’affichent avec les arguments. Testez avant de câbler le serveur dans Claude — la plupart des bugs « le modèle n’appelle pas mon outil » sont des bugs de description/schéma que l’inspector fait remonter immédiatement.

Versionnement

ChangementCompatibilitéFaire
Ajouter un nouvel outilRétrocompatibleLivrez librement ; incrémentez la version mineure
Ajouter un champ optionnelRétrocompatibleLivrez ; documentez
Renommer/supprimer un outil ou un champ requisCassantNouveau nom d’outil ; gardez l’ancien déprécié un temps
Changer silencieusement la sémantique d’un outilDangereuxJamais — les agents ont encodé l’ancien comportement ; versionnez et communiquez
Version du protocoleNégociée à initializeSupportez une plage ; annoncez la plus haute que vous parlez

Préférez une évolution additive. Comme les agents et les prompts encodent les noms et comportements d’outils, un changement sémantique silencieux casse les appelants sans erreur — le versionnement et les fenêtres de dépréciation sont l’approche correcte pour l’examen.

Idées reçues courantes

Idée reçueRéalitéPourquoi cela compte à l’examen
« Tools, resources et prompts sont interchangeables »Tools = actions invoquées par le modèle ; resources = données sélectionnées par l’application ; prompts = modèles invoqués par l’utilisateurDistracteur de confusion de primitives
« MCP est agent-à-agent »MCP est modèle↔outil ; utilisez une couche d’orchestration/A2A pour agent↔agentDistracteur de mauvais protocole
« Un outil qui ne trouve rien devrait renvoyer {} »Renvoyez isError avec une category ; jamais de succès videAnti-pattern de silent-failure
« Exposer tout ce que le serveur peut faire »Moindre privilège ; séparez les outils destructifs ; supprimez les inutilesDistracteur d’outils trop larges
« OAuth est optionnel pour les serveurs distants »Les serveurs distants Streamable HTTP nécessitent OAuth 2.1 + PKCE ; propagez l’identité de l’utilisateurFaille d’authz de super-utilisateur partagé
« 20 outils sur un serveur, ça va »4–8 typique ; au-delà de ~10 utilisez la recherche d’outils + defer_loadingAnti-pattern de trop d’outils
« Les erreurs métier devraient être des erreurs JSON-RPC »Utilisez isError sur le résultat ; les erreurs JSON-RPC sont pour les appels malformésDistracteur de forme d’erreur

Analyse de scénario

Une entreprise SaaS veut que Claude, embarqué dans plusieurs applications internes, lise et agisse sur les enregistrements CRM des clients. Multi-tenant : chaque utilisateur final ne peut voir que ses propres comptes. Le CRM dispose déjà d’un fournisseur OAuth. Comment concevoir l’intégration MCP ?

  1. Serveur MCP, pas des outils personnalisés par application — le connecteur est réutilisé sur plusieurs hosts/applications ; un serveur standard est découvrable et géré par les permissions du host.
  2. Transport Streamable HTTP — distant, multi-utilisateur ; stdio est réservé aux sous-processus locaux.
  3. OAuth 2.1 + PKCE, tokens par utilisateur — le token porte l’identité de l’utilisateur final pour que les outils appliquent les permissions CRM de cet utilisateur. Un identifiant de super-utilisateur partagé est le distracteur de faille d’authz.
  4. Outils étroits — search_accounts, get_account, create_note (4–8). Les opérations destructives (delete_account) vivent derrière un serveur séparé ou une confirmation, ou sont omises (moindre privilège).
  5. Erreurs structurées — isError avec category/retryable ; jamais de succès vide.
  6. Traiter la sortie d’outil comme non fiable — les notes CRM pourraient porter une injection indirecte ; gardez les frontières et validez en aval.
  7. Versionner de façon additive — ajoutez des outils au fil du temps ; ne changez jamais silencieusement la sémantique.

Alternatives rejetées : stdio (pas distant/multi-utilisateur), une clé API partagée (casse l’authz par utilisateur), exposer chaque verbe CRM (trop large), et renvoyer {} sur « aucun compte trouvé » (silent failure).

Dernière mise à jour le 18 sept. 2026