Domaines
D5 · Tools and MCPs
Cycle de vie de l’utilisation d’outils, descriptions et schémas d’outils, tool_choice, outils parallèles, outils côté client vs côté serveur, tool search, fondamentaux MCP, écriture de serveurs MCP, et configuration de MCP dans Claude Code et la Messages API.
Ce domaine représente environ 5 items sur 53. Il vérifie que vous savez bien définir des outils (la description est le levier le plus important), exécuter correctement le cycle de vie de l’utilisation d’outils, choisir entre outils côté client et côté serveur, et comprendre et écrire des serveurs MCP. Le thème : les outils sont la façon dont Claude agit sur le monde – décrivez-les précisément et connectez-les en toute sécurité.
Objectifs d’apprentissage
À la fin de cette page, vous devriez être capable de :
- Exécuter le cycle de vie utilisation d’outils / function-calling avec un JSON correct.
- Écrire des descriptions d’outils efficaces et concevoir l’
input_schema. - Utiliser
tool_choice(auto/any/tool/none) et connaître la restriction Fable 5.1. - Utiliser les appels d’outils parallèles et distinguer les outils côté client vs côté serveur.
- Utiliser tool search +
defer_loading, l’appel d’outils programmatique, et les patterns d’approbation. - Expliquer les fondamentaux MCP et écrire un serveur MCP en Python (FastMCP) et TypeScript.
- Configurer MCP dans Claude Code / Desktop et via le connecteur MCP dans la Messages API.
5.1 The tool-use lifecycle
{ "tools": [{ "name": "get_weather", "description": "Get the current weather for a city. Use when the user asks about weather, temperature, or conditions in a named location.", "input_schema": { "type": "object", "properties": { "city": {"type": "string", "description": "City name, e.g. 'Paris'"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"], "default": "celsius"} }, "required": ["city"] } }]}{ "stop_reason": "tool_use", "content": [ {"type": "text", "text": "Let me check the weather."}, {"type": "tool_use", "id": "toolu_01", "name": "get_weather", "input": {"city": "Paris"}} ]}{ "role": "user", "content": [ {"type": "tool_result", "tool_use_id": "toolu_01", "content": "18C, partly cloudy"} ]}Puis rappelez l’API ; Claude produit la réponse finale end_turn.
Les erreurs sont renvoyées avec "is_error": true dans le tool_result pour que Claude puisse récupérer.
A complete round-trip on the wire
Les quatre Tabs ci-dessus sont les quatre messages sur le fil d’un aller-retour. Lisez-les comme une seule conversation pour que le chaînage du tool_use_id soit sans équivoque. La requête déclare les outils ; Claude répond avec stop_reason: 'tool_use' ; vous exécutez la fonction et envoyez un tool_result référençant le même id ; Claude produit la réponse end_turn.
import anthropicclient = anthropic.Anthropic()
TOOLS = [{ "name": "get_weather", "description": "Get current weather for a city. Use when the user asks about " "weather, temperature, or conditions in a named location. " "Returns a short text summary. Read-only, no side effects.", "input_schema": { "type": "object", "properties": { "city": {"type": "string", "description": "City name, e.g. 'Paris'"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"], "default": "celsius"}, }, "required": ["city"], },}]
messages = [{"role": "user", "content": "What's the weather in Paris?"}]
# 1. Tour du modèle -> Claude demande l'outilresp = client.messages.create( model="claude-sonnet-5", max_tokens=1024, tools=TOOLS, messages=messages,)assert resp.stop_reason == "tool_use" # NE JAMAIS parser le texte pour décider celamessages.append({"role": "assistant", "content": resp.content})
# 2. Vous exécutez l'outil pour chaque bloc tool_usefor block in resp.content: if block.type == "tool_use": result = fetch_weather(**block.input) # votre vraie fonction messages.append({"role": "user", "content": [{ "type": "tool_result", "tool_use_id": block.id, # DOIT correspondre à l'id d'origine "content": result, }]})
# 3. Tour du modèle à nouveau -> Claude donne la réponse finalefinal = client.messages.create( model="claude-sonnet-5", max_tokens=1024, tools=TOOLS, messages=messages,)assert final.stop_reason == "end_turn"print(final.content[0].text)Bouclez sur stop_reason, pas sur le texte
La boucle d’agent canonique est while stop_reason == 'tool_use': run tools; call again. Analyser la prose de l’assistant pour décider de continuer est l’anti-pattern nº 1. Quand un outil échoue, renvoyez {"type": "tool_result", "tool_use_id": id, "content": "Error: timeout", "is_error": true} pour que Claude puisse réessayer ou s’excuser – ne supprimez pas silencieusement le résultat (anti-pattern nº 7).
5.2 Tool descriptions – the most important lever
La description est le principal déterminant de savoir si Claude utilise un outil correctement. Investissez ici plus que partout ailleurs. Une bonne description se lit comme la docstring que vous écririez pour un collègue qui n’a jamais vu la fonction.
Good vs bad tool descriptions – four pairs
| Bad | Good |
|---|---|
get_data — ‘Gets data’ | get_order — ‘Retrieve one order by its ID. Use when the user references a specific order number. Returns status, line items and totals. Read-only.’ |
search — ‘Search’ | search_kb — ‘Full-text search of the help-centre knowledge base. Use for how-to and policy questions, NOT for live account data. Returns up to 5 article snippets with URLs.’ |
update — ‘Updates a record’ | update_shipping_address — ‘Change the shipping address on an unshipped order. Fails if the order has shipped. Side effect: writes to the orders DB. Confirm with the user first.’ |
run — ‘Runs a query’ | run_sql_readonly — ‘Execute a read-only SELECT against the analytics warehouse. Rejects INSERT/UPDATE/DELETE. Use for reporting questions. Returns at most 1000 rows as JSON.’ |
Chaque bonne description répond à quatre questions : ce qu’elle fait, quand l’utiliser (et quand non), ce qu’elle renvoie, et quels effets de bord / quelle irréversibilité elle comporte.
| Good description | Poor description |
|---|---|
| Énonce ce que fait l’outil, quand l’utiliser, quand non, et ce qu’il renvoie | ‘Gets data’ |
| Documente chaque paramètre avec type, sens et exemple | Params non documentés |
| Note les effets de bord et l’irréversibilité | Muet sur les effets de bord |
Signal d’examen
« Claude choisit le mauvais outil / l’appelle avec de mauvais arguments » → améliorez la description de l’outil et l’input_schema (types, enums, required, exemples). Allez chercher la description avant de toucher à la température ou au modèle.
5.3 input_schema design checklist
Le schéma est du JSON Schema. Il contraint ce que Claude peut passer et, avec strict: true, garantit la forme. Concevez-le délibérément.
- Types — donnez un
typeà chaque propriété. Utilisez le type le plus étroit (integerplutôt quenumberquand c’est entier). - Enums — contraignez les ensembles fermés avec
enumpour que Claude ne puisse pas inventer une valeur :{"type": "string", "enum": ["celsius", "fahrenheit"]}. required— listez chaque argument dont l’outil a réellement besoin. Les arguments requis-mais-omis sont une cause majeure d’appels malformés.- Descriptions par propriété — décrivez chaque champ, avec un exemple. Claude les lit.
- Nullable / optionnel — les params optionnels sont simplement absents de
required; pour autoriser un null explicite, utilisez{"type": ["string", "null"]}. - Bornes et formats —
minimum,maximum,pattern,format: 'date'réduisent les entrées de mauvaise qualité. strict: true— activez le respect strict du schéma pour que les sorties soient exactement conformes (aussi un moyen d’obtenir un comportement structuré sur Fable 5.1 où les outils forcés font 400).
{ "name": "create_ticket", "description": "Open a support ticket. Use only after the user confirms they want one.", "input_schema": { "type": "object", "properties": { "priority": {"type": "string", "enum": ["low", "normal", "high", "urgent"], "description": "Urgency; default to 'normal' unless the user signals otherwise"}, "summary": {"type": "string", "description": "One-line summary, e.g. 'Cannot log in'"}, "due_date": {"type": ["string", "null"], "format": "date", "description": "ISO date, or null if none"} }, "required": ["priority", "summary"] }, "strict": true}5.5 tool_choice
| Value | Behaviour | Notes |
|---|---|---|
auto | Claude décide s’il utilise un outil (défaut) | Meilleur défaut général ; combinez avec une instruction claire |
any | Claude doit utiliser l’un des outils | Force un outil ; 400 sur Fable 5.1 |
{type: 'tool', name: '…'} | Forcer un outil spécifique | Extraction déterministe à un seul outil ; 400 sur Fable 5.1 |
none | Désactiver les outils pour ce tour | Le modèle répond depuis le contexte uniquement |
Restriction Fable 5.1
Sur Fable 5.1, tool_choice: 'any' et {type: 'tool'} forcé renvoient 400. Utilisez auto avec une instruction claire, des schémas strict: true, ou les sorties structurées (output_config.format). C’est une erreur client — ne la réessayez pas avec backoff.
5.6 Parallel tool calls
Quand les sous-tâches sont indépendantes, Claude peut émettre plusieurs blocs tool_use dans une seule réponse. Exécutez-les en concurrence et renvoyez tous les blocs tool_result dans le message user suivant (en faisant correspondre chaque tool_use_id). Si les appels sont dépendants (le résultat de l’un alimente le suivant), Claude les sérialisera plutôt entre les tours.
tool_uses = [b for b in resp.content if b.type == "tool_use"]results = run_concurrently(tool_uses) # outils indépendants en parallèlemessages.append({"role": "assistant", "content": resp.content})messages.append({"role": "user", "content": [ {"type": "tool_result", "tool_use_id": u.id, "content": r} for u, r in zip(tool_uses, results)]}) # TOUS les résultats dans UN tour userRenvoyez chaque résultat, une fois
Vous devez renvoyer exactement un tool_result par bloc tool_use, dans le même tour user, chacun indexé sur son tool_use_id. Des résultats manquants ou dupliqués provoquent un 400. Pour décourager le parallélisme quand les outils sont à état, réglez disable_parallel_tool_use: true dans tool_choice.
5.7 Client-side vs server-side tools
| Type | Runs where | Examples |
|---|---|---|
| Côté client (custom) | Votre code | Vos API, requêtes DB, fonctions métier |
| Côté serveur (hébergés par Anthropic) | Anthropic | Web search, exécution de code, computer use, éditeur de texte, bash, memory |
Les outils côté serveur sont activés en les déclarant ; Anthropic les exécute et peut mettre le tour en pause (pause_turn) pendant l’exécution.
Server-side built-in tools
| Tool | What it does | Typical use |
|---|---|---|
| Web search | Requêtes web en direct avec citations | Actualités, faits au-delà de la coupure de connaissances |
| Code execution | Exécute du code dans un sandbox | Analyse de données, calcul, tracé |
| Text editor | Visualise et édite des fichiers via une interface str-replace | Éditions de code multi-fichiers |
| Bash | Exécute des commandes shell dans un sandbox | Étapes build/test/install en code agentique |
| Memory | Stockage persistant entre sessions | Se souvenir des préférences utilisateur entre sessions |
| Computer use | Captures d’écran + contrôle souris/clavier | Opérer une GUI quand aucune API n’existe |
Signal d’examen
« Chercher sur le web en direct / exécuter du code dans un sandbox / éditer des fichiers / opérer un ordinateur / se souvenir entre sessions » → outils intégrés côté serveur. « Appeler notre API interne / base de données / fonction métier » → outil personnalisé côté client.
5.8 Tool search, defer_loading and programmatic calling
- Au-delà de ~10 outils, utilisez le tool search tool avec
defer_loading: truepour que les définitions complètes d’outils soient chargées à la demande plutôt que toutes en amont — réduit le gonflement du contexte et la sélection du mauvais outil (anti-pattern nº 8). - L’appel d’outils programmatique permet au code d’invoquer les outils directement dans une boucle contrôlée.
- Patterns d’approbation : exiger une approbation humaine/par hook avant les actions d’outils irréversibles (voir hooks, Domaines 3 et 6).
# Grand catalogue : différer les définitions complètes, exposer l'outil de recherche.tools = [ {"type": "tool_search_tool_20250000", "name": "tool_search"}, # laisse Claude trouver des outils à la demande {"name": "get_order", "description": "...", "input_schema": {...}, "defer_loading": True}, {"name": "issue_refund", "description": "...", "input_schema": {...}, "defer_loading": True}, # ...50 autres outils différés ; seuls ceux que Claude recherche sont hydratés dans le contexte]resp = client.messages.create(model="claude-sonnet-5", max_tokens=2048, tools=tools, messages=messages)Le pattern garde l’ensemble d’outils actifs restreint (4–5 dans le contexte à la fois) même quand le catalogue est grand, ce qui est exactement le correctif de l’anti-pattern nº 8.
5.9 MCP fundamentals
Le Model Context Protocol est un standard ouvert (JSON-RPC 2.0) pour connecter Claude à des outils et données externes.
| Primitive | Controlled by | Example |
|---|---|---|
| Tools | Modèle | Fonctions appelables |
| Resources | Application | Fichiers, enregistrements que l’app expose |
| Prompts | Utilisateur | Templates de prompt réutilisables |
- Transports :
stdio(sous-processus local) et Streamable HTTP (distant ; SSE est hérité). - La négociation des capacités a lieu à
initialize. - OAuth 2.1 sécurise les serveurs distants.
Host (Claude Desktop / Code) │ JSON-RPC 2.0 ├── stdio ──► local MCP server (subprocess) └── Streamable HTTP ──► remote MCP server (OAuth 2.1)5.10 Authoring an MCP server
Un serveur minimal mais complet : il se nomme, déclare un outil avec un schéma typé et une description en docstring, gère ses propres erreurs, et s’exécute sur stdio. Les deux SDK ci-dessous sont exécutables tels quels.
# weather_server.py — run: python weather_server.pyfrom mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather")
@mcp.tool()def get_weather(city: str, unit: str = "celsius") -> str: """Get current weather for a city.
Use when the user asks about weather, temperature or conditions in a named location. Returns a short text summary. Read-only, no side effects. """ if not city: raise ValueError("city is required") return fetch_weather(city, unit)
@mcp.resource("config://units")def default_units() -> str: """Application-controlled resource: the default unit system.""" return "celsius"
if __name__ == "__main__": mcp.run() # transport stdio par défaut ; utiliser mcp.run(transport='streamable-http') pour le distant// weather_server.ts — run: node weather_server.jsimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';import { z } from 'zod';
const server = new McpServer({ name: 'weather', version: '1.0.0' });
server.tool( 'get_weather', 'Get current weather for a city. Use when asked about weather in a named location. Read-only.', { city: z.string().describe('City name, e.g. Paris'), unit: z.enum(['celsius', 'fahrenheit']).default('celsius') }, async ({ city, unit }) => { if (!city) throw new Error('city is required'); return { content: [{ type: 'text', text: await fetchWeather(city, unit) }] }; },);
const transport = new StdioServerTransport();await server.connect(transport); // pour le distant : StreamableHTTPServerTransport5.11 Configuring MCP
# stdio (sous-processus local)claude mcp add weather --scope project -- python weather_server.py
# HTTP (serveur distant)claude mcp add --transport http docs https://mcp.example.com/mcp --scope user
# list / removeclaude mcp listclaude mcp remove weatherScopes : local (cette machine, privé), project (partagé via .mcp.json, committé), user (tous vos projets).
{ "mcpServers": { "weather": { "command": "python", "args": ["weather_server.py"], "env": { "WEATHER_API_KEY": "${WEATHER_API_KEY}" } }, "docs": { "type": "http", "url": "https://mcp.example.com/mcp", "headers": { "Authorization": "Bearer ${DOCS_TOKEN}" } } }}Le serveur stdio utilise command/args ; le serveur distant utilise type: 'http' + url. Les secrets viennent de variables d’env — ne les codez jamais en dur ici.
Le connecteur MCP permet à la Messages API d’appeler directement un serveur MCP distant, de sorte que les outils d’un serveur hébergé sont disponibles pour le modèle sans que vous ayez à redéclarer chaque outil.
resp = client.beta.messages.create( model="claude-sonnet-5", max_tokens=1024, messages=[{"role": "user", "content": "Search the docs for retry policy."}], mcp_servers=[{ "type": "url", "url": "https://mcp.example.com/mcp", "name": "docs", "authorization_token": "Bearer …", # token OAuth 2.1 pour le serveur distant }], betas=["mcp-client-2025-04-04"],)5.12 MCP vs custom tool vs Skill – decision table
Ces trois façons d’étendre Claude sont fréquemment confondues à l’examen.
| Choose | When | Runs / lives | Controlled by |
|---|---|---|---|
| Custom tool (Messages API) | Vous avez besoin d’une ou de quelques fonctions pour une seule app ; contrôle total de l’exécution | Votre code, par requête | Votre intégration d’API |
| MCP server | Vous voulez des outils/ressources réutilisables partagés entre apps, hosts (Code, Desktop, API) et équipes | Un processus séparé (stdio/HTTP), réutilisé partout | Un protocole ouvert |
| Skill | Vous voulez empaqueter instructions + fichiers + scripts qui se chargent progressivement à la demande dans Claude Code | .claude/skills/<name>/SKILL.md, chargé quand pertinent | Un fichier markdown avec frontmatter |
Règle générale : une app, quelques fonctions → custom tools ; réutilisation entre hosts/équipes → MCP ; savoir-faire empaqueté et scripts d’aide pour Claude Code → Skill.
Signal d’examen
« Partager les mêmes outils entre Claude Code, Desktop et notre API » → MCP. « Grouper un workflow avec des fichiers de référence et des scripts d’aide que Claude charge seulement quand nécessaire » → Skill. « Simplement appeler notre unique endpoint interne depuis ce service » → custom tool.
5.13 MCP transports, capability negotiation and OAuth 2.1
Les détails « sur le fil » de MCP reviennent dans les items d’examen. MCP est du JSON-RPC 2.0 ; un host et un serveur négocient les capacités à initialize, puis échangent des appels tool/resource/prompt sur un transport.
| Aspect | stdio | Streamable HTTP |
|---|---|---|
| Où le serveur s’exécute | Sous-processus local | Endpoint distant |
| Auth | Confiance de processus local / env | OAuth 2.1 |
| Idéal pour | Outils de dev locaux, plugins Desktop/Code | Serveurs partagés/d’équipe, connecteur Messages API |
| Note héritée | — | Le transport SSE-only est hérité ; préférez Streamable HTTP |
Host ──initialize──► Server (capability negotiation: tools? resources? prompts?)Host ◄─capabilities─ ServerHost ──tools/list───► Server (discover model-controlled tools)Host ──tools/call───► Server (Claude invokes a tool)Host ──resources/read► Server (application-controlled data)Host ──prompts/get──► Server (user-controlled templates)Signal d’examen
« Outil en sous-processus local » → stdio. « Serveur distant/partagé, sécurisez-le » → Streamable HTTP + OAuth 2.1. « Quelle primitive le modèle décide-t-il d’appeler ? » → tools (resources = application, prompts = utilisateur). La négociation des capacités a lieu à initialize.
5.14 Approval and human-in-the-loop for irreversible tools
Certains outils sont irréversibles (remboursements, suppressions, envois, déploiements). La conception correcte les protège de manière déterministe, pas en faisant confiance au modèle.
| Control | Mechanism | Notes |
|---|---|---|
| Allowlist | N’exposer que les outils dont la tâche a besoin | Moindre privilège ; gardez les irréversibles hors des agents routiniers |
| Hook PreToolUse | Bloquer (exit 2) et router vers l’approbation | Le modèle ne peut pas le contourner par l’argumentation (anti-pattern nº 3) |
| Workflow d’approbation | Validation humaine avant exécution | Pour paiements/suppressions/déploiements |
is_error sur les résultats | Remonter les échecs d’outils pour que Claude récupère | Ne supprimez jamais un résultat silencieusement (anti-pattern nº 7) |
# Protéger un outil irréversible derrière une approbation ; renvoyer is_error pour que Claude s'adapte.if block.name == "issue_refund" and block.input["amount_cents"] > 50000: result = {"type": "tool_result", "tool_use_id": block.id, "content": "Refund over $500 requires human approval; request queued.", "is_error": True}L’approbation est une application, pas un prompt
« Demander à l’utilisateur avant de rembourser » dans la description de l’outil est une consigne que le modèle peut ignorer. La garantie vient d’un hook/contrôle d’approbation plus le fait de garder l’outil hors de la liste blanche là où il n’est pas nécessaire.
5.15 Common misconceptions
| Misconception | Reality | Why it matters on the exam |
|---|---|---|
| Une description vague suffit si le schéma est strict | La description est le levier principal pour une utilisation correcte des outils | Questions mauvais-outil/mauvais-args |
tool_choice: 'any' fonctionne partout | Fable 5.1 rejette any/les outils forcés (400) | Un piège récurrent de changement incompatible |
| Un 400 sur un choix d’outil forcé est transitoire | Il est déterministe ; changez la requête, ne faites pas de backoff | Distingue les couches |
| Web search est un outil que vous implémentez | Web search et exécution de code sont des intégrés côté serveur | Tri client vs côté serveur |
| Les resources sont contrôlées par le modèle comme les tools | Les resources sont contrôlées par l’application ; les prompts par l’utilisateur | Correspondance des primitives MCP |
| Les résultats d’outils parallèles peuvent s’étaler sur plusieurs tours | Tous les résultats vont dans un tour user, chacun indexé sur son tool_use_id | 400 de forme de protocole |
| Plus d’outils améliorent la sélection | Au-delà de ~10, la sélection se dégrade ; utilisez tool search + defer_loading | Anti-pattern nº 8 |
| Un Skill peut partager des outils entre hosts | Les Skills sont du savoir-faire empaqueté pour Claude Code ; la réutilisation entre hosts est MCP | Décision Skill/MCP/tool |
5.16 Scenario walkthrough: a payments tool that must be safe and portable
Scénario. Une fintech veut que Claude consulte les commandes, cherche dans un centre d’aide, et — avec précaution — émette des remboursements, et elle veut les mêmes outils disponibles dans Claude Code, Claude Desktop et un service Messages API de production, maintenus en un seul endroit. Elle est sur Fable 5.1 pour sa qualité de raisonnement. Les premières tentatives forcent l’outil de remboursement avec tool_choice: {type: 'tool', name: 'issue_refund'} (obtenant des 400), suppriment parfois un résultat d’outil quand deux outils s’exécutent en parallèle (obtenant des 400), et émettent des remboursements sans étape d’approbation.
Trace de raisonnement d’expert.
- Choisissez le mécanisme de réutilisation. « Mêmes outils entre Code, Desktop et l’API, un seul endroit » → construisez un serveur MCP et connectez chaque host (stdio en local, Streamable HTTP pour le serveur partagé/distant sécurisé avec OAuth 2.1 ; la Messages API utilise le connecteur MCP). Copier le JSON de custom-tool dans chaque app est le piège de maintenance.
- Corrigez les 400 de Fable 5.1 sur le choix d’outil. Fable 5.1 rejette le choix d’outil forcé/
any. Utiliseztool_choice: 'auto'avec une instruction claire, ou les sorties structurées /strict: truepour les parties d’extraction. Réessayer le 400 avec backoff est faux — il est déterministe. - Corrigez les 400 de résultats parallèles. Renvoyez exactement un
tool_resultpar bloctool_use, tous dans le même tour user suivant, chacun indexé sur sontool_use_id; en cas d’échec, renvoyezis_error: truepour que Claude puisse récupérer. Supprimer un résultat provoque le 400. - Rendez les remboursements sûrs. Les remboursements sont irréversibles → protégez-les avec un hook PreToolUse / workflow d’approbation et gardez l’outil de remboursement hors de la liste blanche de tout agent routinier en lecture seule. « Confirmer avant de rembourser » dans la description n’est pas une application.
- Dimensionnez correctement le catalogue. Gardez ~4–5 outils actifs ; si le catalogue grandit, utilisez tool search +
defer_loading. - Rejetez les alternatives tentantes. « Forcer l’outil de remboursement pour le déterminisme » — 400 sur Fable 5.1. « Réessayer le 400 avec backoff » — erreur déterministe. « Mettre les outils dans
CLAUDE.mdpour les partager » —CLAUDE.mdcontient des instructions, pas des outils exécutables. « Utiliser un Skill pour partager entre hosts » — les Skills sont du savoir-faire empaqueté propre à Claude Code.
Décision correcte. Un serveur MCP (OAuth 2.1 pour le transport distant) connecté à tous les hosts ; auto + instruction ou sorties structurées sur Fable 5.1 au lieu du choix d’outil forcé ; gestion correcte des tool_result parallèles avec is_error ; remboursements derrière un hook d’approbation et hors des listes blanches routinières ; tool search + defer_loading si le catalogue grandit.
Pièges de l’examen dans ce domaine
| Piège | Pourquoi c’est faux |
|---|---|
| Blâmer le modèle quand il utilise mal un outil | Corrigez d’abord la description et l’input_schema |
| Forcer un outil sur Fable 5.1 | any/forcé renvoient 400 ; utilisez les sorties structurées / strict / auto |
| Charger 18 outils en amont | Surcharge la sélection ; utilisez tool search + defer_loading (anti-pattern nº 8) |
| Renvoyer les erreurs d’outils comme un succès simple | Marquez is_error pour que Claude puisse récupérer |
Ne pas faire correspondre le tool_use_id sur les résultats | Les résultats doivent référencer le tool_use_id d’origine |
| Utiliser un outil client pour web search | Web search est un intégré côté serveur |
| Traiter les resources MCP comme contrôlées par le modèle | Les resources sont contrôlées par l’application ; les tools par le modèle |
| Ignorer OAuth pour un MCP distant | Les serveurs distants utilisent OAuth 2.1 |
| Analyser le texte de l’assistant pour décider de continuer à appeler des outils | Bouclez sur stop_reason == 'tool_use' (anti-pattern nº 1) |
| Utiliser un Skill quand les outils doivent être partagés entre hosts | La réutilisation entre hosts/équipes est MCP ; les Skills sont du savoir-faire empaqueté pour Claude Code |
Coder en dur des secrets dans .mcp.json | Référencez des variables d’env (${VAR}) ; ne committez jamais d’identifiants |
| Sécuriser un serveur MCP distant avec un en-tête statique au lieu d’OAuth 2.1 | Les serveurs distants/Streamable HTTP utilisent OAuth 2.1 |
| Renvoyer les résultats d’outils parallèles sur plusieurs tours user | Tous les résultats vont dans un tour user, chacun indexé sur son tool_use_id |
| Se fier à « confirmer avant de rembourser » dans la description de l’outil | Consigne, pas application ; protégez les outils irréversibles avec un hook/approbation et le moindre privilège |
| Réessayer un 400 d’outil forcé sur Fable 5.1 avec backoff | Erreur client déterministe ; utilisez auto/sorties structurées, ne réessayez pas |
| Utiliser stdio pour un serveur d’équipe partagé et distant | stdio est pour les sous-processus locaux ; distant/partagé → Streamable HTTP + OAuth 2.1 |
Questions d’entraînement
Q1 · Claude appelle fréquemment le mauvais outil et passe des arguments malformés. Quelle est la FIRST chose à améliorer ? (Sélectionnez une réponse)
A. Baisser la température.
B. Réécrire les descriptions d’outils et resserrer l’input_schema (types, enums, required, exemples, quand-utiliser).
C. Passer à Opus 5.
D. Augmenter max_tokens.
Réponse : B. La description et le schéma sont les leviers principaux pour une utilisation correcte des outils. La température (A), le modèle (C) et max_tokens (D) sont secondaires.
Q2 · Un développeur règle `tool_choice: 'any'` sur Fable 5.1 et reçoit un 400. Quelle est l’approche correcte ? (Sélectionnez une réponse)
A. Réessayer avec backoff.
B. Utiliser tool_choice: 'auto' avec une instruction, ou les sorties structurées / strict: true, puisque Fable 5.1 rejette le choix d’outil forcé.
C. Passer à none.
D. Augmenter max_tokens.
Réponse : B. Fable 5.1 rejette le choix d’outil any/forcé ; utilisez auto + instruction ou les sorties structurées. C’est une erreur client 400, pas transitoire (A) ; none (C) désactive les outils.
Q3 · Un agent est passé à 18 outils et la qualité de sélection a chuté. Quel est le correctif recommandé ? (Sélectionnez une réponse)
A. Ajouter des outils plus descriptifs.
B. Réduire à un ensemble focalisé et utiliser le tool search tool avec defer_loading pour le catalogue plus grand.
C. Forcer un outil à chaque tour.
D. Augmenter la température.
Réponse : B. Trop d’outils est l’anti-pattern nº 8 ; le correctif est moins d’outils plus tool search + defer_loading. Plus d’outils (A) aggrave le problème.
Q4 · Lesquels des éléments suivants sont des outils côté serveur (hébergés par Anthropic) ? (Sélectionnez deux réponses)
A. Web search. B. L’API de commandes interne de votre entreprise. C. Code execution. D. Une fonction de requête de base de données personnalisée que vous avez écrite. E. Un script shell local que vous maintenez.
Réponse : A et C. Web search et code execution sont des outils côté serveur hébergés par Anthropic. Votre API (B), votre fonction DB personnalisée (D) et votre script local (E) sont côté client.
Q5 · Une équipe veut que les outils d’un serveur MCP distant soient disponibles directement depuis la Messages API sans redéclarer chaque outil. Qu’est-ce qui permet cela ? (Sélectionnez une réponse)
A. La Files API. B. Le connecteur MCP dans la Messages API. C. Le prompt caching. D. La Batch API.
Réponse : B. Le connecteur MCP permet à la Messages API d’appeler directement des serveurs MCP distants. La Files API (A), le caching (C) et le batching (D) sont sans rapport.
Q6 · Dans la boucle d’utilisation d’outils, comment le code devrait-il décider s’il faut exécuter un autre aller-retour d’outil ? (Sélectionnez une réponse)
A. Analyser le texte de l’assistant à la recherche de phrases comme « let me check ».
B. Vérifier si resp.stop_reason == 'tool_use' et, si oui, exécuter les outils et rappeler l’API.
C. Boucler un nombre fixe de 5 fois quelle que soit la sortie.
D. Continuer jusqu’à ce que la réponse soit vide.
Réponse : B. L’API vous l’indique de manière déterministe via stop_reason. Analyser la prose (A) est l’anti-pattern nº 1 ; un plafond fixe (C) est l’anti-pattern nº 2 ; la détection de réponse vide (D) n’est pas fiable.
Q7 · Un outil `get_order` renvoie un timeout. Comment le résultat devrait-il être renvoyé à Claude ? (Sélectionnez une réponse)
A. Omettre le tool_result pour que Claude l’ignore.
B. Renvoyer une chaîne vide comme contenu.
C. Renvoyer un tool_result avec le même tool_use_id, un message d’erreur, et is_error: true.
D. Lever une exception et arrêter la conversation.
Réponse : C. Les erreurs doivent être renvoyées avec l’id correspondant et is_error: true pour que Claude puisse réessayer ou s’excuser. Omettre (A) provoque un 400 ; un contenu vide (B) est un échec silencieux (anti-pattern nº 7) ; planter (D) masque les diagnostics.
Q8 · Quelles propriétés d’un `input_schema` empêchent le mieux Claude d’inventer une valeur d’argument invalide pour un ensemble fermé comme un niveau de priorité ? (Sélectionnez une réponse)
A. Un max_tokens élevé.
B. Un enum contraignant les valeurs autorisées, plus lister le champ dans required.
C. Régler tool_choice: 'any'.
D. Baisser la température.
Réponse : B. enum restreint l’espace des valeurs et required garantit que le champ est fourni. max_tokens (A) et la température (D) sont sans rapport avec la validité du schéma ; tool_choice (C) régit si un outil est utilisé, pas ses arguments.
Q9 · Un agent de support doit extraire de manière fiable des données de commande structurées sur Fable 5.1, mais forcer un outil spécifique renvoie 400. Quelles sont les DEUX approches valides ? (Sélectionnez deux réponses)
A. Utiliser tool_choice: 'auto' avec une instruction claire d’appeler l’outil d’extraction.
B. Réessayer l’appel forcé avec backoff exponentiel.
C. Utiliser les sorties structurées via output_config.format avec un schéma JSON.
D. Passer tool_choice à none.
E. Rétrograder à Haiku 4.5 pour tout le trafic.
Réponse : A et C. Fable 5.1 rejette le choix d’outil forcé/any, donc utilisez auto + instruction ou les sorties structurées. Le backoff (B) ne corrigera pas une erreur client 400 ; none (D) désactive les outils ; changer de modèle pour tout (E) est un changement trop large et injustifié.
Q10 · Un développeur veut le MÊME ensemble d’outils disponible dans Claude Code, Claude Desktop et leur service Messages API de production, maintenu en un seul endroit. Quel est le meilleur mécanisme ? (Sélectionnez une réponse)
A. Copier le JSON de custom tool dans chaque app.
B. Construire un serveur MCP et y connecter chaque host (stdio/HTTP ; connecteur pour l’API).
C. Écrire un Skill dans .claude/skills/.
D. Mettre les outils dans CLAUDE.md.
Réponse : B. MCP est le mécanisme de réutilisation entre hosts. Copier le JSON (A) duplique la maintenance ; un Skill (C) est du savoir-faire empaqueté propre à Claude Code, pas un serveur d’outils multi-host ; CLAUDE.md (D) contient des instructions, pas des outils exécutables.
Q11 · Quelle primitive MCP est contrôlée par le modèle, signifiant que Claude décide quand l’invoquer ? (Sélectionnez une réponse)
A. Resources. B. Prompts. C. Tools. D. Transports.
Réponse : C. Les tools sont contrôlés par le modèle. Les resources (A) sont contrôlées par l’application, les prompts (B) par l’utilisateur, et les transports (D) sont le mécanisme de connexion (stdio / Streamable HTTP), pas une primitive que Claude invoque.
Q12 · Claude demande deux outils indépendants (`get_weather` pour Paris et `get_weather` pour Tokyo) dans une seule réponse. Comment les résultats doivent-ils être renvoyés ? (Sélectionnez une réponse)
A. Deux tours user séparés, un résultat chacun.
B. Un tour user contenant les deux blocs tool_result, chacun indexé sur son propre tool_use_id.
C. Un seul tool_result combinant les deux villes.
D. En ignorer un et répondre à l’autre.
Réponse : B. Les blocs tool_use parallèles sont répondus avec tous les blocs tool_result dans un tour user, chacun correspondant à son tool_use_id d’origine. Séparer les tours (A), fusionner les ids (C), ou supprimer un résultat (D) cassent tous le protocole / provoquent un 400.
Q13 · Vous devez grouper un workflow de traitement de factures en plusieurs étapes avec des templates de référence et un script Python d’aide pour que Claude Code le charge seulement quand c’est pertinent. Quel mécanisme convient le mieux ? (Sélectionnez une réponse)
A. Un outil Messages API personnalisé.
B. Un serveur MCP distant.
C. Un Skill (SKILL.md avec frontmatter et fichiers groupés, chargé progressivement).
D. Un hook PreToolUse.
Réponse : C. Les Skills empaquettent des instructions plus des fichiers et scripts qui se chargent à la demande dans Claude Code — exactement ce scénario. Un custom tool (A) est une fonction unique ; un serveur MCP (B) sert au partage d’outils entre hosts ; un hook (D) est un garde-fou déterministe, pas un workflow empaqueté.
Q14 · Une équipe doit exposer un serveur MCP partagé et distant à Claude Desktop, Claude Code et la Messages API. Quels transport et auth sont appropriés ? (Sélectionnez une réponse)
A. stdio avec confiance de processus local.
B. Streamable HTTP sécurisé avec OAuth 2.1.
C. Un en-tête bearer statique codé en dur dans .mcp.json.
D. Le transport SSE-only, qui est le défaut recommandé actuel.
Réponse : B. Les serveurs distants/partagés utilisent Streamable HTTP sécurisé avec OAuth 2.1. stdio (A) est pour les sous-processus locaux ; un en-tête codé en dur (C) est un problème de secrets/hygiène et non l’auth standard ; SSE-only (D) est hérité, pas le défaut recommandé.
Q15 · Claude demande deux outils indépendants dans une réponse, mais le code renvoie chaque résultat dans son propre tour user séparé, et les requêtes commencent à échouer avec 400. Quel est le correctif ? (Sélectionnez une réponse)
A. Fusionner les deux sorties en un seul tool_result combiné.
B. Renvoyer les deux blocs tool_result dans un tour user, chacun indexé sur son propre tool_use_id.
C. Supprimer un résultat pour simplifier le tour.
D. Réessayer le 400 avec backoff exponentiel.
Réponse : B. Les blocs tool_use parallèles doivent être répondus avec tous les blocs tool_result dans un tour user, chacun correspondant à son id d’origine. Fusionner les ids (A) ou supprimer un résultat (C) casse le protocole ; le 400 est déterministe, donc le backoff (D) n’aidera pas.
Q16 · Un agent peut émettre des remboursements, mais tout remboursement de plus de $500 nécessite une approbation humaine. Où cela doit-il être imposé ? (Sélectionnez une réponse)
A. Dans la description de l’outil issue_refund (« confirmer avant de rembourser au-dessus de $500 »).
B. Dans un hook PreToolUse / workflow d’approbation qui bloque le remboursement au-dessus du seuil et route vers un humain, l’outil étant gardé hors des listes blanches des agents routiniers.
C. En baissant la température du modèle.
D. En demandant au modèle de revérifier le montant.
Réponse : B. Les actions irréversibles sont protégées de manière déterministe par un hook/approbation et le moindre privilège, pas par la description ou des auto-vérifications. Le texte de description (A) et les auto-vérifications (D) sont des consignes que le modèle peut ignorer (anti-pattern nº 3) ; la température (C) est sans rapport.
Q17 · Quelle interaction MCP a lieu à `initialize`, et comment les trois primitives sont-elles contrôlées ? (Sélectionnez une réponse)
A. La négociation des capacités a lieu à initialize ; les tools sont contrôlés par le modèle, les resources par l’application, les prompts par l’utilisateur.
B. L’authentification a lieu à initialize ; les trois primitives sont contrôlées par le modèle.
C. Rien ne se passe à initialize ; les primitives sont négociées par appel.
D. initialize renvoie le token OAuth ; les tools sont contrôlés par l’utilisateur.
Réponse : A. Les hosts et serveurs négocient les capacités à initialize, et la correspondance de contrôle est tools (modèle), resources (application), prompts (utilisateur). B étiquette mal toutes les primitives ; C est faux (la négociation se fait à l’init) ; D brouille la correspondance et se trompe sur OAuth.
Q18 · Un agent de support sur Fable 5.1 doit extraire de manière fiable des données de commande structurées, mais forcer l’outil d’extraction renvoie 400. Quelles DEUX approches sont valides ? (Sélectionnez deux réponses)
A. Utiliser tool_choice: 'auto' avec une instruction claire d’appeler l’outil d’extraction.
B. Utiliser les sorties structurées via output_config.format avec un schéma JSON.
C. Réessayer l’appel d’outil forcé avec backoff.
D. Passer tool_choice à none.
E. Rétrograder tout le trafic à Haiku 4.5.
Réponse : A et B. Fable 5.1 rejette le choix d’outil forcé/any, donc auto + instruction ou les sorties structurées sont valides. Le backoff (C) ne corrigera pas un 400 déterministe ; none (D) désactive les outils ; changer le modèle de chaque requête (E) est un changement trop large et injustifié.
Q19 · Un appel d’outil d’un serveur MCP distant échoue avec un timeout pendant un appel parallèle aux côtés d’un outil réussi. Comment l’appel échoué doit-il être représenté ? (Sélectionnez une réponse)
A. Omettre son tool_result pour que Claude passe à autre chose.
B. Renvoyer un tool_result avec le même tool_use_id, un message d’erreur, et is_error: true, dans le même tour user que le résultat réussi.
C. Réessayer silencieusement et renvoyer un contenu vide.
D. Faire planter la conversation pour forcer un redémarrage.
Réponse : B. Chaque tool_use nécessite un tool_result correspondant (avec is_error: true en cas d’échec) dans le même tour pour que Claude puisse récupérer. L’omettre (A) provoque un 400 et masque l’échec ; un contenu vide (C) est une suppression silencieuse (anti-pattern nº 7) ; planter (D) perd les diagnostics.
À retenir
- Le cycle de vie d’utilisation d’outils : définir les outils →
tool_use→ exécuter et renvoyertool_result(correspondant autool_use_id) → réponse finale. - La description d’outil et l’
input_schemasont le levier le plus important pour une utilisation correcte des outils. tool_choicevautauto/any/tool/none; Fable 5.1 rejetteanyet les outils forcés – utilisez les sorties structurées /strict/auto.- Les outils indépendants peuvent s’exécuter en parallèle ; renvoyez tous les résultats dans un tour
user. - Les outils côté client s’exécutent dans votre code ; les intégrés côté serveur (web search, exécution de code, computer use, éditeur de texte, bash, memory) s’exécutent chez Anthropic.
- Au-delà de ~10 outils, utilisez tool search +
defer_loading; exigez une approbation pour les actions irréversibles. - MCP est du JSON-RPC 2.0 avec tools (modèle), resources (app), prompts (utilisateur) ; stdio pour le local, Streamable HTTP + OAuth 2.1 pour le distant ; écrivez-le avec FastMCP (Python) ou
@modelcontextprotocol/sdk(TS). - La négociation des capacités a lieu à
initialize; choisissez stdio pour les outils en sous-processus local et Streamable HTTP + OAuth 2.1 pour les serveurs partagés/distants (SSE-only est hérité). - Protégez les outils irréversibles (remboursements/suppressions/envois/déploiements) avec un hook PreToolUse / workflow d’approbation et le moindre privilège — la description de l’outil est une consigne, pas une application.
- Renvoyez chaque
tool_resultparallèle dans un tour user indexé sur sontool_use_id, et marquez les échecs avecis_error: truepour que Claude puisse récupérer. - Un 400 d’outil forcé sur Fable 5.1 est déterministe — passez à
auto/aux sorties structurées plutôt que de réessayer avec backoff.
Dernière mise à jour le 18 sept. 2026