CCAR-F study guide/Domain 02 of 0518% of the exam

Tool design and MCP integration

Five subdomains, 18% of the marks, and a claim worth memorising because it organises all of them: an agent’s ceiling is its toolset. The model supplies judgement; the tools supply capability, visibility and blast radius. This page covers the contract every tool is (interface, errors, distribution), the protocol that standardises them (MCP), and the six built-ins the exam expects you to know by name.

Fabs||12 min read|Lire en français →

A tool definition is a contract with a non-deterministic client. The model cannot read your source code, cannot infer your intentions and cannot see your documentation — everything it knows about a tool is the name, the description and the input schema, delivered in the API request. That trio is the entire interface, and exam questions in this domain are almost always “which part of the contract is wrong?” wearing a scenario.

01The interface: name, description, schema

The name is an address: verb-first, specific, honest about what will happen — query_orders, not data_lookup; create_invoice, not process. The description is the contract’s substance, and the exam has a fixed idea of what a good one contains: what the tool does, when to use it, when not to, and what its results mean. A reviewer tool that “checks whether a Python file follows the team style guide” beats “reviews code”, the same way a good function docstring beats a vague one — the model chooses between tools the way a developer chooses between functions, by reading the docs.

The input schema is JSON Schema, and its quality is the difference between a tool that works and one that hallucinates arguments. Few parameters, each with a clear name, a declared type, a description, and constraints the schema itself enforces — enums instead of free strings where the domain is closed, required exactly where requirement is real. The model will fill whatever shape you give it; a schema with optional everything invites the model to guess values it should have been forced to surface. And the schema cuts both ways: strict input validation rejects malformed calls before anything executes, which converts “mysterious wrong behaviour” into “an error I can read in Domain 2’s next section”.

02Boundaries: scope, blast radius, idempotency

Beyond syntax, the exam tests three boundary properties of a well-scoped tool. Blast radius: prefer read-only to write, write to delete, narrow to broad — a tool that reads one order is safer than one that reads all orders, and a tool that drafts an email is safer than one that sends it; the granularity you choose is a safety decision, not a convenience one. Reversibility and idempotency: operations that can run twice harmlessly (idempotent) are the natural fit for agents that retry; destructive, irreversible operations deserve their own tool, gated by their own permission, never bundled into a convenient multi-purpose grab-bag. Single purpose: one tool, one job. Tools that do “anything with the records API” produce descriptions the model cannot choose between and failures nobody can attribute.

This is also where the interface meets Domain 1’s enforcement layers: a narrow tool is restriction by construction. You do not tell the agent “don’t delete anything” and hand it delete_everything() with a polite description; you give it the tools whose union of capabilities is exactly the task, and the prompt’s job becomes easy because the design already did it.

03Structured error responses

A tool call can fail; the architect’s job is making failure useful. The rule the exam repeats in different costumes: errors are for the model to read, and the model is a reader of plain language with no access to your stack. A structured error says what failed, why, and — where possible — what would work instead. “Invalid date: expected YYYY-MM-DD, got ‘March 3rd’” lets the agent correct itself on the next turn. A bare stack trace, an HTTP 500 or an unhandled exception string lets it thrash, retry the same call, or start guessing — the loop from Domain 1, spinning on malformed input until a budget saves it.

↳An error the model can use, versus one it cannot
BAD {"error": "SQLException at line 42: constraint FAILED"}
→ the model retries the identical call, thrashes, burns turns
 
GOOD {"isError": true,
"content": "Rejected: invoice_date must be YYYY-MM-DD
and no earlier than 2020-01-01. Received
’March 3rd’. Call again with the date as
2026-03-03."}
→ the model corrects on the next turn
In MCP, a tool signals failure with isError: true and the human-readable explanation in content. The format is the contract; the readability is the feature.

For MCP tools specifically, the shape is fixed: a failed tool call is a successful protocol response whose payload carries isError: true, with the explanation as content the model reads. Two distinctions the exam draws sharply. A tool error (“your arguments were invalid”, “the record does not exist”) is data — it goes back into the loop as context, and the agent may recover by itself. A protocol or transport error (the server never answered) is infrastructure — it is your orchestration layer’s business: retry with backoff, timeout, surface to a human. Merging the two categories produces the classic wrong design: agents retrying network outages as if arguing with a validation error.

04Distributing tools across agents — and tool choice

When a coordinator runs subagents, tool distribution is an architecture decision with a fixed set of right answers. Principle one: give each agent the toolset its job implies, and nothing more — the researcher gets search and read; the implementer gets read-write and shell; the reviewer gets read-only. Every tool withheld is a failure mode deleted. Principle two: watch the count. Tool sets that grow without bound degrade selection quality — the model mis-picks among near-duplicates and misses the right tool in a crowd; the mitigations are specialisation (split toolsets across subagents so no single context carries them all), consolidation (retire the near-duplicates), and, at API scale, letting the model search or programmatically retrieve tool definitions rather than shipping every schema in every request. The exam’s phrasing is usually “the agent picks the wrong tool among many similar ones” — the answer is never “write a longer system prompt”; it is “the toolset is the problem”.

The other half of the subdomain is the API’s tool_choice setting — four values, and the exam expects all four verbatim. auto (the default): the model decides whether and which tool to call. any: some tool must be called — the model chooses which, but it cannot answer in prose; use it when a structured result is mandatory. tool, with a name: forces that one specific tool. none: tools are visible but the model must not call any. The scenario language maps directly: “the model keeps answering in prose when we need a rating from the schema” → tool_choice any; “always extract with our schema, never a different tool” → tool with the name; “let it decide” → auto.

05MCP: servers, transports and scopes

Model Context Protocol is the open standard that moves tool design from “hand-coded into my application” to “plug a server into any MCP host”. One MCP server exposes tools (functions the model can call), resources (data it can read) and prompts (templates it can be given) — one server can serve all three. A host — Claude Code, the Agent SDK, Claude Desktop, your own application — connects to servers and merges their offerings into the agent’s toolset. The exam’s design principle is isolation: a server cannot see other servers, cannot see the conversation, cannot reach into the host. If a scenario needs cross-server coordination, the coordinator does it — the servers never do.

Transports are how a server is reached, and there are two that matter: stdio for local servers (the host spawns a subprocess and speaks the protocol over the process’s standard input and output — stdout is the protocol channel, logs go to stderr) and streamable HTTP for remote servers (one endpoint serves many clients, usually with OAuth for authentication). The exam’s phrasing keys: “runs on the user’s machine, no network” → stdio; “shared team server, authenticated” → streamable HTTP. In Claude Code, servers are registered with claude mcp add and live at one of three scopes: local (the default — this project, this user, not shared), project (committed as .mcp.json at the repository root, so everyone who clones gets the same servers) and user (available across all your projects). The scenario verb gives the scope away: “the whole team, reproducibly” → project scope with .mcp.json checked in.

↳MCP scopes in Claude Code
ScopeLives inWho gets it
localPer-project, per-user configOnly you, only in this project (the default)
project.mcp.json at the repo root, committedEveryone who clones the repository
userYour user-level configYou, in every project
Security follows scope: project-scoped .mcp.json is shared configuration — every teammate trusts every server in it, so it is also an attack surface to review like code.

MCP security has one more exam-favourite: the server trusts its inputs. A server must validate every resource URI and sanitise filesystem paths — the crafted file:// URI that walks out of its directory is the classic illustration of what happens when it does not. The host limits what a server sees (isolation); the server still owns what it does with what it is handed. Both halves are your design responsibility; neither excuses the other.

06The built-in tools, by name

The exam names six built-in tools and expects fluency in their trade-offs — this is the most “trivia-shaped” part of the architect exam, and the marks are real. Read reads files (with offset and limit for paging through large ones — the context-polite way to look at a big file). Glob finds files by name pattern; Grep finds content by pattern inside them — the pair are the search tier, and targeted search beats bulk reading wherever it can answer the question. Edit makes surgical replacements: give it an exact string to match and the replacement; the match must be exact, whitespace included, and a mismatch fails rather than approximates — which is precisely its value as a safe mutator. Write creates or overwrites a whole file — the broad-spectrum mutator; note the overwrite semantics, because “Write for the surgical fix” is a wrong answer the exam likes. Bash runs shell commands with all their power and all their blast radius, and its session state persists across calls — a cd in one call still applies in the next — which is either a convenience or a trap depending on who wrote the command.

↳Which built-in, when
You need toReach forThe trap
Find files by nameGlobReading the whole tree instead
Find where something is saidGrepReading every candidate file in full
Look at part of a big fileRead with offset/limitReading the whole file into context
Change three lines in one fileEditWrite — it replaces the entire file
Create a file from scratchWriteEdit — there is nothing to match yet
Run a build, a test, gitBashForgetting state persists across calls
Cheapest-first is the rule: search before reading, read narrowly before reading widely, edit before writing, and reach for Bash last because it can do anything — including everything you did not ask for.

07The traps

  • —“The tool failed, so throw the exception and let the caller see the stack.” The model reads plain language, not stack traces. isError with an actionable message is the contract; raw exceptions are how thrashing loops are born.
  • —“One powerful tool keeps the schema simple.” One grab-bag tool makes every wrong action possible and no description honest. Small, single-purpose tools with narrow blast radius are the senior answer.
  • —“Ship all forty tools to every agent for flexibility.” Overloaded toolsets degrade selection. Distribute by job, consolidate near-duplicates, and keep any single context’s toolset small.
  • —“The model ignored the tool, so force tool_choice any.” any forces a call — any call. If the problem was the wrong tool being picked among many, forcing makes it worse. Fix the toolset or the descriptions first.
  • —“MCP servers coordinate with each other.” They cannot see each other. Coordination belongs to the host or your coordinator; a design that assumes server-to-server chat is a design that fails on paper.
  • —“Use Write — it is more thorough than Edit.” Write overwrites the whole file; one mismatched Edit fails loudly instead of silently rewriting everything. Thoroughness you did not ask for is damage.
↳Check yourself
Q1

A data-extraction agent must always return its findings as your invoice schema — never in prose, and never via a different tool. Which setting?

  1. Atool_choice: "auto", with a stern system prompt
  2. Btool_choice: "any"
  3. Ctool_choice: { "type": "tool", "name": "extract_invoice" }
  4. Dtool_choice: "none"
→Check your answer
Answer: C

The named-tool setting forces exactly that tool, which is what “always this schema, never another tool” asks for. any would guarantee a tool call but leave the choice open; none forbids calls entirely.

Q2

Your team’s style-check MCP server should be available to everyone who clones the repository, identically. What is the right registration?

  1. Aclaude mcp add at local scope on each machine
  2. BBake it into each agent’s system prompt
  3. CUser scope on the CI machine only
  4. DA .mcp.json at the repository root, committed — project scope
→Check your answer
Answer: D

Project scope is exactly “shared per repository”: the file ships with the clone. Local is private per user; user scope follows one person across projects.

Q3

A subagent keeps calling get_records with malformed dates and thrashing. The dates arrive in a dozen human formats. Best fix?

  1. ARaise the subagent’s turn limit
  2. BMake date a free-text parameter and validate in the system prompt
  3. CConstrain the schema (an explicit date format or enum where closed) and return structured, actionable errors with the expected format
  4. DWrap get_records in Bash so the shell can pre-parse
→Check your answer
Answer: C

Schema constraints prevent the malformed call; structured errors make any that slip through self-correcting. Turn limits are backstops, prompts are guidance, and Bash-wrapping a tool adds blast radius to solve a contract problem.

Q4

A reviewer agent must inspect files but must never modify them. Which toolset is the architect’s?

  1. ARead, Grep, Glob only
  2. BRead, Write, Edit, Bash — plus “do not modify anything” in the prompt
  3. CBash only, run as a read-only OS user
  4. DAll built-ins; rely on the PostToolUse hook to revert changes
→Check your answer
Answer: A

Restriction by construction: the read/search tier cannot express a write. Prompt prohibitions guide but do not enforce; reverting after the fact means the write happened.

Q5

An MCP tool call fails because the database was unreachable. The agent retried the identical call five times. What went wrong architecturally?

  1. AThe tool should have returned the driver exception string raw
  2. BA transport/infrastructure error was surfaced as a tool error — retries belong to the orchestration layer with backoff, not to the model
  3. CThe agent needed a higher turn budget
  4. Dtool_choice should have been "none"
→Check your answer
Answer: B

A dead database is not feedback the model can act on. Infrastructure errors are your layer’s to retry or escalate; presenting them as tool errors invites exactly this thrash.

Fabs
Founder, The Third Way Company
Work with us