CCDV-F · module 5 of 8 · 10.6% of the exam
Tools and MCPs
Weight: 10.6 percent of the exam. Tests whether you can define tools the model uses correctly, run the tool-use loop properly, and reason about MCP architecture and the MCP connector on the API.
What the exam expects
Two halves, roughly equal in weight.
The first is tool use on the Claude API: writing tool definitions the model actually selects correctly, controlling whether and which tool gets called, running the request-execute-respond loop without corrupting the conversation, and knowing which capabilities are Anthropic-hosted versus yours to execute.
The second is MCP, the Model Context Protocol: its client-server architecture, the primitives a server exposes and who controls each one, the two transports, and how you reach a remote MCP server from a Messages API request.
Expect scenarios where an agent misbehaves and you have to trace the cause back to a definition, a loop bug, or a misuse of a primitive. The distractors reliably include one over-engineered alternative and one plausible-sounding statement that inverts a fact (resources are model-controlled, stdio serves many clients, strict lives on tool_choice).
Tool definition quality
The model chooses tools almost entirely from what you wrote in the definition. Four things carry the weight:
- Name. Specific and verb-led.
search_product_catalogbeatslookup. A vague name forces the model to infer purpose from the description alone. - Description. State what the tool does and when to call it. Prescriptive trigger conditions ("call this whenever the user asks about current prices or recent events") measurably improve should-call rate on current models, which reach for tools more conservatively than older ones. Adjectives like "fast" and "accurate" carry no decision-relevant information.
- Parameters. Describe every property. Use
enumfor fixed value sets. Mark only genuinely required parameters as required. - Count. Keep the set focused. A large, vaguely described tool surface makes selection harder, not easier.
There is a real tension to hold: current models follow instructions literally, so "CRITICAL: You MUST ALWAYS call this tool" produces over-triggering on unrelated requests. Prescriptive is not the same as forceful. Describe the condition, not the imperative.
For hard guarantees on the shape of tool input, set strict: true as a top-level field on the tool definition, alongside name, description, and input_schema. It requires additionalProperties: false and a required list. It does not go on tool_choice, and it is a different feature from output_config.format, which constrains the model's response, not its tool parameters.
Controlling tool selection
tool_choice has four forms:
| Value | Behaviour |
|---|---|
{"type": "auto"} | The model decides whether to use a tool. Default. |
{"type": "any"} | The model must call at least one tool, but chooses which. |
{"type": "tool", "name": "..."} | The model must call that specific tool. |
{"type": "none"} | The model may not call tools at all. |
Any of these can carry disable_parallel_tool_use: true to cap the model at one tool call per response. By default, parallel tool use is on and a single assistant message may contain several tool_use blocks.
The trap: none forbids tools, not text. Candidates reading quickly sometimes pick it when they want to forbid a prose answer.
Running the loop correctly
This is where most production bugs live, and the exam knows it.
- Every
tool_useblock needs a matchingtool_resultcarrying the sametool_use_id. - When one assistant turn emits several
tool_useblocks, return all the results in a single user message. Splitting them across turns trains the model to stop making parallel calls, which is a slow, silent regression. - When a tool fails, return a
tool_resultwithis_error: trueand an informative message. Do not drop the block, and do not fabricate a successful-looking empty result. A dropped block breaks pairing; a fake success gets reasoned over as fact. - Append the full
response.contentto the conversation, not just extracted text, sotool_useblocks survive. - Parse tool inputs with a real JSON parser. Current models may escape Unicode or forward slashes differently, so raw string matching on serialized input is fragile.
Prefer the SDK tool runner over hand-writing the loop. A persistent misconception is that you must write the loop yourself to get control. You do not: the runner yields the assistant message before tools execute, so approval gating, logging, result modification, and per-turn retries are all available, and gating can also live inside the tool function itself. Reach for a manual loop only when you need a control flow the runner's hooks do not fit.
Note also that the Tool Runner and the Claude Agent SDK are different products. The Tool Runner is a helper in the API SDK that loops over tools you define. The Claude Agent SDK is Claude Code packaged as a library, with its own built-in tools.
Server tools, deferred loading, and composition
Server-side tools (web search, web fetch, code execution, tool search) run on Anthropic's infrastructure. You declare them in tools and the results arrive as content blocks in the same response, with no execution loop on your side. Custom tools are yours to execute.
Two consequences worth knowing:
- Server tool errors do not raise. You get a normal response containing a result block whose content is an error object. Code that only checks HTTP status reads an error as data.
- A long server-tool turn can stop with
stop_reason: "pause_turn", meaning the server-side loop hit its iteration limit. Resend the conversation with the paused assistant turn appended and the server resumes. Do not add a "Continue" message and do not treat it as a rate limit.
Two scaling features come up regularly:
Tool search solves a large tool surface. Declare the search tool and mark the rest with defer_loading: true, so only relevant schemas load into context. Two constraints: the search tool itself must not be deferred, and at least one tool must be non-deferred. Because discovered schemas are appended rather than swapped in, the cached prefix survives, which is why this beats the intuitive alternative of rebuilding a filtered tools array per request (that changes the front of the prefix and destroys the cache).
Programmatic tool calling solves long sequential chains with large intermediate payloads. Claude writes a script in the code execution container; when the script calls a tool, the result returns to the running code rather than into Claude's context. Only the script's final output comes back. Token cost then scales with the answer, not the intermediate data.
MCP architecture
MCP standardizes how an AI application obtains context and capabilities from external programs. Three participants:
- Host: the AI application (an IDE, a desktop app, Claude Code) that coordinates everything.
- Client: created by the host, one per server, each maintaining a dedicated connection.
- Server: a program that provides context and capabilities. It may run locally or remotely.
Messages are JSON-RPC 2.0. Two transports:
| Transport | Shape | Typical use |
|---|---|---|
| stdio | Standard input and output between local processes | A local server, typically serving one client, no network overhead |
| Streamable HTTP | HTTP POST with optional server-sent events | A remote server serving many clients, with standard HTTP auth such as OAuth |
Servers expose three primitives, and who controls each one is the single most tested fact in this section:
| Primitive | Controlled by | What it is | Methods |
|---|---|---|---|
| Tools | The model | Executable functions the model decides to invoke | tools/list, tools/call |
| Resources | The application | Read-only data the host retrieves and supplies as context | resources/list, resources/read, resources/templates/list |
| Prompts | The user | Reusable templates invoked explicitly, often as slash commands | prompts/list, prompts/get |
Each resource has a unique URI and a MIME type. When the set of resources is dynamic, use a resource template: a parameterized URI such as docs://product/{version}, discoverable through the templates listing, rather than enumerating a fixed resource per value.
Clients can also expose primitives back to servers. Elicitation lets a server request additional input or confirmation from the user mid-operation. Sampling, which let a server request a model completion from the client, is deprecated in current protocol versions.
The MCP connector on the API
To let Claude call a remote MCP server's tools directly from a Messages API request, you need both halves:
mcp_servers, listing each server with its type, name, and URL (plus auth on the server entry, not on individual tools).- A matching
mcp_toolsetentry intoolswhosemcp_server_nameequals the declared server name.
Every declared server must be referenced by exactly one toolset. Omitting the toolset is rejected as a validation error, and it is the single most common first-attempt failure.
How to think through the question
- Classify the failure. Is this a definition problem (the model picks the wrong tool, or calls it with bad arguments), a loop problem (something about message shape, pairing, or stop reasons), or a concept problem (which MCP primitive, which transport)?
- For definition problems, go to the four levers in order: name, description with trigger condition, parameter descriptions, tool count. Reaching for
tool_choiceto fix a description problem is almost always wrong, because forcing a call on every request trades one failure mode for a worse one. - For loop problems, check pairing and grouping first. Missing
tool_result, split results, dropped error blocks, and text-only appends account for most of them. - For MCP problems, name the control. Model decides, application retrieves, user invokes. Map the scenario's actor to the primitive before reading the options.
- Eliminate inverted facts. Distractors in this domain frequently state a true-sounding sentence with two terms swapped.
Worked example. An agent must read a customer profile, then that customer's last fifty orders, then check inventory for each item, then report which are back in stock. Each step is a round trip and the intermediate payloads are large and never referenced again. What reduces both latency and token cost?
Step 1: this is not a definition or a concept problem. The tools work; the shape of the composition is the issue. Step 3 does not apply either, since nothing is malformed. Step 5: check the options for inverted facts, and note that enabling parallel tool use is one, because the steps are genuinely sequential (each needs the previous step's output), so parallelism cannot help. Raising effort improves planning without changing round-trip or payload economics. That leaves two real designs: fold everything into one custom tool, or use programmatic tool calling. The scenario emphasizes that intermediate payloads are large and discarded, which is precisely the condition programmatic tool calling addresses, because results return to the script instead of the context window. The single mega-tool is a defensible design but hard-codes one workflow and gives up the flexibility that made these separate tools. Choose programmatic tool calling.
Exam traps
- Swapping MCP primitives. "Resources are model-controlled" and "tools are read-only data" are the two inversions to watch for. Resources cannot perform writes.
- Swapping transports. stdio is local and typically one client; Streamable HTTP is remote and many clients. An option claiming stdio is what supports many clients is inverted.
- Putting
strictontool_choice. It is a top-level field on the tool definition. - Splitting parallel tool results across messages. It works, which is why the resulting drift is so hard to notice.
- Fabricating success for a failed tool. Returning an empty object rather than
is_error: trueconverts a visible failure into silent bad data. - Reaching for
tool_choice: anyto fix a weak description. It forces a tool call on requests that need none. - Defining a custom tool named
bash. The Anthropic bash and text editor tools are schema-less and declared by versioned type plus their fixed name. Supplying your own schema silently creates an ordinary custom tool with none of the built-in behaviour. - Rebuilding the tools array per request to save context. Use tool search instead; a per-request rebuild invalidates the whole prompt cache.
- Treating
pause_turnas an error. It is a resumable state, and resending with the paused turn appended continues the work. - Declaring
mcp_serverswithout the matchingmcp_toolset. Both halves are required.
Quick reference
- Tool definitions: specific name, description stating when to call, per-property descriptions,
enumfor fixed sets. strict: trueis top-level on the tool, withadditionalProperties: falseandrequired.tool_choice:auto,any,tool(named),none.noneforbids tools, not text.- All
tool_resultblocks for one assistant turn go in one user message. Failures useis_error: true. - Prefer the SDK tool runner; it supports approval gating, interception, and retries.
- Server tool errors return a result block, not an exception.
pause_turnmeans resend with the paused turn appended. - Tool search plus
defer_loadingscales a large tool surface and preserves the cache; the search tool itself must not be deferred. - MCP: host creates one client per server; JSON-RPC 2.0; stdio (local) and Streamable HTTP (remote).
- MCP primitives: tools are model-controlled, resources are application-controlled, prompts are user-controlled. Elicitation is a client primitive; sampling is deprecated.
- MCP connector needs
mcp_serversand a matchingmcp_toolsetintools.
Ready to test this domain?
Drill mode gives instant feedback: pick a wrong answer and you immediately see why it is wrong.
Start the drill