TimoBy Amotion AI

Tool distribution and tool choice: CCAR-F task statement 2.3

CCAR-F · Tool Design & MCP Integration (18% of the exam)

Task statement 2.3 sits in Tool Design & MCP Integration, 18% of the CCAR-F exam. It tests two decisions: which tools each agent should get, and when to use tool_choice to make Claude call a tool, or one particular tool, instead of leaving the choice to Claude.

What the official guide covers

The Claude Certified Architect Foundations exam guide (version 1.0, effective July 2026) lists this under task statement 2.3, "Distribute tools appropriately across agents and configure tool choice":

Knowledge ofSkills in
Too many tools on one agent (the guide's example is 18 instead of 4 or 5) make tool selection less reliableLimiting each subagent's tools to those its role needs
Agents given tools outside their speciality tend to misuse them, such as a synthesis agent running web searchesReplacing generic tools with constrained ones, such as load_document that validates URLs instead of an open fetch_url
Scoped access: role tools only, plus a few cross-role tools for frequent needsGiving a scoped cross-role tool (a verify_fact for the synthesis agent) while complex cases still go through the coordinator
tool_choice options: "auto", "any" and forced selection with {"type": "tool", "name": "..."}Forcing a specific tool first, then handling later steps in follow-up turns; using "any" to guarantee a tool call instead of text

Why fewer tools per agent works better

Every tool definition is something Claude must read and weigh on every turn. With four or five tools that each do a clear job, the right choice is usually obvious. With eighteen, several will look relevant to most requests, and Claude has more chances to pick a near miss. Anthropic's tool documentation makes the same point: fewer, more capable tools reduce selection ambiguity.

Tool access also shapes behaviour. If a synthesis agent has a web search tool, it will sometimes search instead of working with the findings it was given. That duplicates the search agent's work and mixes unchecked sources into the draft. Removing the tool removes the temptation.

The opposite failure exists too. An agent missing a tool it needs will improvise with whatever it has, or return a partial answer without saying so. The practical rule: start each role with the smallest set that covers its job, and add a tool only when a test run shows a real gap. Registering tools "just in case" is how agents end up with eighteen.

Keep the system prompt in step with the tool list. A prompt that mentions a tool the agent does not have invites calls that fail, and a prompt that ignores a tool needing special care leaves Claude to guess when to use it.

How to scope tools in the Agent SDK (Python)

Each subagent's AgentDefinition takes a tools list. A tool left out of that list is not in the subagent's session at all. If you omit tools, the subagent inherits every tool available to subagents, so always set it for specialised roles.

from claude_agent_sdk import ClaudeAgentOptions, AgentDefinition

options = ClaudeAgentOptions(
    mcp_servers={"research": research_server},          # your MCP server
    allowed_tools=["Agent", "mcp__research__*"],         # coordinator delegates; MCP tools pre-approved
    agents={
        "web-searcher": AgentDefinition(
            description="Finds public sources for one research question and returns excerpts with URLs.",
            prompt="Search, read and return excerpts with source URLs and dates. Do not write the report.",
            tools=["mcp__research__search_web", "mcp__research__load_document"],
        ),
        "synthesizer": AgentDefinition(
            description="Combines findings it is given into a cited draft. Does not search.",
            prompt="Write the draft from the findings provided. Use verify_fact only for single facts.",
            tools=["mcp__research__verify_fact"],      # scoped cross-role tool, no open search
        ),
    },
)

The synthesiser gets verify_fact for quick checks of a date or a name. A question that needs real research goes back through the coordinator to the search agent. That keeps the common case fast without giving the synthesiser the whole search toolkit.

The same idea applies to single tools. An open fetch_url lets an agent load anything. A load_document tool that accepts only document URLs from approved sources does the job the role needs and nothing more.

Exposing only part of a large MCP server

An MCP server often brings many tools when a role needs three. Every tool definition Claude can see takes context and adds one more option to weigh, so the platform gives you ways to narrow what is exposed.

On the Messages API, the MCP connector takes an mcp_toolset entry per server. Set enabled to false in default_config and switch on only the tools the role needs; defer_loading keeps a tool's definition out of the initial context until it is needed.

{
  "type": "mcp_toolset",
  "mcp_server_name": "crm",
  "default_config": { "enabled": false },
  "configs": {
    "search_accounts": { "enabled": true },
    "get_account": { "enabled": true }
  }
}

In Claude Code, tool search is on by default in most setups, so MCP tool definitions are loaded when a task calls for them rather than all at once. Permission rules work per tool, written as mcp__server__tool. A deny rule that names a tool on its own removes it from Claude's context; an allow rule lets one named tool run without a prompt while the server's other tools keep their normal approval behaviour.

Two different controls are at work here. Hiding a tool (connector enabled: false, or a deny rule) means Claude never considers it. A permission prompt means Claude can choose it, but a person approves each call. Use hiding for tools outside the role, and prompts for in-role tools with serious side effects.

How tool_choice works

tool_choice is a Messages API parameter. It has four values:

ValueWhat Claude doesUse it when
{"type": "auto"}Decides whether to call a tool and which one. Default when tools are providedNormal agent turns
{"type": "any"}Must call one of the provided tools, but chooses whichYou need a tool call, not a text answer, and any of the tools is acceptable
{"type": "tool", "name": "extract_metadata"}Must call that one toolOne step must happen first, every time
{"type": "none"}Cannot call tools. Default when no tools are providedYou want a text-only reply while keeping tool definitions in the request

Two details from the documentation matter. With any or a forced tool, the API prefills the assistant turn, so Claude does not write any text before the tool_use block, even if asked to. And any and forced tool choice are not supported with manually enabled extended thinking, and some newer models reject them with an error; check the model before you rely on them.

The tool_choice object also carries disable_parallel_tool_use. Set it to true and Claude calls at most one tool per response under auto, or exactly one under any or a forced tool. Use it when one call's result decides the next call, so the steps cannot be issued together.

Force the first step, then hand back control (Python)

The guide's pattern is to force one tool on the first request and let Claude decide afterwards.

messages = [{"role": "user", "content": f"Process this contract:\n\n{contract_text}"}]

# Turn 1: metadata extraction must happen first
first = client.messages.create(
    model=MODEL, max_tokens=2048, tools=TOOLS, messages=messages,
    tool_choice={"type": "tool", "name": "extract_metadata"},
)
messages.append({"role": "assistant", "content": first.content})
messages.append({"role": "user", "content": run_tools(first.content)})   # tool_result blocks

# Later turns: Claude chooses the enrichment tools it needs
while True:
    response = client.messages.create(
        model=MODEL, max_tokens=2048, tools=TOOLS, messages=messages,
        tool_choice={"type": "auto"},
    )
    messages.append({"role": "assistant", "content": response.content})
    if response.stop_reason == "end_turn":
        break                                   # the task is finished
    if response.stop_reason == "pause_turn":
        continue                                # server tool paused: send the turn back as it is
    if response.stop_reason != "tool_use":      # max_tokens, refusal, context full: see task statement 1.1
        raise RuntimeError(f"Loop stopped early: {response.stop_reason}")
    messages.append({"role": "user", "content": run_tools(response.content)})

If you kept the forced choice on every turn, Claude would call extract_metadata again and again and never move on.

Which setting to choose

SituationChooseWhy
One agent holds 15 or more tools and picks wrong onesSplit tools across role-specific subagentsFewer, clearer choices per agent
A subagent uses a tool that belongs to another roleRemove it from that subagent's tools listAbsent tools cannot be misused
A role needs one small capability from another role, oftenA scoped cross-role tool such as verify_factSaves round trips without granting the full toolkit
A step must always run firstForced tool_choice on the first request, then autoGuarantees order, then returns control
Every reply must be a tool call, any tool will dotool_choice: {"type": "any"}No conversational text replies
Claude should decideautoThe default for agent loops
A role needs 3 of a server's 40 toolsConnector allowlist (enabled) or per-tool deny rulesUnneeded tools never reach the role
An in-role tool can delete or sendKeep it visible, require approval per callThe role needs it; a person checks each use
Each step depends on the previous resultdisable_parallel_tool_use: trueOne tool call per response

Rules that decide exam answers

  • Fewer tools per agent, chosen by role. When an agent misuses tools or picks near misses, reduce and scope its tool set before tuning prompts.
  • Remove, do not instruct. If a subagent must never search the web, leave the search tool out. A prompt saying "do not search" is weaker.
  • Scoped cross-role tools for the common case. Give a narrow tool for frequent simple needs and keep complex cases on the coordinator path.
  • any guarantees a tool call; forced guarantees a specific tool. Pick any when several tools are acceptable and only text is the problem.
  • Force once, then switch to auto. A forced tool is for the first step; later steps happen in follow-up turns.
  • Hide what the role never needs; gate what it needs but is risky. Allowlists and deny rules narrow what Claude sees. Approval prompts check individual calls. They solve different problems.

Where it appears in the exam

Tool Design & MCP Integration is a primary domain in three of the six exam scenarios: Customer Support Resolution Agent, Multi-Agent Research System and Developer Productivity with Claude. Tool scoping across subagents fits the research scenario most closely. The guide's practice exercise on a multi-agent research pipeline reinforces this domain.

Two sample questions

These are original Timo practice questions. They are not official exam questions.

Question 1

A research system's document-analysis subagent was given all 16 tools the system uses, including an open fetch_url. Reviews show it often loads unrelated web pages and quotes them as if they came from the supplied documents. What should the architect do?

Answer: A. Scoping tools by role and constraining the generic tool removes the misuse at its source. B relies on the prompt while the tool stays available. C leaves the subagent unable to load the documents it needs. D cleans up after the problem instead of preventing it.

Question 2

A ticket-triage service sends each new ticket to Claude with three tools: route_to_billing, route_to_support and route_to_sales. About one ticket in twenty gets a text reply such as "This looks like a billing issue" and no tool call, which breaks the pipeline. Any of the three tools is a valid outcome. Which setting fixes this?

Answer: D. any requires a tool call while letting Claude choose the right one. A still allows text replies. B forces every ticket to support. C removes tool calls entirely and makes the pipeline parse free text.

Build exercise

  1. Give one agent 15 tools and run 30 mixed requests, logging each tool call. Then split the tools across three role-specific subagents and run the same requests.
  2. Remove a search tool from a synthesis subagent and add a narrow verify_fact tool instead. Check that complex questions still go back through the coordinator.
  3. Send the same prompt with tool_choice set to auto, any, a forced tool and none. Note when Claude writes text and when it calls a tool.
  4. Build the force-then-auto loop above and confirm the forced tool runs once, then Claude chooses freely.

Practise this topic

Sources