A tool definition is the contract between Claude and your code. The single biggest lever on whether the model uses a tool correctly isn't the code behind it — it's the description and the JSON schema. Toggle a definition from sloppy to sharp and watch the model's behaviour flip.
Every tool has the same skeleton. The model never sees your implementation — it sees only these fields and reasons entirely from them:
| Field | What the model does with it |
|---|---|
name | A short handle it emits when calling. Make it descriptive (get_order_status, not tool3). |
description | The most important field. What it does, when to use it, when not to, side effects, units, and what it returns. Treat it like docs for a junior dev who can't ask questions. |
input_schema | A JSON Schema of the parameters: types, which are required, allowed enums, formats, and per-field descriptions. |
| (your code) | Runs when the model emits tool_use. The model never sees it — only the tool_result you return. |
A parameter the model must supply goes in required. But what about a field that's
optional or sometimes genuinely unknown? Don't just leave it out — model it explicitly. A field that can be
absent should be typed to allow null ("type": ["string", "null"]) and its description
should say when null is correct. Otherwise the model invents a value to fill the gap — the root cause
of hallucinated arguments in extraction tasks (Domain 4).
required forces the model to fabricate values it doesn't have —
make truly-optional fields nullable and say so.Curated companion: Anthropic — Tool use · Writing tools for agents.