A hands-on guide to Claude tool use: defining JSON Schema tools, running the tool-use loop, handling errors, and shipping function calling to production with the Messages API.
Tool use is the feature that turns Claude from a text generator into a system component. By declaring tools with JSON Schema definitions in a Messages API request, you let the model decide when to query your database, call an internal service, or trigger a workflow — while your code stays in control of every actual execution. It is the foundation for agents, RAG orchestration, and most serious enterprise integrations.
This guide walks through the mechanics teams get wrong in their first production build: schema design that the model can reliably follow, the request-response loop, streaming and parallel calls, and the error-handling and cost patterns that separate a demo from a dependable service.
Tool use is a structured conversation protocol, not remote code execution. You pass a tools array in your Messages API request; each entry has a name, a description, and an input_schema written in JSON Schema. When Claude decides a tool is needed, the response ends with a stop_reason of tool_use and contains one or more tool-call blocks with validated-shape JSON arguments.
Your application then executes the real function — Claude never touches your infrastructure directly — and sends the output back as a tool_result block in the next user message. The model reads the result and either calls another tool or produces its final answer. Three consequences matter architecturally:
Most tool-use failures are schema-design failures. Claude reads your tool descriptions the way a new engineer reads documentation, so write them that way: state what the tool does, when to use it, and what it returns. A minimal, well-described tool outperforms a clever, ambiguous one.
tools = [{
"name": "get_invoice",
"description": "Fetch one invoice by ID from billing. Use when the user references a specific invoice.",
"input_schema": {
"type": "object",
"properties": {"invoice_id": {"type": "string"}},
"required": ["invoice_id"]
}
}]Practical rules that hold up in production:
enum for closed sets instead of free-text strings.required; make everything else optional with sane defaults.The core pattern is a while-loop: call the API, execute any requested tools, append results, repeat until Claude stops asking. Keep it boring and observable.
while response.stop_reason == "tool_use":
calls = [b for b in response.content if b.type == "tool_use"]
results = [run_tool(c.name, c.input) for c in calls]
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": [
tool_result(c.id, r) for c, r in zip(calls, results)
]})
response = client.messages.create(model=MODEL, tools=tools,
messages=messages, max_tokens=2048)Production hardening belongs around this loop, not inside the model: cap the number of iterations to prevent runaway loops, set per-tool timeouts, and log every tool call with its arguments and latency. Treat the loop as a state machine you can replay when debugging — the full message list is your trace.
Three capabilities change the ergonomics of tool use once you move past the happy path. First, streaming: the Messages API streams via server-sent events, and tool-call arguments arrive as incremental JSON deltas. Buffer them until the block completes before parsing — partial JSON is not parseable JSON.
Second, parallel tool calls: Claude can request several independent tools in a single turn, such as fetching a customer record and their open tickets simultaneously. Execute these concurrently and return all tool_result blocks together in one message; serializing them wastes latency for no correctness gain.
Third, structured outputs: when what you really want is a guaranteed JSON payload rather than an action, use structured outputs to constrain the final response shape instead of inventing a fake “return_answer” tool. Reserve tool use for genuine side effects and lookups; use output constraints for formatting. Mixing the two muddies both.
Tools fail in production — APIs time out, records go missing, inputs arrive malformed. The design question is what Claude sees when they do. Return errors as tool results with is_error set, containing a short, actionable message (“invoice not found; verify the ID”) rather than a raw stack trace. Claude will typically retry sensibly, ask the user for clarification, or explain the failure — but only if the error text gives it something to reason about.
Layer guardrails outside the model as well:
Tool definitions are tokens, and in a multi-turn loop you resend them — plus the growing transcript — on every iteration. Prompt caching is the single biggest lever here: cache the system prompt and tools block so repeated turns reuse it at a fraction of the cost and latency. For fleets of similar requests, the batch API handles non-interactive workloads cheaply.
Model selection is the second lever. Anthropic’s docs cover current options; as a rule of thumb, Claude Haiku 4.5 handles high-volume routing and simple single-tool calls, Claude Sonnet 5 is the balanced default for most tool-use loops, and Claude Opus 4.8 or Claude Fable 5 earn their cost on long multi-step reasoning chains.
Teams that want structured, hands-on practice with these patterns can work through our Claude API & MCP training or the immersive Claude Code bootcamp.
No. Claude only emits a structured request naming the tool and its JSON arguments. Your application executes the actual function, then returns the output as a tool result message. This keeps authorization, credentials, and side effects entirely inside your infrastructure, and makes every tool invocation auditable in the conversation transcript.
There is no meaningful hard ceiling for typical apps, but accuracy and cost degrade as tool counts grow, since every definition consumes prompt tokens and widens the decision space. Keep the set focused per use case, split large surfaces across routed sub-agents or MCP servers, and use prompt caching to offset the token overhead.
Use tool use when Claude must trigger real lookups or side effects mid-conversation. Use structured outputs when you simply need the final answer in a guaranteed JSON shape, such as extraction or classification results. They combine well: tools gather data during the loop, and structured outputs format the terminal response.
Hitesh Motwani is a globally recognised corporate AI trainer and generative-AI expert. He has trained 2,00,000+ professionals across 16+ countries on Claude, ChatGPT and generative AI, and advised leadership teams at Tata, Flipkart, Hitachi, Siemens, Adani and Marks & Spencer. Connect on LinkedIn →
…and 200+ organisations, across 16+ countries.
Verified feedback collected from participants across corporate sessions — average rating 4.8/5.
“A very productive session for working professionals. A must-do.”
“The session was highly insightful and conducted in a very professional and interactive manner. Learnt about AI and excited to learn more!”
“Highly recommended! Hands-on and directly useful — from making PPTs and strategic plans to building KRAs.”
“Great work done by Mr Hitesh in the AI landscape — a true subject-matter expert. More power to him for spreading this knowledge.”
“I would recommend everyone to go through this session — it clarifies both what to expect from AI and where AI isn’t needed.”
“Amazing session by Hitesh. The AI tools he shared are very helpful for day-to-day work.”
“Mr Hitesh Motwani is a very informative trainer. The way he delivers training is awesome.”
“Mr Hitesh Motwani delivered a valuable, informative session and showed us exactly how to use AI tools to enhance our work. Thank you so much.”
“A nice interactive session with a lot of new insights and the power of AI. This will help me save time in routine activities.”
“A very good training session. AI can do wonders — we’ll implement it to create efficiency and save time.”
“Hitesh was very informative and knowledgeable about AI tools. It will let me use my time far more effectively.”
“Your session helped me walk into the world of magic.”
Tell us your team, tools and goals and we will send a fixed proposal — usually within one business day.