Tool definitions, tool_choice, and strict
Three fields, and the exam’s favourite move in this whole domain is asking which object each one hangs off. Get the placement wrong and everything else you know is worth nothing.
It is the same class of knowledge as remembering that strict in a tsconfig goes under compilerOptions and not at the root. Nobody finds that interesting, everybody has been bitten by it, and being wrong about it invalidates a file that is otherwise perfect. Placement is not trivia. It is the difference between a request that works and a request that silently does not do what you meant.
The tool definition
Name, description, and an input_schema in JSON Schema. That is the contract.
{
"name": "get_weather",
"description": "Get the current weather for a city. Use when the user asks about conditions right now.",
"input_schema": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
}The description is not documentation, it is the routing logic. The model chooses tools by reading descriptions, so a vague one is a bug, and “gets weather” versus “use when the user asks about conditions right now” is the difference between a tool that fires correctly and one that fires whenever anybody mentions the sky.
tool_choice, and what it forces
Four shapes:
auto: the model decides whether to use a tool at all. The default when tools are present.any: it must call some tool, its pick.toolwith aname: it must call that tool.none: no tool calls this turn, even though the definitions are right there in the request.
none is the one people forget and it is quietly the most useful in a workflow. It leaves the model aware that the capability exists while forbidding it on this turn, which is exactly what you want on a summarisation step at the end of a run.
any and tool are how you convert a chat model into a structured-output machine: force a call, and the arguments are your parsed object.
strict, and the placement trap
strict: true goes on the tool definition. Next to name, next to description, next to input_schema.
{
"name": "get_weather",
"description": "...",
"input_schema": { "type": "object", "properties": { "city": { "type": "string" } } },
"strict": true
}And the second half of the same fact: strict is not available on mcp_toolset. Tools arriving through the MCP connector do not get strict tool use. Not “set it somewhere else”, not “on by default”: the capability is not there. That is a real constraint on architecture, not exam trivia, because it means moving a tool from your own definitions into an MCP server can silently cost you a guarantee you were relying on.
Parallel tool use, and its off switch
The model can request several tools in one turn, and it is on by default. Your loop handles it the way Lesson 2 said: one user message, several tool_result blocks, ids matched.
To turn it off you set disable_parallel_tool_use, and it lives on tool_choice.
Which is the placement fact worth writing down: tool_choice controls two different things. Whether a tool must be called, and whether more than one may be called at once. It does not control strict. If you remember only “strict on the definition, disable_parallel_tool_use on tool_choice”, you have the whole lesson.
Try it yourself
Where strict goes
You want guaranteed schema conformance on one of your tools. Where does strict: true actually go?
Show answer
Correct answer: B — On the tool definition itself, next to name, description and input_schema
strict is a property of the tool definition. The tool_choice answer is the designed trap and it is a good one, because tool_choice is the other object in the request with the word tool in it and it genuinely does control tool behaviour, just not this. The JSON Schema answer is tempting for anyone who knows schema validation, but strict is Anthropic's field, not a JSON Schema keyword.
One field, wrong object
One field in this request is on the wrong object. The tool description is also weak, but that is not what this card is testing.
{
"tools": [
{
"name": "create_invoice",
"description": "Create an invoice",
"input_schema": {
"type": "object",
"properties": { "amount": { "type": "number" } }
}
}
],
"tool_choice": { "type": "any", "strict": true }
}Show answer
Correct answer: A — strict belongs on the tool definition, next to name, description and input_schema
strict is a property of an individual tool definition, so it moves up into the object alongside name, description and input_schema. The top-level answer is the sharpest trap here, because it is the design you would choose yourself: per-request conformance is a perfectly coherent idea and it would be less repetitive. It is simply not the shape Anthropic chose, and on this paper the shape is the answer. tool_choice type any is fine with a single tool, and an absent required array is a schema-quality issue rather than the placement defect the question is about.
The tool_choice values
Four shapes, and one of them is the least obvious but most useful in a workflow.
Name the tool_choice options and say what each one forces.
Reveal answer
auto lets the model decide whether to call a tool at all, and is the default when tools are present. any forces it to call some tool, but leaves the choice open. tool with a name forces one specific tool. none forbids tool use entirely while leaving the definitions in the request, which is how you keep the model aware of a capability without letting it reach for it on this turn.
strict on an MCP tool
You liked strict so much you want it on the tools coming in through an mcp_toolset.
Show answer
Correct answer: C — You cannot. Strict tool use is not available on mcp_toolset
Strict tool use is unavailable on mcp_toolset, so this is a capability gap rather than a placement question. The on-by-default answer is the seductive one because the reasoning sounds sound: MCP servers do publish schemas, so surely conformance is handled. Publishing a schema and guaranteeing the model's output conforms to it are different guarantees, and only the second one is what strict means.
Turning parallel tool use off
A small placement fact, and placement facts are what this whole lesson is about.
Parallel tool use is on by default. Which object carries the switch that turns it off?
Reveal answer
disable_parallel_tool_use lives on tool_choice, not on the tool definition and not at the top level of the request. So tool_choice ends up controlling two separate things: whether a tool must be called, and whether several may be called at once.
Write one definition, and place both fields
Two minutes in a scratch file, no network. This is placement practice rather than schema practice, because placement is what the marks hang on.
- Write one complete tool definition for a tool you would genuinely use, with name, description and input_schema.
- Make the description say when to reach for the tool, not what the tool is.
- Add strict: true, and put it on the correct object.
- Beside it, write a tool_choice object that forces this specific tool by name and forbids parallel calls.