Version : 1.1 · Date : 2026-10-21 · Domaine 2 : Tool Design & MCP Integration (18 %)
En une phrase : Claude choisit un outil d'après son nom et sa description, votre code l'exécute et lui renvoie un résultat (ou une erreur structurée qui dit quoi faire ensuite) ; chaque agent ne reçoit que les 4 ou 5 outils de son rôle ; MCP branche ces outils sur Claude Code et l'Agent SDK sans code d'intégration, avec un
.mcp.jsond'équipe qui ne contient jamais de secret.

Ce que l'examen demande#
Texte officiel du Claude Certified Architect – Foundations Exam Guide v1.0 (juillet 2026), domaine 2 :
| TS | Task statement (guide officiel, en anglais) | Section |
|---|---|---|
| 2.1 | Design effective tool interfaces with clear descriptions and boundaries | 2 |
| 2.2 | Implement structured error responses for MCP tools | 3 |
| 2.3 | Distribute tools appropriately across agents and configure tool choice | 4 |
| 2.4 | Integrate MCP servers into Claude Code and agent workflows | 5 |
| 2.5 | Select and apply built-in tools (Read, Write, Edit, Bash, Grep, Glob) effectively | 6 |
Scénarios d'examen où ce domaine pèse le plus : 1 Customer Support Resolution Agent (outils MCP get_customer,
lookup_order, process_refund, escalate_to_human), 3 Multi-Agent Research System et 4 Developer Productivity with
Claude (outils intégrés et serveurs MCP). Voir 06-scenarios-examen.md.
Réponse d'examen ou état actuel. Le guide v1.0 date de juillet 2026 et le produit a évolué depuis. À l'examen, on répond selon le guide. Dans ce chapitre, chaque écart est signalé par un encadré « Réponse d'examen / État actuel », vérifié sur la documentation officielle le 21/10/2026.
1. Les bases : tool use et MCP en dix minutes#
1.1 Client tools et server tools#
Tool use (ou function calling) permet à Claude d'appeler des fonctions. Claude décide quand appeler un outil à partir de la demande et de la description de l'outil, puis renvoie un appel structuré.
| Client tools | Server tools | |
|---|---|---|
| Qui exécute | Votre application | L'infrastructure d'Anthropic |
| Exemples | Vos outils (get_customer), bash, text_editor, memory |
web_search, web_fetch, code_execution, tool_search |
| Ce que vous gérez | Lire le tool_use, exécuter, renvoyer un tool_result |
Rien : le résultat arrive dans la même réponse |
C'est ce que l'examen teste : vos propres outils, donc des client tools.
1.2 Le cycle, pas à pas#
sequenceDiagram
participant U as Utilisateur
participant A as Votre application
participant C as Claude API
U->>A: demande
A->>C: messages + tools (name, description, input_schema)
C-->>A: stop_reason = tool_use, bloc tool_use (id, name, input)
A->>A: exécute l'outil
A->>C: message user avec tool_result (tool_use_id, content, is_error)
C-->>A: stop_reason = end_turn, réponse finale
A-->>U: réponse
Règles de format à connaître (doc Handle tool calls) :
- Le
tool_resultreprend letool_use_idde l'appel et suit immédiatement le message assistant qui contient letool_use. - Dans le message
user, les blocstool_resultviennent en premier ; un texte éventuel vient après. is_error: truesignale un échec ; lecontentexplique ce qui s'est passé et quoi essayer ensuite.- La boucle continue tant que
stop_reasonvaut"tool_use": c'est le sujet de la boucle agentique (01-agentic-architecture.md).
1.3 Une définition d'outil#
{
"name": "lookup_order",
"description": "Retrieves one order by its order ID and returns status, items, amount and shipping date. Use it when the customer mentions an order, a delivery or a refund for a specific order. Order IDs look like ORD-12345. It does not return customer profile data: use get_customer for name, email or account status. If the order ID is unknown, ask the customer for it instead of guessing.",
"input_schema": {
"type": "object",
"properties": {
"order_id": { "type": "string", "description": "Order ID, format ORD- followed by 5 digits, e.g. ORD-12345" }
},
"required": ["order_id"]
}
}
name:^[a-zA-Z0-9_-]{1,128}$.input_schema: un JSON Schema.- Champs optionnels :
input_examples(exemples validés par le schéma, utiles pour les entrées complexes),strict: true(entrées garanties conformes au schéma),defer_loading(tool search),cache_control.
Côté résultat :
{
"role": "user",
"content": [
{ "type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": "Order service timeout after 10 s. Retry once in 30 seconds.", "is_error": true }
]
}
1.4 MCP en une image#
Le Model Context Protocol (MCP) standardise la façon dont une application d'IA, le MCP host (Claude Code, Claude Desktop, votre application Agent SDK), se connecte à des MCP servers qui exposent des tools, des resources et des prompts. Le host crée un MCP client par serveur. Le détail est dans la section 5.
| Terme | Ce que c'est |
|---|---|
| MCP server | Programme qui expose des tools, resources, prompts (local en stdio, distant en Streamable HTTP) |
tools/list, tools/call |
Découverte puis appel d'un outil (JSON-RPC 2.0) |
isError |
Champ du résultat MCP qui signale une erreur d'exécution d'outil (équivalent du is_error de l'API) |
.mcp.json |
Fichier de configuration MCP du projet, versionné dans le dépôt |
mcp__{serveur}__{outil} |
Nom complet d'un outil MCP dans Claude Code et l'Agent SDK |
2. TS 2.1 : des interfaces d'outils claires#
2.1 Ce que l'examen teste#
- La description est le premier mécanisme dont le modèle se sert pour choisir un outil ; une description minimale rend le choix peu fiable entre outils proches.
- Une bonne description contient les formats d'entrée, des exemples de requêtes, les cas limites et les frontières avec les outils voisins.
- Des descriptions ambiguës ou qui se recouvrent causent du mauvais routage (
analyze_contentcontreanalyze_document). - La formulation du system prompt compte : une consigne à mots-clés peut créer une association d'outil non voulue.
- Savoir renommer, scinder un outil fourre-tout, et relire le system prompt.

2.2 La description d'abord#
La doc officielle est nette : des descriptions « extrêmement détaillées » sont de loin le facteur le plus important pour la performance des outils. Elles disent ce que fait l'outil, quand l'utiliser et quand ne pas l'utiliser, ce que signifie chaque paramètre, et les limites (ce que l'outil ne renvoie pas). Visez au moins 3 ou 4 phrases par outil.
Avant / après, dans le scénario support client :
| Outil | Avant (mal routé) | Après |
|---|---|---|
get_customer |
« Gets customer info. » | « Returns the customer profile (name, email, tier, account status) for a customer ID (CUS-…) or an email. Use it to identify or verify the customer. It does not return orders: use lookup_order for anything about a specific order, delivery or refund. » |
lookup_order |
« Looks up an order. » | Voir la définition complète en 1.3 |
La frontière explicite (« pour X, utilise plutôt Y ») est l'élément qui corrige le plus directement un mauvais routage entre deux outils voisins.
2.3 Renommer, scinder, consolider#
| Situation | Correction | Exemple du guide |
|---|---|---|
| Deux outils aux noms et descriptions presque identiques | Renommer et réécrire la description | analyze_content → extract_web_results (description propre au web) |
| Un outil générique qui fait tout | Scinder en outils à contrat d'entrée/sortie défini | analyze_document → extract_data_points, summarize_content, verify_claim_against_source |
| Plusieurs variantes d'une même opération | Consolider en un outil avec un paramètre action (doc actuelle) |
create_pr, review_pr, merge_pr → un outil |
Scinder et consolider ne se contredisent pas : on scinde ce qui fait des choses différentes derrière un même nom, on
consolide des variantes de la même opération. Le guide teste surtout le renommage et la scission ; la consolidation et le
namespacing par service (github_list_prs, slack_send_message) viennent de la doc et de l'article Writing tools for agents.
2.4 Le system prompt peut défaire une bonne description#
Une consigne comme « analyse toujours le contenu avant de répondre » pousse le modèle vers tout outil nommé analyze_*, même avec
de bonnes descriptions. Après avoir réécrit les descriptions, relisez le system prompt et retirez les mots-clés qui orientent
vers un outil précis.
2.5 Le bon ordre des corrections#
Quand deux outils sont confondus, l'examen attend la correction la moins chère et la plus directe :
- Enrichir les descriptions (formats, exemples, frontières).
- Renommer ou scinder si les outils se recouvrent vraiment.
- Seulement ensuite : few-shot, classifieur de routage, fusion d'outils. Ce sont des réponses piège en premier recours (coût, complexité, ou traitement du symptôme).
Réponse d'examen / État actuel. Le guide illustre la surcharge par « 18 outils au lieu de 4-5 » (voir 4.1). La doc actuelle du tool search tool indique que la précision de choix se dégrade au-delà de 30 à 50 outils et propose de charger les outils à la demande (
defer_loading: true). À l'examen, retenez le cadrage du guide.
3. TS 2.2 : des erreurs structurées pour les outils MCP#
3.1 Ce que l'examen teste#
- Le mécanisme
isErrorde MCP pour signaler un échec d'outil à l'agent. - Quatre familles : transient (timeout, indisponibilité), validation (entrée invalide), business (règle métier), permission.
- Pourquoi un message uniforme (« Operation failed ») empêche l'agent de choisir la bonne reprise.
- La différence entre retryable et non-retryable, et comment les métadonnées évitent des réessais inutiles.
- Savoir renvoyer
errorCategory,isRetryableet une description lisible ;retriable: falseavec une explication présentable au client pour une règle métier ; récupérer localement dans le subagent ; distinguer échec d'accès et résultat vide valide.

3.2 Deux couches d'erreur dans MCP#
| Protocol error | Tool execution error | |
|---|---|---|
| Cas | Outil inconnu, requête mal formée, panne du serveur | L'outil a tourné et a échoué : API en panne, entrée refusée, règle métier |
| Forme | Réponse JSON-RPC error (code, message) |
result avec isError: true et un content explicatif |
| Qui la traite | L'application hôte ; le client peut la transmettre au modèle | Le modèle, que le client devrait informer pour qu'il se corrige |
Règle pratique du SDK Python MCP : « un modèle plus intelligent aurait-il pu éviter cette erreur ? » Si oui, c'est une erreur d'exécution d'outil (le modèle la voit et corrige) ; sinon, une erreur de protocole.
3.3 Les quatre catégories et isRetryable#
isRetryable répond à une seule question : renvoyer exactement le même appel peut-il réussir ?
errorCategory |
Exemple | isRetryable |
Reprise attendue |
|---|---|---|---|
transient |
timeout, service indisponible | true |
Réessayer après un délai (dans le subagent) |
validation |
ID mal formé, date dans le passé | false |
Corriger l'entrée, puis un nouvel appel |
business |
remboursement au-delà du plafond, politique | false |
Expliquer au client, chemin alternatif, escalade |
permission |
accès refusé | false |
Escalader ou utiliser d'autres droits |
false ne veut pas dire « abandonner » : cela veut dire « pas cet appel une deuxième fois ».
Réponse d'examen / État actuel. Le guide donne
errorCategory(transient/validation/permission) etisRetryable, etretriable: falsepour une règle métier. Ces champs sont une convention applicative, pas des champs de la spécification MCP : la spec définit seulementisErroret uncontent(plus unstructuredContentfacultatif). Vous les placez dans le texte du résultat ou dansstructuredContent.
3.4 À quoi ressemble une bonne erreur#
Résultat MCP d'une règle métier (le modèle le voit) :
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"content": [{ "type": "text", "text": "{\"errorCategory\": \"business\", \"isRetryable\": false, \"description\": \"Refunds above 500 USD need a human agent.\", \"customerMessage\": \"This refund needs a quick review by our team. I'm transferring you now.\"}" }],
"isError": true
}
}
Résultat vide valide, à ne surtout pas présenter comme une erreur :
{ "content": [{ "type": "text", "text": "{\"resultCount\": 0, \"customers\": []}" }], "isError": false }
Le même outil avec le SDK Python officiel (classe MCPServer) : une ToolError devient un résultat isError: true que le
modèle voit, alors qu'un retour normal reste un succès.
import json
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError
mcp = MCPServer("support")
def erreur(categorie: str, reessayable: bool, description: str) -> ToolError:
# Métadonnées lisibles par l'agent : il choisit la reprise sans deviner
return ToolError(json.dumps({"errorCategory": categorie, "isRetryable": reessayable, "description": description}))
@mcp.tool()
def search_customers(email: str) -> str:
"""Finds customer accounts by exact email address. Returns a JSON list of matching customers
(id, name, tier). An empty list means no account uses this email: do not retry, ask the customer."""
if "@" not in email:
raise erreur("validation", False, "Email must contain '@', e.g. [email protected]")
try:
comptes = crm.find_by_email(email) # appel au CRM (votre code)
except TimeoutError:
raise erreur("transient", True, "CRM timeout after 10 s, retry in 30 s")
return json.dumps({"resultCount": len(comptes), "customers": comptes}) # 0 résultat = succès
if __name__ == "__main__":
mcp.run(transport="stdio")
Le tutoriel officiel Build an MCP server renvoie "Unable to fetch alerts or no alerts found." dans un seul message : c'est
exactement la confusion « échec d'accès / résultat vide » que l'examen demande de corriger.
3.5 Récupérer localement, remonter le reste#
flowchart TD
A["Le subagent reçoit isError: true"] --> B{"isRetryable ?"}
B -->|"oui (transient)"| C["Réessai local avec délai, nombre limité"]
C --> D{"Réussi ?"}
D -->|"oui"| E["Continue la tâche"]
D -->|"non"| F["Remonte au coordinateur : type d'échec, requête tentée, résultats partiels"]
B -->|"non"| G{"Catégorie"}
G -->|"validation"| H["Corrige l'entrée, nouvel appel"]
G -->|"business"| I["Explique au client, chemin alternatif ou escalade"]
G -->|"permission"| F
Deux anti-patterns, tous deux testés : masquer l'erreur (renvoyer un résultat vide comme un succès : le coordinateur ne sait plus distinguer « rien trouvé » de « recherche impossible ») et tout arrêter au premier échec. La propagation entre agents est détaillée au domaine 5 (05-context-reliability.md, TS 5.3).
4. TS 2.3 : répartir les outils et régler tool_choice#
4.1 Ce que l'examen teste#
- Trop d'outils (18 au lieu de 4-5) dégrade la fiabilité du choix.
- Un agent qui a des outils hors de sa spécialité les utilise mal (un agent de synthèse qui lance des recherches web).
- Scoped tool access : seulement les outils du rôle, plus quelques outils transverses limités pour des besoins fréquents.
- Les options de
tool_choice:"auto","any", et la sélection forcée{"type": "tool", "name": "..."}. - Remplacer un outil générique par une version contrainte (
fetch_url→load_documentqui valide les URL de documents).

4.2 Un rôle, un petit jeu d'outils#
| Principe | Pourquoi | Exemple |
|---|---|---|
| 4-5 outils par agent, propres au rôle | Moins de décisions, moins d'erreurs de choix | Le subagent web n'a que search_web, fetch_page, extract_links, save_snippet |
| Pas d'outil hors spécialité | Il serait mal utilisé | L'agent de synthèse n'a pas search_web |
| Outil contraint plutôt que générique | Moindre privilège, moins d'usages détournés | load_document (URL de documents seulement) plutôt que fetch_url |
| Outil transverse limité pour le fréquent | Évite les allers-retours par le coordinateur | verify_fact sur l'agent de synthèse pour les vérifications simples ; le complexe repasse par le coordinateur |
| Le coordinateur délègue | Il garde la vue d'ensemble | Outils Agent (ex-Task), revue, demande de révision |
Ajouter un serveur MCP de plus ne règle pas une surcharge : le client présente tous les outils à plat au modèle.
Dans l'Agent SDK, on restreint les outils d'un subagent dans sa définition (tools d'un AgentDefinition), et on autorise les
outils MCP par leur nom complet dans allowedTools :
from claude_agent_sdk import ClaudeAgentOptions
options = ClaudeAgentOptions(
mcp_servers={"docs": {"command": "python", "args": ["docs_server.py"]}},
allowed_tools=["mcp__docs__load_document", "mcp__docs__extract_metadata"], # seulement ces deux outils
)
4.3 tool_choice#

| Valeur | Effet | Usage type |
|---|---|---|
{"type": "auto"} |
Claude choisit : un outil ou du texte (défaut quand tools est fourni) |
Cas général |
{"type": "any"} |
Un outil obligatoire, Claude choisit lequel | Garantir un appel plutôt qu'une réponse conversationnelle (extraction parmi plusieurs schémas) |
{"type": "tool", "name": "extract_metadata"} |
Cet outil-là | Imposer le premier outil, puis auto aux tours suivants |
{"type": "none"} |
Aucun outil (défaut sans tools) |
Forcer une réponse texte |
Sélection forcée au premier tour, puis retour à auto :
premier = client.messages.create(
model=MODELE, max_tokens=1024, tools=outils, messages=messages,
tool_choice={"type": "tool", "name": "extract_metadata"}, # métadonnées d'abord
)
# … exécuter extract_metadata, ajouter le tool_result à messages …
suite = client.messages.create(
model=MODELE, max_tokens=1024, tools=outils, messages=messages,
tool_choice={"type": "auto"}, # enrichissement librement ensuite
)
Réponse d'examen / État actuel. Le guide attend
anypour garantir un appel et la sélection forcée pour imposer l'ordre. La doc actuelle précise : avecanyoutool, l'API préremplit la réponse, donc pas de texte ni de thinking avant l'appel ; le thinking manuel (thinking: {type: "enabled"}) les refuse ; Claude Opus 5.5, Claude Sonnet 5.5 et Claude Fable 5.1 renvoient une erreur 400 pouranyettool, y compris surcount_tokenset dans les lots (Claude Opus 5, Claude Fable 5 et Claude Haiku 5.5 les acceptent encore). Sur ces modèles, on utiliseautoavec strict tool use (strict: true) ou les structured outputs, et le prompt nomme l'outil attendu.autone garantit pas l'appel : le code vérifie qu'untool_useest bien revenu et relance sinon.
5. TS 2.4 : intégrer des serveurs MCP#
5.1 Ce que l'examen teste#
- Portées :
.mcp.json(projet) pour l'outillage d'équipe ;~/.claude.json(utilisateur) pour le personnel et l'expérimental. - Expansion des variables d'environnement dans
.mcp.json(${GITHUB_TOKEN}) pour ne jamais committer de secret. - Les outils de tous les serveurs configurés sont découverts à la connexion et disponibles en même temps.
- Les MCP resources exposent des catalogues (résumés d'issues, arborescence de doc, schémas de base) pour éviter les appels exploratoires.
- Préférer un serveur communautaire pour une intégration standard (Jira) ; réserver le serveur maison aux workflows propres à l'équipe.
- Enrichir les descriptions des outils MCP pour que l'agent ne leur préfère pas un outil intégré (Grep) moins adapté.

5.2 Architecture et transports#
| Élément | Rôle |
|---|---|
| MCP host | L'application d'IA (Claude Code, Claude Desktop, votre app Agent SDK) |
| MCP client | Un par serveur, connexion dédiée |
| MCP server | Expose ses primitives ; local ou distant |
| stdio | Serveur local lancé comme processus ; échanges sur stdin/stdout. Ne jamais écrire sur stdout (logs sur stderr) |
| Streamable HTTP | Serveur distant ; transport recommandé pour le distant. SSE est déprécié côté Claude Code |
| Primitive | Contrôlée par | Pour quoi faire |
|---|---|---|
| Tools | Le modèle | Agir : tools/call |
| Resources | L'application | Donner du contexte : catalogues, schémas, documents (resources/read) |
| Prompts | L'utilisateur | Modèles d'invite réutilisables, exposés en commandes dans Claude Code |
La découverte, l'hébergement et l'authentification OAuth des serveurs sont hors programme. L'examen porte sur la configuration et la conception des outils et resources.
5.3 Portées et .mcp.json#

.mcp.json à la racine du dépôt (versionné, partagé avec l'équipe) :
{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": { "Authorization": "Bearer ${GITHUB_TOKEN}" }
},
"jira": {
"command": "npx",
"args": ["-y", "{serveur-jira-communautaire}"],
"env": { "JIRA_API_TOKEN": "${JIRA_API_TOKEN}", "JIRA_URL": "${JIRA_URL:-https://jira.example.com}" }
}
}
}
- Un serveur distant déclare
"type": "http"et uneurl; un serveur local déclarecommandetargs(stdio). ${VAR}est remplacé au chargement ;${VAR:-défaut}donne une valeur par défaut. L'expansion vaut pourcommand,args,env,urletheaders.- Chacun définit ses tokens localement (profil shell,
.envignoré par Git, gestionnaire de secrets). La rotation d'un token ne change pas le fichier.
Ajouter un serveur en ligne de commande :
# Serveur d'équipe, écrit dans .mcp.json
claude mcp add --transport http --scope project github https://api.githubcopilot.com/mcp/
# Serveur personnel en stdio (le "--" sépare les options de Claude de la commande du serveur)
claude mcp add --scope user --env NOTES_DIR=/home/moi/notes mes-notes -- python notes_server.py
claude mcp list # état des serveurs, avertissement si une variable manque
Réponse d'examen / État actuel. Le guide présente deux niveaux : projet (
.mcp.json) et utilisateur (~/.claude.json). Claude Code en a aujourd'hui trois, choisis par-s/--scope:
local(par défaut) : ce projet, pour vous seul, stocké dans~/.claude.json;project: partagé par.mcp.json;user: tous vos projets, dans~/.claude.json.En cas de doublon de nom, local > project > user, et Claude Code demande une approbation avant d'utiliser un serveur de
.mcp.json. Une variable absente sans défaut ne bloque pas le chargement : un avertissement s'affiche dansclaude mcp listet${VAR}reste tel quel. Exception de sécurité : dansurletheadersd'un serveur distant, certaines variables d'identifiants sensibles (par exempleANTHROPIC_API_KEY,NPM_TOKEN) sont lues comme vides.
5.4 Découverte, nommage et Agent SDK#
À la connexion, le host appelle tools/list sur chaque serveur : tous les outils de tous les serveurs sont disponibles
ensemble, sans étape d'activation. Chaque outil MCP prend le nom mcp__{serveur}__{outil} (par exemple mcp__github__list_issues),
qu'on utilise dans les permissions et dans allowedTools.
Agent SDK (TypeScript), serveurs déclarés dans le code ; un .mcp.json du projet est aussi chargé par défaut :
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "List the 3 most recent issues in our repository",
options: {
mcpServers: {
github: { type: "http", url: "https://api.githubcopilot.com/mcp/",
headers: { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` } }
},
allowedTools: ["mcp__github__list_issues"] // ou "mcp__github__*" pour tout le serveur
}
})) {
if (message.type === "system" && message.subtype === "init") console.log(message.mcp_servers); // état de chaque serveur
if (message.type === "result" && message.subtype === "success") console.log(message.result);
}
Sans permission dans allowedTools, Claude voit les outils MCP mais ne peut pas les appeler.
5.5 Les resources comme catalogue#
Sans resource, un agent qui doit écrire une requête SQL appelle list_tables, puis describe_table pour chaque table. Une
resource « schéma » lui donne le catalogue d'un coup.
@mcp.resource("db://schema/main", mime_type="application/json")
def schema_principal() -> str:
"""Full schema of the main database: tables, columns, types, foreign keys."""
return json.dumps(lire_schema())
@mcp.prompt()
def analyse_incident(ticket_id: str) -> str:
"""Prepare an incident analysis for a ticket."""
return f"Analyse le ticket {ticket_id} : chronologie, cause probable, actions."
Dans Claude Code, on attache une resource par mention, comme un fichier (@db:db://schema/main, @github:issue://123), et un
prompt MCP devient une commande (/mcp__github__pr_review 456).
5.6 Communautaire ou maison, et la concurrence des outils intégrés#
| Besoin | Choix |
|---|---|
| Intégration standard (GitHub, Jira, Slack…) | Serveur communautaire ou officiel existant : maintenu, testé |
| Workflow propre à l'équipe, logique métier, système interne sans équivalent | Serveur maison |
Un outil MCP mal décrit perd face à un outil intégré bien décrit : si search_codebase (MCP, avec index sémantique) n'a qu'une
ligne de description, Claude utilisera Grep. La correction attendue est d'enrichir la description de l'outil MCP
(capacités, sorties, quand le préférer à Grep), pas d'ajouter une règle de prompt ni de retirer Grep.
5.7 Un serveur MCP minimal en TypeScript#
Le SDK TypeScript officiel (McpServer, schémas zod) ; une erreur d'exécution se renvoie avec isError: true :
import { McpServer } from "@modelcontextprotocol/server";
import { serveStdio } from "@modelcontextprotocol/server/stdio";
import { z } from "zod";
function createServer() {
const server = new McpServer({ name: "orders", version: "1.0.0" });
server.registerTool(
"lookup_order",
{
description: "Retrieves one order by ID (format ORD-12345): status, items, amount. Not for customer profiles: use get_customer.",
inputSchema: z.object({ order_id: z.string().describe("Order ID, e.g. ORD-12345") }),
},
async ({ order_id }) => {
if (!/^ORD-\d{5}$/.test(order_id)) {
return { isError: true, content: [{ type: "text",
text: JSON.stringify({ errorCategory: "validation", isRetryable: false, description: "Expected ORD- followed by 5 digits" }) }] };
}
const commande = await chercherCommande(order_id); // votre accès aux données
return { content: [{ type: "text", text: JSON.stringify(commande ?? { resultCount: 0 }) }] };
},
);
return server;
}
serveStdio(createServer, { onerror: (e) => console.error("orders MCP error:", e) }); // logs sur stderr
État actuel (hors examen). La spécification MCP 2026-07-28 rend le protocole sans état : chaque requête porte sa version et ses capacités dans
_meta, et la découverte passe parserver/discover.serveStdiogère encore les clients de l'ancienne poignée de maininitialize. Rien de cela n'est demandé à l'examen.
6. TS 2.5 : les outils intégrés de Claude Code#
6.1 Ce que l'examen teste#
- Grep cherche dans le contenu (noms de fonctions, messages d'erreur, imports).
- Glob cherche des chemins par motif (
**/*.test.tsx). - Read/Write pour un fichier entier ; Edit pour une modification ciblée par texte unique.
- Quand Edit échoue (texte non unique) : Read + Write en repli.
- Comprendre un code par étapes : Grep pour les points d'entrée, Read pour suivre les imports, au lieu de tout lire.
- Suivre une fonction à travers des modules d'enveloppe : relever tous les noms exportés, puis chercher chacun.

6.2 Le bon outil#
| Outil | Fait | Permission (mode manuel) | Piège |
|---|---|---|---|
Glob |
Trouve des fichiers par motif de nom | Non | Ne lit pas le contenu : inutile pour trouver des appelants |
Grep |
Cherche un motif dans le contenu (ripgrep) | Non | Pour trouver des fichiers par extension, c'est Glob |
Read |
Lit un fichier | Non | Lire tout le dépôt sature le contexte |
Edit |
Remplace un old_string exact et unique |
Oui | Échoue si le texte n'est pas unique (protection voulue) |
Write |
Crée ou écrase un fichier | Oui | Réécrire un fichier entier coûte du contexte |
Bash |
Exécute une commande | Oui | Pas un remplaçant de Grep/Glob quand ils sont disponibles |
6.3 Explorer par étapes#
sequenceDiagram
participant C as Claude
participant R as Dépôt
C->>R: Grep sur processLegacyOrder
R-->>C: 6 fichiers appelants, dont lib/orders/index.ts
C->>R: Read lib/orders/index.ts
R-->>C: réexport sous le nom handleOrder
C->>R: Grep sur handleOrder
R-->>C: 4 appelants de plus, via le nom réexporté
C->>R: Glob sur les fichiers de test order
R-->>C: fichiers de test à mettre à jour
C->>R: Read seulement les fichiers retenus, puis Edit
Le piège des réexports : une fonction définie sous un nom, réexportée sous un autre (fichier barrel), échappe à un Grep sur le nom d'origine. On lit les exports du fichier de définition, puis on cherche chaque nom.
Réponse d'examen / État actuel.
- Édition : le guide attend Read + Write quand Edit échoue sur un texte non unique. La doc actuelle fait d'abord allonger
old_stringavec plus de contexte, ou utiliserreplace_all: truesi toutes les occurrences doivent changer.- Disponibilité : sur macOS, Linux et WSL,
GlobetGrepsont absents par défaut, et Claude cherche avecfindetgrepviaBash. Sur Windows, ils sont dans le jeu par défaut. À l'examen, considérez-les comme des outils intégrés.
7. Labs conseillés#
Avec un compte API de test et Claude Code ; coût faible (quelques centimes par lab avec un modèle léger). Ne mettez aucun vrai secret dans les fichiers d'exemple.
Lab 1 : corriger un mauvais routage (TS 2.1, 30 min).
- Déclarer
get_customeretlookup_orderavec une description d'une ligne chacune. - Envoyer 10 demandes variées (« où en est ma commande ORD-12345 ? », « changez mon email »…) et noter l'outil choisi.
- Réécrire les deux descriptions avec les 5 éléments et une frontière explicite.
- Rejouer les 10 demandes. Résultat attendu : le routage devient correct sans few-shot ni classifieur.
Lab 2 : un serveur MCP avec erreurs structurées (TS 2.2, 45 min).
- Écrire
search_customers(section 3.4) sur une base factice, avec un paramètre de test qui déclenche chaque catégorie. - Renvoyer
transient,validation,business,permission, et un résultat vide valide. - L'ajouter à Claude Code (
claude mcp add … -- python serveur.py) et lui demander des recherches. Résultat attendu : Claude réessaie seulement le transient, corrige la validation, explique la règle métier et ne réessaie pas le résultat vide.
Lab 3 : tool_choice et sélection forcée (TS 2.3, 20 min).
- Sur un modèle qui accepte la sélection forcée, imposer
extract_metadataau premier tour, puisauto. - Essayer
anysur une demande conversationnelle. Résultat attendu : un appel d'outil, jamais de texte seul. - Rejouer avec Claude Opus 5.5 ou Sonnet 5.5. Résultat attendu : erreur 400 ; passer à
auto+strict: true.
Lab 4 : un .mcp.json d'équipe (TS 2.4, 30 min).
- Créer
.mcp.jsonavec un serveur distant et"Authorization": "Bearer ${GITHUB_TOKEN}". - Vérifier avec
git diffqu'aucun secret n'est indexé ; lancerclaude mcp listsans la variable (avertissement), puis avec. - Ajouter un serveur personnel en portée
user. Résultat attendu :/mcpmontre les deux serveurs, leurs outils sont disponibles en même temps.
Lab 5 : tracer une fonction dépréciée (TS 2.5, 20 min).
- Dans un dépôt de test, renommer une fonction via un fichier
index.tsqui la réexporte sous un autre nom. - Demander à Claude Code de lister tous les appelants et leurs tests. Résultat attendu : Grep, Read des exports, Grep du nouveau nom, Glob des tests ; aucun « Read de tout le dépôt ».
8. Pièges d'examen#
| Piège | Bonne réponse |
|---|---|
| Deux outils confondus : ajouter des few-shot | Enrichir les descriptions d'abord (formats, exemples, frontières) |
| Deux outils confondus : un classifieur de routage en amont | Surdimensionné en premier recours ; corriger les descriptions |
| Descriptions réécrites mais le mauvais outil persiste | Relire le system prompt : une consigne à mots-clés attire l'outil |
analyze_document fait extraction, résumé et vérification |
Scinder en outils à contrat défini |
| Message d'erreur générique « Operation failed » | errorCategory, isRetryable, description lisible |
Erreur de validation marquée isRetryable: true |
false : le même appel échouera encore ; corriger l'entrée |
| Règle métier réessayée | isRetryable: false + explication présentable au client |
| Recherche sans résultat réessayée 3 fois | C'est un succès vide : ne pas réessayer |
Subagent qui renvoie [] quand la source est inaccessible |
Masquage : renvoyer une erreur avec ce qui a été tenté |
| Subagent qui fait échouer tout le workflow au premier timeout | Réessai local, puis erreur structurée avec résultats partiels |
| 18 outils à un seul agent | 4-5 outils par rôle |
| Ajouter un serveur MCP pour « isoler » des outils | Le client les présente tous à plat : répartir par agent |
| Agent de synthèse qui demande toujours au coordinateur de vérifier un fait simple | Outil transverse limité verify_fact, le complexe passe par le coordinateur |
fetch_url pour charger des documents |
load_document qui valide les URL |
Sortie structurée requise avec tool_choice: auto |
any (ou un outil forcé) selon le guide |
| Imposer un premier outil | {"type": "tool", "name": ...} puis auto aux tours suivants |
Serveur d'équipe dans ~/.claude.json |
.mcp.json du projet |
Token collé dans .mcp.json « parce que le dépôt est privé » |
${GITHUB_TOKEN} ; un dépôt privé n'est pas un coffre-fort |
| Construire un serveur Jira maison | Évaluer d'abord un serveur communautaire |
| L'agent préfère Grep à l'outil MCP plus capable | Enrichir la description de l'outil MCP |
Appels répétés list_tables / describe_table |
Exposer le schéma en MCP resource |
| Glob pour trouver les appelants d'une fonction | Grep (contenu) |
Grep pour trouver tous les fichiers *.test.tsx |
Glob (chemins) |
| Lire tous les fichiers avant d'analyser | Exploration incrémentale |
| Edit échoue (texte non unique) | Guide : Read + Write (aujourd'hui : plus de contexte ou replace_all) |
9. Scénarios corrigés#
Format de l'examen : une seule bonne réponse sauf mention contraire. Les questions officielles du guide sont commentées dans 06-scenarios-examen.md.
1. Customer Support Resolution Agent. Les journaux montrent que l'agent appelle process_refund pour des demandes
d'information sur un remboursement déjà fait. Les deux outils process_refund et get_refund_status ont une description d'une
ligne. Que faire en premier ?
- A. Ajouter une règle « n'appelle process_refund qu'après confirmation » au system prompt
- B. Réécrire les deux descriptions : effet, entrées, cas d'usage, et la frontière « pour connaître l'état d'un remboursement existant, utilise get_refund_status »
- C. Fusionner les deux outils en
refund(action) - D. Ajouter un classifieur qui choisit l'outil avant Claude
B. La description est le premier critère de choix ; la frontière explicite corrige la confusion. A est probabiliste et traite le symptôme, C et D sont plus lourds.
2. Multi-Agent Research System. Le subagent de recherche web reçoit un timeout de l'API de recherche, réessaie deux fois sans succès. Que doit-il remonter au coordinateur ?
- A. Une liste vide, pour ne pas bloquer la synthèse
- B. « Operation failed »
- C. Une erreur structurée : type
transient, requête tentée, réessais effectués, résultats partiels déjà obtenus - D. Rien : il doit arrêter tout le workflow
C. Récupération locale d'abord, puis seulement l'irrécupérable, avec ce qui a été tenté et les résultats partiels. A masque l'échec, B empêche la décision, D est l'autre anti-pattern.
3. Un outil search_customers renvoie isError: true avec « No customer found » quand l'email n'existe pas, et l'agent
réessaie trois fois avant d'escalader. Quelle correction ?
- A. Monter la limite de réessais à 5
- B. Renvoyer
isError: falseetresultCount: 0: c'est une réponse valide - C. Interdire les réessais dans le system prompt
- D. Marquer l'erreur
isRetryable: false
B. « Aucune correspondance » n'est pas une erreur. D réduit le gaspillage mais garde un mauvais signal (l'agent croit à un échec).
4. Quelle combinaison est correcte pour une demande de remboursement de 900 USD refusée par une règle « au-delà de 500 USD, validation humaine » ? (2 réponses)
- A.
errorCategory: "business" - B.
isRetryable: true - C. Une explication présentable au client
- D.
errorCategory: "transient"
A et C. Règle métier, non réessayable, avec un message que l'agent peut transmettre ; l'escalade suit (domaine 5).
5. Developer Productivity with Claude. Un agent unique a reçu 19 outils (fichiers, CI, tickets, documentation, base de données) et se trompe souvent d'outil. Quelle approche ?
- A. Raccourcir les descriptions pour réduire le contexte
- B. Répartir les outils entre subagents spécialisés de 4 à 5 outils chacun, le coordinateur délégant
- C. Déplacer la moitié des outils sur un second serveur MCP
- D. Passer
tool_choiceàany
B. Trop d'outils dégrade le choix ; C ne change rien (tous les outils restent visibles), D force un appel sans aider le choix.
6. Un pipeline doit toujours exécuter extract_metadata avant les outils d'enrichissement. Quelle configuration le garantit,
selon le guide ?
- A.
tool_choice: {"type": "auto"}et une consigne « commence par extract_metadata » - B.
tool_choice: {"type": "any"} - C.
tool_choice: {"type": "tool", "name": "extract_metadata"}au premier tour, puisauto - D. Retirer les autres outils de la requête définitivement
C. La sélection forcée impose cet outil ; les étapes suivantes se font aux tours suivants. A reste probabiliste, B laisse choisir n'importe quel outil.
7. L'équipe veut que tous les développeurs aient le serveur GitHub dans Claude Code, sans secret dans Git, et un développeur veut tester un serveur expérimental pour lui seul. Quelle configuration ?
- A. Les deux dans
.mcp.json, avec le token en clair puisque le dépôt est privé - B. GitHub dans
.mcp.jsonavec${GITHUB_TOKEN}; l'expérimental en portée utilisateur (~/.claude.json) - C. Les deux dans
~/.claude.jsonde chaque développeur - D. GitHub dans
~/.claude.json, l'expérimental dans.mcp.json
B. Partagé et versionné pour l'équipe, secrets en variables d'environnement ; personnel hors du dépôt.
8. Un serveur MCP maison expose semantic_code_search (index sémantique du code), mais Claude utilise presque toujours Grep.
Que faire ?
- A. Retirer Grep des outils autorisés
- B. Ajouter au system prompt « utilise toujours semantic_code_search »
- C. Enrichir la description de
semantic_code_search: capacités, format des résultats, et quand le préférer à Grep - D. Renommer l'outil en
grep_semantic
C. Le guide le cite explicitement. A casse des usages légitimes, B est probabiliste, D crée une confusion de nom.
9. Un agent d'analyse écrit des requêtes SQL et appelle à chaque session list_tables puis describe_table pour 40 tables.
Comment réduire ces appels ?
- A. Exposer le schéma de la base comme MCP resource
- B. Augmenter
max_tokens - C. Mettre le schéma complet dans chaque description d'outil
- D. Ajouter un outil
describe_all_tables
A. Les resources servent à exposer des catalogues et évitent les appels exploratoires. D marcherait mais reste un appel exploratoire ; C alourdit chaque requête.
10. Il faut trouver tous les appelants de formatInvoice() dans un dépôt de 8 000 fichiers, puis leurs tests. Bash n'est pas
autorisé. Quelle séquence ?
- A. Glob
**/*formatInvoice*, puis Grep sur les résultats - B. Grep
formatInvoice(, lire les exports pour repérer d'éventuels réexports et les chercher aussi, puis Glob des tests par convention de nommage - C. Read de tous les fichiers
src/ - D. Edit sur chaque fichier pour vérifier s'il contient l'appel
B. Grep pour le contenu, suivi des réexports, Glob pour les chemins. A confond les deux outils, C sature le contexte.
10. Pour aller plus loin (hors examen)#
- Strict tool use :
strict: truecontraint l'échantillonnage pour queinputrespecte toujours le schéma (types, champs requis) ; un sous-ensemble de JSON Schema est accepté. Lien avec les sorties structurées : 04-prompt-structured-output.md. - Tool search : au-delà de 10 outils ou 10 000 tokens de définitions,
defer_loading: trueet l'outiltool_searchne chargent que les 3 à 5 outils utiles. Dans Claude Code, la recherche d'outils MCP est activée par défaut (ENABLE_TOOL_SEARCH). - Réponses économes : renvoyer des identifiants lisibles et stables, paginer, filtrer, et proposer un paramètre
response_format(concise/detailed) ; Writing tools for agents cite une réponse concise à environ un tiers des tokens. Claude Code avertit au-delà de 10 000 tokens de sortie d'un outil MCP et plafonne à 25 000 par défaut (MAX_MCP_OUTPUT_TOKENS). - Approbation obligatoire : un serveur peut marquer un outil
_meta["anthropic/requiresUserInteraction"]: true; Claude Code demande alors une confirmation à chaque appel, quel que soit le mode de permission. - Elicitation : un serveur MCP peut demander une information à l'utilisateur en cours de tâche (formulaire ou URL).
- MCP connector : connecter un serveur MCP distant directement depuis l'API Messages, sans client MCP à écrire.
- Contenu non fiable : un résultat d'outil peut porter une injection de prompt indirecte ; le laisser dans le
tool_result, jamais dans le system prompt.
11. Fiche à retenir#
- Claude choisit un outil d'abord grâce à sa description : ce qu'il fait, entrées et formats, exemples, cas limites, frontière avec l'outil voisin, 3-4 phrases au minimum.
- Ordre des corrections d'un mauvais routage : descriptions → renommer / scinder → seulement ensuite few-shot ou classifieur ; relire le system prompt.
- Renommer
analyze_content→extract_web_results; scinderanalyze_documenten trois outils à contrat défini. -
tool_result:tool_use_id, en premier dans le message user,is_error: trueavec un message qui dit quoi faire. - MCP : protocol error (JSON-RPC, l'hôte gère) ≠ tool execution error (
isError: true, le modèle voit). -
errorCategorytransient / validation / business / permission,isRetryablevrai seulement pour transient. - Résultat vide valide ≠ échec d'accès ; ne jamais masquer une erreur en liste vide.
- Récupération locale dans le subagent, puis remontée de l'irrécupérable avec tentative et résultats partiels.
- 4-5 outils par agent, propres au rôle ; outil contraint (
load_document) plutôt que générique (fetch_url) ; outil transverse limité (verify_fact) pour le fréquent. -
tool_choice:auto(défaut),any(un appel garanti),tool(cet outil, puisauto),none. État actuel : refusés (400) par Opus 5.5, Sonnet 5.5, Fable 5.1 →auto+strict: true. -
.mcp.json= équipe, versionné,${VAR};~/.claude.json= personnel. État actuel : portées local (défaut), project, user. - Tous les outils des serveurs configurés sont découverts à la connexion et disponibles ensemble :
mcp__{serveur}__{outil}. - Resources = catalogues (schémas, doc, issues) ; tools = actions ; prompts = modèles d'invite.
- Intégration standard → serveur communautaire ; serveur maison seulement pour le spécifique.
- Grep = contenu, Glob = chemins, Edit = texte unique, sinon Read + Write (guide) ; explorer par étapes.
Références#
Lues le 21/10/2026.
Guide d'examen et base du cours
- Claude Certified Architect – Foundations Exam Guide v1.0 (juillet 2026), domaine 2
- claudecertificationguide.com, Domain 2 : Tool Design & MCP Integration (leçons 2.1 à 2.5)
API Claude
- Tool use with Claude
- Define tools (descriptions,
input_examples,tool_choice) - Handle tool calls (
tool_result,is_error) - Strict tool use
- Tool search tool
- Writing tools for agents
Claude Code et Agent SDK
- Connect Claude Code to tools via MCP (portées,
.mcp.json, variables, resources, prompts, tool search) - Tools reference (Read, Write, Edit, Bash, Grep, Glob)
- Agent SDK : Connect to external tools with MCP (
mcpServers,allowedTools, nommage)
Model Context Protocol