CCDV-F study guide/Domain 08 of 0810.6% of the exam

Tools and MCPs

Three subdomains, 10.6% of the marks, on how Claude acts: writing tool definitions that get called correctly, understanding what an MCP server actually is, and choosing the smallest mechanism that closes the gap.

Fabs||22 min read|Lire en français →
↵Video walkthrough
A nearly-13-minute, plain-language walk through every section of this guide — narrated.

A tool is a typed contract between the model and your application. You declare an operation and the shape of its arguments; the model decides when to call it and with what values; something on your side executes. Two facts about that contract organise this whole domain: the model never sees your implementation — only the schema you wrote and the results you returned — and the quality of your tool design, not the model’s intelligence, is what the exam is really testing here.

A map before you set off. The exam names three subdomains; this page runs longer than three sections, on purpose. Sections 01–03 cover tool definitions, section 04 the execution loop, section 05 failures and approvals, section 06 MCP, and section 07 the decision ladder between mechanisms. Everything after that — the revision tables, the traps, the quiz — is study aid, not new syllabus. And a legend for the markup: the prose explains, the "Remember for the exam" boxes carry the facts questions are built from, and the traps are the wrong answers dressed as right ones. Anything labelled an SDK footnote is recognise-only — the exam reaches for the concept, not the wiring.

↳Glossary — six terms this page leans on
tool_use / tool_result

The block pair at the centre of the loop. tool_use is the model’s structured request — an id, the tool’s name, an input object. tool_result is your answer, echoing the same id. Every tool_use owes exactly one tool_result.

stop_reason

The response field that says why generation ended. Your loop keys on it: "tool_use" means execute and keep going; anything else means the turn is over.

Server tool

A tool defined and executed on Anthropic’s infrastructure — web search, web fetch, code execution, tool search. Its result comes back already attached; you never build one.

Structured content

An MCP tool result that validates against a declared output schema — machine-checkable data, rather than prose the model has to parse.

Elicitation

The client-side MCP primitive: a server asks the client to collect input or confirmation from the human, then waits for the answer. The server cannot reach the human itself.

Roots

The directories a client offers up to a server — a hint about where its filesystem lives. A well-behaved server stays inside them.

01When a tool is the answer

In plain language: reach for a tool when the model must do something, must learn something fresh, or must answer in a shape your code can consume — and skip it when prose alone is already the right output.

Four situations justify one: actions with side effects (sending, writing, updating); fresh or external data the model cannot know (prices, weather, database contents); outputs that must conform to a guaranteed structure; and calls into existing systems — databases, internal APIs, filesystems. The heuristic the docs offer for the borderline case is worth memorising verbatim in spirit: if you are writing a regex to extract a decision from the model’s prose, that decision should have been a tool call. And the anti-cases: summarisation, translation, general-knowledge Q&A — anything the model can do from its training alone, with no side effects, where a tool round-trip costs more than the work.

02Anatomy of a definition

A user-defined tool in the API’s tools array has a name (letters, digits, hyphens and underscores, up to 128 characters), a plaintext description, and an input_schema in JSON Schema. The optional properties around them: example inputs, cache_control, strict schema enforcement, deferred loading for large tool sets, and allowed_callers limiting which components may invoke the tool. Use the schema to make arguments safe: enums to bound a unit parameter to celsius or fahrenheit, required to distinguish mandatory from optional. The model reads the schema to construct arguments. But it reads the description to decide whether to call the tool at all.

That is the single most examinable fact in this domain: the docs call the description by far the most important factor in tool performance — and the mechanism explains the ranking, because the API assembles a dedicated system prompt out of your tool definitions, the tool configuration, and your own system prompt. A description is not metadata the model consults; it is prompt text, present every turn. A good one runs three or four sentences at minimum and covers what the tool does, when to use it, when not to, what each parameter means, and — the part everyone skips — what it does not return. "Gets the stock price" is the bad example; the rewrite names the exchanges it covers, the currency of the answer, and states plainly that it provides no other information about the company. Example inputs exist but solve a different problem: complex, nested or format-sensitive arguments — and each example must validate against the schema.

↳tool_choice — the four settings
SettingWhat it forces
tool + the tool’s nameThat exact tool, this turn
anySome tool — the model picks which
autoNothing — the model’s choice, tools optional
noneTools off entirely for the turn
Position in the tools array is meaningless — a planted answer that makes order matter is wrong by construction.

And when a tool call fails downstream, return a tool_result with the matching tool_use_id, is_error set to true, and a message the model can act on (what failed, whether and when to retry) — feeding it the raw error body as if it were data is the documented way to confuse it. Every tool_use must be answered by exactly one tool_result; an unanswered one makes the next request malformed.

03Designing the set

  • —Consolidate — one tool with an action parameter beats create_pr, review_pr, merge_pr as three separate definitions; fewer, more capable tools give the model less to choose wrongly between.
  • —Namespace — github_list_prs, slack_send_message — names that carry their service, which matters most once tool search is in play.
  • —Return only high signal — stable semantic identifiers, the fields the model needs for its next step, nothing else. Bloated results burn context and bury the signal.

04The loop and who runs what

One question unlocks this whole section, and most of the domain with it: where does the tool execute? Where it runs decides who drives the loop, who returns the result, and who handles the failure — settle that first and everything else follows. The block identifiers give you the answer at a glance: toolu_ marks a client tool_use, srvtoolu_ a server_tool_use. Treat the prefixes as diagnostic clues to read, not a list to memorise cold.

Client tools put your application in the driving seat: Claude can ask for a call but cannot run your code, so the loop is yours to drive. When the model wants a tool, the response ends with stop_reason "tool_use" and one or more tool_use blocks — each an id, the tool’s name, and an input object shaped to your schema. You dispatch on the name, execute, and answer with a user message whose tool_result blocks echo those ids back. In code, the standard client is a while loop keyed on stop_reason:

↳Client tools — the loop you drive
You

Send the conversation plus the tools array — schemas and descriptions only. The model never sees your implementation.

Model

Wants a tool: the response ends with stop_reason "tool_use" and one or more tool_use blocks, each carrying an id (toolu_…), the tool’s name, and the input.

You

Dispatch on the name and execute the call in your application.

You

Answer with a user message whose tool_result blocks echo those ids back — exactly one result per tool_use.

Loop

Send again, and keep looping while stop_reason reads "tool_use".

Exit

end_turn, max_tokens, stop_sequence, refusal — anything other than "tool_use" ends the loop.

An unanswered tool_use makes the next request malformed — the pairing rule is mechanical, not stylistic.

Server tools invert the arrangement. Web search, web fetch, code execution and tool search run their own loop inside Anthropic’s infrastructure — one request can fire several searches before a response comes back — and that response pairs every server_tool_use block (srvtoolu_-prefixed ids) with its result already attached. You never construct a tool_result for these; the exam’s favourite trick in this territory is making you think you owe one. The behaviour to know cold is pause_turn: the server loop hit its iteration limit and the work is not finished.

↳Server tools — the loop Anthropic drives
You

Send one request with server tools enabled — web search, web fetch, code execution, tool search.

Anthropic

Runs the server loop inside its own infrastructure; several tool iterations can fire before any response comes back.

API

Returns every server_tool_use block (srvtoolu_-prefixed) with its result already attached.

You

Build nothing — no tool_result, ever, for a server tool.

If paused

stop_reason "pause_turn": the loop hit its iteration limit, unfinished. Re-send the conversation exactly as it arrived — dropping a tool from the array is a validation error — and cap your retries, because a resumed turn can pause again.

Server tools never cross into your process. The only thing you can ever owe is the resend.

The subtle case is the mixed turn: Claude emits a server tool and a client tool in the same parallel group, and the API returns at once, without running the server tool, so that you can run yours first. It rewards a careful read — stop_reason "tool_use", not "pause_turn"; a server_tool_use block with no result attached as the tell; exactly one tool_result owed, and it is yours.

↳The mixed turn, step by step
Model

Emits a server tool and a client tool in the same parallel group.

API

Returns immediately, without running the server tool — you get to run yours first. stop_reason reads "tool_use", not "pause_turn".

The tell

A server_tool_use block with no result attached. With no client tool in the group that means pause_turn; here it means "waiting for you".

You

Run your client tool and send only its tool_result — one result, for the one tool you own.

You

Keep the tools array byte-identical — removing web_fetch earns a 400.

API

The deferred server tool runs next; its result is first in the following response.

↳The same exchange, as it looks on the wire
response stop_reason: "tool_use" ← not "pause_turn"
assistant [ server_tool_use web_fetch srvtoolu_01… (no result yet)
tool_use get_weather toolu_01A… ]
 
you send user [ tool_result toolu_01A… ] ← only yours
 
next response
assistant [ server_tool_use web_fetch + its result ← arrives first
text … ]
One round trip, both tools served: yours now, the server’s on the response that follows.

05When tools fail, and who approves

The error taxonomy falls out cleanly once execution location is clear — the same one question again: where does the tool run? That tells you whose problem each failure is.

↳Who handles which failure
The failureWhat actually happensYour move
Your tool fails mid-execution — the weather service is downThe failure becomes data: a tool_result with is_error trueWrite the message the model can act on — what failed, whether and when to retry
Claude’s call is invalid — a required parameter missingIn development, a description problem; at runtime, an invalid-input errorSpell the parameter out in the description; at runtime return an is_error tool_result naming the mistake — Claude typically retries two or three times, corrected, before apologising to the user
A server tool fails — web search: too many requests, uses exhausted, query too longClaude absorbs the error and answers around itNothing — no is_error from you; it is not your tool
A thrown tool ends nothing. An execution failure is data the model relays — not a crash in your loop.

Approvals are the Agent SDK’s answer to "should this run at all" — and the concept matters more than the wiring. Register a can_use_tool callback (canUseTool in TypeScript) and it fires whenever a call was not already approved by a permission rule or mode. It is the one place you inspect the full input before anything executes: the actual command behind Bash, the actual path and contents behind Write. Return allow, optionally with an updated_input that substitutes for what was asked, or deny — execution is skipped, but Claude sees your message and can change course.

Two SDK footnotes, recognise-only: a tools array passed alongside the callback must include AskUserQuestion, and the Python SDK needs a no-op PreToolUse hook registered to hold the stream open. What is not a footnote: for hard denials, disallowed_tools is evaluated before any permission mode is consulted — so "Bash(rm -rf *)" stays blocked even under bypassPermissions, while a bare "Bash" would strip the entire tool from the model’s view, broader than you meant.

06MCP without the mystery

In plain language: MCP is a standard plug. A host application owns the conversation and the policy; inside it sits one client per server; and servers are the things people write, exposing capabilities through a uniform protocol. Anything that speaks it — an editor, Claude Desktop, Claude Code, your own app — can use the same server.

↳The three roles, and what each owns
RoleWhat it isWhat it owns
HostThe application the human runs — Claude Code, Claude Desktop, your appThe conversation, the security policy, every consent and authorisation decision, the full history
ClientA connector inside the hostExactly one server — one client per server connection
ServerThe thing you writeThe capabilities it exposes to the host
Local servers (stdio) typically serve one client; remote servers (streamable HTTP) typically serve many.

The design principle the exam tests is isolation: a server cannot see other servers, cannot see the conversation, cannot reach into the host. If it needs something from the client side, it must request it and wait — elicitation to ask the human for input, roots to learn which directories it may touch, sampling to borrow the host’s model for a completion. One currency note: sampling was deprecated in the spec’s 2026-07-28 revision — recognise the name; new implementations integrate with LLM provider APIs directly.

Two transports, and the rule of thumb for telling them apart: a command means local, a URL means remote. Remote hygiene: bind local servers to loopback only, validate the Origin header on connections, authenticate properly. In Claude Code, registration is one line each way — a command for stdio, a URL for HTTP.

↳The two transports
TransportHow you spot itHow it talksThe hygiene rule
stdio — localA command; the server runs as a child processJSON-RPC, one message per line — and stdout belongs to the protocol absolutelyBind to loopback only; logs go to stderr, and a well-behaved client will not treat stderr as failure
Streamable HTTP — remoteA URLOne endpoint; each request a POST whose Accept header lists both JSON and event-stream, and the server answers in either formValidate the Origin header on connections; authenticate properly
A stray debug print on stdout corrupts a stdio server’s stream — the classic local-server bug the exam names.

Before any capability is used, both sides declare and negotiate it for the session — a client may only call tools if the server declared the tools capability, and lists refresh by notification when they change.

Then the three primitives — one line each before the detail. A tool performs an action. A resource exposes readable data. A prompt packages a reusable interaction. They are separate primitives, not three views of one thing, and one server may expose any mix: the spec’s own example is a database server offering query tools, a schema resource, and a few-shot prompt at the same time.

  • —Tools — the model-acting primitive: name, description, and a required input schema (a no-argument tool still declares an empty, closed object — {} with nothing permitted inside); optionally an output schema, which buys you machine-validatable structured content in results. Results carry a content array and an error flag; a tool may also signal that it needs human input before proceeding.
  • —Resources — readable data addressed by URI, listed and read, optionally templated for parameterised families. The security rule is non-negotiable: a server must validate every URI and sanitise filesystem paths, because a crafted file:// URI walking out of its directory is the classic attack; unknown URIs answer with a protocol error.
  • —Prompts — named, reusable message templates with arguments, filled on request. How an organisation packages its workflows for humans to invoke.

07Built-in, custom tool, MCP, or skill

In plain language: use what ships, write only the logic that is yours, plug into what already exists, and add knowledge — not tools — when the gap is knowledge. The ordering principle is that the cheapest mechanism is the one you do not have to build.

↳The decision ladder at a glance
MechanismWhat it isReach for it whenThe tell it’s wrong
Built-insShip with Claude Code and the Agent SDK — file reading and editing, shell, search, web fetch; some permission-free, some requiring approvalThe job stays inside what ships — a refactor inside the repository needs nothing elseYou are about to hand-write a file reader
Custom toolYours: your schema, your codeThe logic is yours — internal APIs, domain calculations, data no built-in can reachThe capability already exists as a service
MCP serverSomeone else’s server, local or remoteThe capability exists — the tracker, the docs system, the database; connecting beats rewritingYou are hand-rolling an integration other teams already share
SkillNot a tool at all — knowledge and workflow, a deployment checklist as a slash commandThe gap is instructions, not actionsThe fix would add a new action to the model’s hands
The ladder runs cheapest-first. Skipping rungs is allowed; inventing rungs is the mistake.

One wiring fact explains a naming quirk and a framing at the same time: in the Agent SDK, custom tools are registered by wrapping them in an in-process MCP server. That is worth knowing twice over — it explains the mcp__-prefixed tool names, and it means "custom tool versus MCP" is really a question about where the logic runs: your process, or someone else’s server.

One distinction from the API side that keeps resurfacing in exam questions: Anthropic-defined schemas like bash and text_editor look like server tools but execute on your side — Anthropic writes the schema (you request it by its date-versioned type rather than defining your own), trains the model on it, and your application runs the call and returns the result. Only the true server tools — web search, web fetch, code execution, tool search — run on Anthropic’s infrastructure.

08One page to revise from

Seven sections of prose sit above this line. Here is the same domain as one table — who runs what, the question every scenario in this domain turns on — plus the night-before checklist. If you reread one thing the night before, reread this.

↳Who runs what — the table this domain turns on
Tool kindWho executesThe idsYour tool_result?On failure
User-defined (client) toolsYour applicationtoolu_Yes — exactly one per tool_useYou write it: is_error true, actionable message
Anthropic-defined schemas — bash, text_editorYour application — the row people get wrongtoolu_Yes — same as client toolsSame as client tools
Server tools — web search, web fetch, code execution, tool searchAnthropic’s infrastructuresrvtoolu_Never — the response pairs itClaude absorbs it; nothing from you
stop_reason "tool_use" → run your client tools and answer. "pause_turn" → server loop unfinished, resend byte-identical. Anything else → done.

The night-before checklist. You should be able to say each of these without looking:

  • —The five rules from the top of this page, out loud, in order.
  • —Which stop_reason means what — and that pause_turn means unfinished, not failed.
  • —The mixed turn in one sentence: server tool with no result plus a client tool in the group → run yours only, resend an identical tools array.
  • —The three MCP roles, the one principle (isolation), and the transport rule: command → stdio with stdout reserved for protocol, URL → streamable HTTP.
  • —Tool, resource and prompt in one line each — and that one server can expose all three.
  • —The ladder cheapest-first — built-ins, custom, MCP, skill — and that a skill is not a tool.

A last sorting pass, because not everything above deserves equal rehearsal. Memorise cold: the five rules, the stop_reason values and what your code does for each, the three MCP roles, tool / resource / prompt in one line each. Recognise on sight: the toolu_ and srvtoolu_ prefixes (diagnostic clues, not a list to recite), the SDK footnotes around can_use_tool, the named web-search failure reasons. Reference only: everything else. This domain rewards judgement — which mechanism, whose failure, which primitive — far more than recall.

09The traps in this domain

  • —"Claude picks the wrong tool — add input examples" — selection is a description problem; examples fix complex inputs.
  • —"More, narrower tools make selection clearer" — the docs say consolidate: one tool, an action parameter.
  • —"The MCP server can see the whole conversation" — isolation is the design; the host sees everything, the server sees requests.
  • —"stdio servers can print to stdout" — stdout is the protocol channel; logs go to stderr.
  • —"bash and text_editor run on Anthropic’s servers" — Anthropic-defined schemas still execute in your application.
  • —"A skill is a kind of tool" — a skill adds knowledge and workflow, not an action.
  • —"After a server tool you owe a tool_result" — never; Anthropic pairs server_tool_use with its result, and constructing one yourself is the error.
  • —"server_tool_use with no result means pause_turn" — only when no client tool shares the group; otherwise it is a mixed turn and you owe exactly your client tool’s result.
  • —"A thrown tool ends the loop" — an execution failure is data, not a crash: is_error true, an actionable message, and Claude relays it.
  • —"bypassPermissions overrides every restriction" — deny rules run before any mode is consulted; disallowed_tools holds even there.

10Check yourself

Four questions, in roughly the exam’s register. Each one expands to show the answer and — more usefully — why the wrong options are wrong.

Q1

In testing, Claude builds correct arguments for your inventory tool but often picks a cheaper lookup tool when it should pick the inventory one. Where do you fix it?

  1. AAdd more input examples showing complex argument shapes
  2. BSet tool_choice to "any" so a tool is always used
  3. CRewrite the inventory tool’s description to say when to use it — and when not to
  4. DRename the tools so the inventory tool sorts first
→Check your answer
Answer: C

Selection is a description problem — the description is the prompt text the model reads to decide whether to call the tool at all. Examples fix a different problem: complex or format-sensitive arguments. "any" forces some tool but not which one, and array position is meaningless, so renaming cannot help.

Q2

A response arrives with stop_reason "tool_use", containing a server_tool_use for web_fetch with no result attached, and a tool_use for your get_weather. What does your code do?

  1. ABuild tool_results for both blocks before resending
  2. BDrop web_fetch from the tools array so the model cannot ask for it again
  3. CTreat it as pause_turn and resend the conversation with no results added
  4. DRun get_weather, return only its tool_result, and resend a byte-identical tools array
→Check your answer
Answer: D

This is the mixed turn: the server tool waits so you can run yours first. The unmatched server_tool_use is the tell, and stop_reason reads "tool_use", not "pause_turn". You owe exactly your client tool’s result — building one for web_fetch is the planted error — and the tools array must stay identical: dropping web_fetch earns a 400.

Q3

Your team’s docs MCP server should let the agent query the docs index, expose the style guide as readable content, and offer a reusable "incident writeup" template that takes arguments. Which primitives does it declare — and how many servers?

  1. ATools, resources and prompts — one server can expose all three
  2. BThree servers, one per primitive
  3. CTools and prompts only — resources must be local files
  4. DResources and prompts only — querying an index is a read, so it is a resource
→Check your answer
Answer: A

A tool performs the action (querying), a resource exposes the readable data (the style guide), a prompt packages the reusable interaction (the template) — and capabilities are declared per server, so one server can expose the lot; the spec’s own database-server example does exactly that. Querying is model-directed action, not passive data, which rules out the last option.

Q4

A reviewer wants Claude to walk the team’s deployment checklist before every release — the same steps each time, no new capabilities needed. Which mechanism fits?

  1. AA custom tool that runs the steps
  2. BAn MCP server wrapping the runbook
  3. CWeb fetch, pulling the checklist from the wiki each time
  4. DA skill — the checklist as a slash command
→Check your answer
Answer: D

The gap is knowledge and workflow, not action — and a skill is exactly knowledge and workflow, not a new tool. The other three all add machinery the ladder says you should not build: the cheapest mechanism is the one you do not have to build.

Fabs
Founder, The Third Way Company
Work with us