Defining a good tool (D2.1) and a good failure (D2.2) is only half the architect’s job; the other half is controlling whether and which tool the model may reach for. Two knobs do this at two different scopes: tool_choice steers a single request — force a tool, free the model, or forbid all tools — while the SDK’s allowedTools defines which tools even exist for an agent. The exam tests the four tool_choice modes (especially the one constraint that trips people up), the any+strict guarantee, and the difference between steering a call and distributing a surface.

The four tool_choice modes

tool_choice is the per-request control over tool calling, and it has four documented modes: auto (Claude decides — the default when tools are provided), any (Claude must use some tool but picks which), {"type": "tool", "name": …} (forces one specific tool), and none (no tools this turn — the default when none are provided). [Official] Define tools · AnthropicT1-official original Tool use with Claude · AnthropicT1-official original

Forced modes are incompatible with extended thinking

The constraint the exam loves: only auto and none are compatible with extended thinking; any and forced tool return an error, and adaptive thinking carries the same limitation. [Official] Tool use with Claude · AnthropicT1-official original Define tools · AnthropicT1-official original If you need the model to reason before acting, you cannot also force it to call a tool — the two are mutually exclusive.

Forced modes prefill the assistant message

Forcing has a second, subtler effect. “When you have tool_choice as any or tool, the API prefills the assistant message to force a tool to be used. This means that the models will not emit a natural language response or explanation before tool_use content blocks, even if explicitly asked to do so.” [Official] Define tools · AnthropicT1-official original A forced call therefore cannot also produce a spoken preamble — there is no room before the tool_use block for one.

Guarantee a schema-valid call: any + strict

any guarantees that a tool fires, but not that its inputs are valid — and forcing one specific tool isn’t always what you want. Compose two switches to get both guarantees at once: “Combine tool_choice: {'type': 'any'} with strict tool use to guarantee both that one of your tools will be called AND that the tool inputs strictly follow your schema. Set strict: true on your tool definitions to enable schema validation.” [Official] Define tools · AnthropicT1-official original any covers that a tool is called; strict: true (D2.2) covers that its arguments match the schema. Together they make “some tool, well-formed” a hard guarantee — the right shape for a classifier or extractor that must always emit structured output through a tool.

Distribution: scope the surface with allowedTools

tool_choice steers one request; distribution decides which tools an agent has at all, and in the SDK that knob is allowedTools / disallowedTools. The two behave differently: allowed_tools=["Read", "Grep"] pre-approves the listed tools (others still exist and fall through to the permission mode), while disallowed_tools=["Bash"] removes the tool from the request entirely, so the model never sees it. [Official] Configure permissions · AnthropicT1-official original

For MCP access the documented guidance is to scope with allowedTools rather than open the gates with a permission mode: a mcp__github__* wildcard “grants exactly the MCP server you want and nothing more,” whereas permissionMode: "bypassPermissions" auto-approves MCP tools but disables every other safety prompt — broader than necessary. [Official] Connect to external tools with MCP · AnthropicT1-official original

Parallel execution is a separate request-level control

A third knob is easy to confuse with tool_choice but is orthogonal to it: disable_parallel_tool_use. Claude 4 models may emit several tool_use blocks in one turn by default; setting disable_parallel_tool_use=true caps that — with tool_choice: auto Claude then uses at most one tool, and with any or forced tool it uses exactly one. [Official] Parallel tool use · AnthropicT1-official original

Practice

Exercise solutions

Solution ↑ Exercise

Forced tool mode is incompatible with extended thinking, so the request errors — you cannot both force a specific tool and let the model reason with extended (or adaptive) thinking. To get a schema-valid guaranteed tool call, combine tool_choice: {"type": "any"} (guarantees some tool fires — here only record_decision exists) with strict: true on the tool (guarantees the inputs match the schema). But any is also incompatible with thinking, so to keep the hard guarantee you must give up extended thinking on this turn (or move the reasoning to a prior tool-free turn and force/any the decision on the next). No single configuration gives you a forced, schema-valid call and visible reasoning at once; forcing also prefills the assistant turn and suppresses the preamble.

Solution ↑ Exercise

Use allowedTools: ["mcp__linear__*"] — the wildcard pre-approves exactly the linear server’s tools and nothing else. It is preferable to permissionMode: "bypassPermissions" because bypass auto-approves the MCP tools and disables every other safety prompt across the whole agent (far broader than you need), whereas the scoped wildcard grants exactly the one server and leaves all other gates intact.

Solution ↑ Exercise

Every turn that changes tool_choice invalidates the cached message blocks — tool definitions and the system prompt stay cached, but the message content has to be reprocessed — so alternating auto/forced means roughly every other turn pays full message-processing cost, which is why caching “barely helps.” The fix: keep tool_choice stable across the cached turns (don’t toggle it per turn); if some steps genuinely need a forced tool, group them so the value changes as rarely as possible rather than every turn.

Exam essentials