Claude API Tool Use Schema Design: A Practical Guide
Designing a good tool schema for Claude's tool use (function calling) feature determines whether the model picks the right tool, fills in correct arguments, and avoids hallucinating parameters. The two things that matter most are naming clarity and JSON Schema precision — Claude reads your tool definitions the same way it reads any other text, so vague descriptions produce vague tool calls.
This guide covers how to structure tool schemas so Claude reliably selects the correct tool, extracts the right arguments, and handles edge cases like optional fields, enums, and nested objects without guessing.
How Claude decides which tool to call
Claude picks a tool based on the name and description fields in your tool definition, combined with the conversation context. It does not see your backend code, variable names, or internal documentation — only what's in the schema. If two tools have overlapping descriptions, Claude will sometimes pick the wrong one or call both.
The practical rule: write tool descriptions as if explaining them to a new engineer who has never seen your codebase. Mention what the tool does, when to use it, and when not to use it if there's a tool it could be confused with.
{
"name": "get_order_status",
"description": "Retrieves the current shipping status and estimated delivery date for an existing order. Use this when the user asks about an order they already placed. Do not use this to create or cancel orders.",
"input_schema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "The order identifier, e.g. 'ORD-48213'. Always starts with 'ORD-'."
}
},
"required": ["order_id"]
}
}
That last sentence in the description — "Do not use this to create or cancel orders" — is a disambiguation hint. It costs almost nothing in tokens and meaningfully reduces wrong-tool selection when you have several similarly named tools.
Schema structure best practices
Keep parameter names self-explanatory. customer_email beats email, cust_em, or e. Claude infers type and intent partly from naming, and short cryptic names increase the odds of malformed output.
Use enums wherever the value space is fixed. If a parameter only accepts "low", "medium", or "high", declare it as an enum instead of a free-text string with a description. This removes an entire class of invalid values.
"priority": {
"type": "string",
"enum": ["low", "medium", "high"],
"description": "Urgency level for the support ticket."
}
Mark required fields explicitly. The required array in JSON Schema is not optional decoration — Claude uses it to decide whether it has enough information to call the tool or whether it should ask a clarifying question first. Omitting it makes every field feel optional, which leads to incomplete calls.
Avoid deeply nested objects when a flat structure works. Claude handles nested objects correctly, but every level of nesting is another place where a key can be misnamed or a type can be wrong. If a tool only needs three or four scalar values, don't wrap them in a nested metadata object just for tidiness.
Add format descriptions for strings that aren't plain text. Dates, IDs with prefixes, phone numbers, and currency amounts should get a one-line format hint in the description field, since JSON Schema's type: string alone tells Claude nothing about expected shape.
"due_date": {
"type": "string",
"description": "ISO 8601 date, e.g. '2025-03-14'. Do not use relative terms like 'next week'."
}
Handling multiple tools without confusion
As tool count grows past five or six, naming collisions and overlapping purposes become the main source of errors. A few patterns help:
- Prefix related tools consistently —
invoice_create,invoice_get,invoice_cancelreads clearer to the model thancreateInvoice,fetchInvoice,cancelInvoiceOp. - Put the discriminating detail first in the description. "Searches products by name or SKU" is more useful than a long paragraph where the key fact is buried in the third sentence.
- Don't register tools you don't need for the current conversation. If your app has 30 tools but a given request only needs 3, filter the tool list server-side before sending the request. Fewer tools in context means fewer wrong matches.
Validating and parsing tool_use responses
Claude returns a tool_use content block with a name and an input object matching your schema. Always validate input against the same JSON Schema you sent — Claude is reliable but not infallible, and malformed input (missing required fields, wrong enum values) should be caught before your tool-execution code runs, not after.
const schema = toolDefinition.input_schema;
const result = validate(schema, toolUseBlock.input); // ajv or similar
if (!result.valid) {
// send a tool_result with an error message back to Claude
// so it can retry with corrected arguments
}
Feeding validation errors back to Claude as a tool_result with is_error: true is more effective than silently failing — Claude will usually correct the arguments on the next turn.
Testing your schemas
Before shipping, run each tool through a handful of adversarial prompts: ambiguous phrasing, missing information, and requests that should trigger a clarifying question instead of a tool call. If Claude is guessing on required fields instead of asking, your required array or descriptions probably need tightening.
If you're building tool-using applications on top of Claude and want streaming, usage metadata, and per-key tracking without managing your own API infrastructure, SubToAPI turns your Claude access into a standard HTTPS API with sub_live_ application keys. Tool use works the same way you'd expect against the Messages endpoint — see the tool use docs and the quickstart for setup, or check messages and streaming for the rest of the API surface.
questions
Should every tool parameter have a description field? Yes. Even obvious-seeming fields benefit from a short description, since Claude uses it both for argument extraction and for deciding whether the tool matches the user's intent at all.
How many tools can Claude handle in one request before accuracy drops? There's no hard limit, but accuracy tends to degrade past 15–20 tools with overlapping purposes. Filtering the tool list to what's relevant for the current request keeps selection accurate.
What's the best way to handle optional parameters with defaults? Omit them from required and state the default behavior explicitly in the description, e.g. "Defaults to 10 if not specified." Claude will then omit the field when the user doesn't mention it, and your code applies the default.