Tools & Function Calling
How a model asks your code to run a function — schemas, the call cycle, writing descriptions that work, error handling, parallel calls, and MCP
Tools & Function Calling
TL;DR
A tool is a function the model can ask you to run. It never runs anything itself — it outputs a structured request, and your code decides whether to comply. Getting tools right is most of the work in building a good agent, and the part that decides success is unglamorous: the wording of your tool descriptions.
| Property | Value |
|---|---|
| Level | Beginner → Intermediate |
| Reading time | ~22 minutes |
| Prerequisites | What Is an Agent? |
| You will understand | Tool schemas, the call cycle, descriptions, errors, and MCP |
The Call Cycle
This is the mechanism. Everything else in this page is detail on top of it.
One tool call, end to end
Step 3 is the whole security model of agents. The model produces intent; your code produces action. Everything you will ever do about safety — permissions, validation, approval gates, rate limits, audit logs — happens at that step. Wire model output straight into execution and you have deleted the only checkpoint you had.
What a Tool Definition Contains
name: get_revenue
description: Look up recorded revenue for one region and one quarter.
Use this for any question about actual past sales figures.
Do NOT use this for forecasts or projections — use
get_forecast for those.
parameters:
region (string, required) One of: Europe, Americas, APAC
quarter (string, required) One of: Q1, Q2, Q3, Q4
year (integer, required) Four-digit year, e.g. 2025
currency (string, optional) Defaults to EUREvery part earns its place:
| Part | Job | If you get it wrong |
|---|---|---|
| Name | Identifies the tool | Vague names get confused with each other |
| Description | Tells the model when to use it | The tool gets ignored, or called at the wrong time |
| Parameter types | Constrains what can be sent | Bad arguments and runtime errors |
| Enums | Restricts to valid values | The model invents plausible-sounding invalid values |
| Required flags | Says what cannot be omitted | Calls arrive missing fields |
| Examples | Shows the expected shape | Correct types, wrong format |
Descriptions Are Prompts, Not Documentation
This is the single highest-leverage thing on this page. The description is the only information the model has when deciding whether to use a tool.
The same tool, described two ways
'Gets data from the sales system.'
Useless. Which data? When would this be the right choice over the other six tools? The model has to guess, and it guesses badly and inconsistently.
'Look up recorded revenue for one region and one quarter. Use for any question about actual past sales. Do NOT use for forecasts — use get_forecast instead.'
RecommendedSays what it does, when to use it, and when not to. That last clause prevents more wrong calls than anything else you can write.
| Write this | Not this |
|---|---|
| "Use for questions about past sales figures" | "Gets sales data" |
| "Do NOT use for forecasts — use get_forecast" | (nothing about boundaries) |
| "region: one of Europe, Americas, APAC" | "region: the region" |
| "Returns an empty list if no records match" | (nothing about the empty case) |
| "year: four-digit, e.g. 2025" | "year: the year" |
When an agent ignores a tool or picks the wrong one, rewrite the description before you touch the model choice. In practice this fixes the problem far more often than a bigger model does, and it costs nothing.
How Many Tools?
| Number | What happens |
|---|---|
| 1–5 | Reliable. The model rarely picks wrongly. |
| 6–15 | Good, if the descriptions clearly separate them |
| 15–30 | Noticeably worse. Similar-sounding tools get confused. |
| 30+ | Unreliable. Also expensive — definitions are sent on every call. |
Ways to keep the list short:
| Technique | How |
|---|---|
| Merge similar tools | One search with a source parameter beats six separate search tools |
| Route by task type | Show only the handful relevant to the current job |
| Group behind one interface | A single database_query tool instead of one per table |
| Remove unused tools | Check your traces — tools that are never called are pure cost |
Tool definitions are sent with every single request in the loop. Thirty verbose definitions can be thousands of tokens paid repeatedly on every iteration of every task. Trimming the list often cuts cost noticeably before it improves accuracy.
Errors
How you handle tool failure decides how well your agent recovers. This is under-appreciated.
What a failed tool should return
Silent empty result
Returning [] with no explanation. The model cannot tell whether nothing matched, the query was wrong, or the service is down — and will often conclude the answer is "there is none".
A raw stack trace
Wastes hundreds of tokens and tells the model nothing it can act on.
An error string returned as normal data
The worst case. "ERROR: invalid region" looks like a result, and the agent may quote it back to the user as a finding.
A clear, structured, actionable error
Recommended{"error": "invalid_region", "message": "Region 'EU' not recognised. Valid values: Europe, Americas, APAC."} — the agent can now fix its own call and retry.
| Failure | What to return |
|---|---|
| Bad arguments | Say which argument, and what the valid values are |
| Nothing found | "No records matched" — explicitly, not an empty list |
| Service down | Say it is temporary and whether retrying will help |
| Not permitted | Say the agent lacks permission, so it stops trying |
| Too much data | Return a summary and a count, not a truncated dump |
Good errors make an agent self-correcting. An agent told "region 'EU' is not valid, use 'Europe'" fixes itself on the next iteration. An agent given [] concludes there is no revenue in Europe and reports that as a fact.
Parallel Tool Calls
Modern models can request several tools at once when the calls do not depend on each other.
One turn, three calls
get_revenue(Europe)
Runs immediately
get_revenue(Americas)
Runs at the same time
get_revenue(APAC)
Runs at the same time
| Consideration | Detail |
|---|---|
| When it works | The calls are independent — none needs another's result |
| The gain | Three lookups take the time of the slowest, not the sum |
| The catch | Your code must actually run them concurrently to get the benefit |
| Watch out | Partial failure. Decide what happens when two succeed and one fails. |
Designing Safe Tools
The tool is where an agent touches the real world, so this is where safety is designed.
| Principle | In practice |
|---|---|
| Narrowest scope that works | A read-only database user, not an admin connection |
| Separate read from write | Reads can be free; writes go through checks |
| No destructive tool without a gate | Deletes, payments, and sends need approval or reversibility |
| Validate before executing | Never trust the arguments — check them like untrusted user input |
| Make retries safe | An idempotency key so a repeated call does not send twice |
| Log every call | Tool, arguments, result, and who approved it |
Treat tool arguments exactly like input from an anonymous user on the internet, because functionally that is what they are — text produced by a model that may have read an attacker's instructions in a web page. Parameterise queries, check permissions server-side, and never build a shell command by string concatenation from model output.
MCP — Model Context Protocol
MCP is a standard for exposing tools to models. Instead of writing custom integration code for every model and every tool, a tool provider implements the protocol once and any MCP-capable client can use it.
| Aspect | Detail |
|---|---|
| The problem it solves | Every tool integration written separately for every framework |
| How it helps | One server exposing tools; many clients can connect |
| What it does not change | Descriptions still matter, the list should still be short, errors still need care |
MCP changes distribution, not design. Connecting a server that exposes forty tools gives you the same tool-overload problem as writing forty by hand. Everything on this page still applies.
Build one: MCP Tool Integration
Common Mistakes
What goes wrong with tools
Vague descriptions
The number one cause of "the agent ignored my tool". Say when to use it and when not to.
Tool never sent to the model
Registered in your code, missing from the request. Log the definitions you actually send — this bug is common and invisible from the outside.
Free-text parameters where enums belong
region: string invites "EU", "europe", "Western Europe". An enum makes the whole class of error impossible.
Returning errors as normal text
The agent reads them as data and reports them as findings.
Thirty tools, all sent every call
Choice quality falls and you pay for the definitions on every iteration.
Executing without validating
The model's output is untrusted input. Treat it that way.
Dumping huge results into context
A 50,000-token API response wrecks your context budget. Summarise or paginate before returning.
Concept Checks
Check yourself
Why is a tool description prompt engineering rather than documentation?
Because it is read by the model at decision time, not by a developer at build time. It is the only evidence available when the model chooses between tools, so its wording directly determines behaviour. "Gets data" leaves the choice to guesswork; naming when to use the tool and when to prefer a different one changes what the model actually does. Rewriting a description is usually a cheaper and more effective fix than changing models.
Your tool returns an empty list when nothing matches. What goes wrong?
The agent cannot distinguish "searched successfully, found nothing" from "the query was malformed" or "the service failed". It typically takes the empty result at face value and reports that no such records exist, which may be entirely false. Returning an explicit message — "no records matched region Europe for Q3 2025" — lets the agent either trust the finding or realise its arguments were wrong and retry.
Why does adding more tools make an agent worse, beyond the token cost?
Because tool selection is a discrimination task, and it gets harder as options multiply and overlap. With forty tools, several will sound applicable to any given step, and the descriptions have to do more work to separate them than they usually can. The model then picks inconsistently between near-synonyms. Merging similar tools behind one parameterised interface reduces the number of decisions rather than making each one harder.
Why treat tool arguments as untrusted input when your own model produced them?
Because the model may have read an attacker's text. Anything it fetched — a web page, an email, a document, a support ticket — can contain instructions aimed at influencing its next tool call. The arguments are therefore text shaped by content you do not control. Parameterise queries, check permissions on the server side, and never build shell commands from that string. The model is a channel, not a trust boundary.
Key Concepts Recap
| Concept | One-line summary |
|---|---|
| The model requests | It outputs intent; your code produces action |
| Validation step | The one checkpoint where all safety lives |
| Descriptions are prompts | Say what, when, and when not |
| Enums over free text | Removes a whole class of bad arguments |
| Keep the list short | Quality falls past ~15 tools; definitions are billed every call |
| Errors must be actionable | Good errors make agents self-correcting |
| Never return silent failure | Empty results get read as facts |
| Parallel calls | Independent lookups can run at once |
| Narrowest scope | Read-only where possible; gates on destructive actions |
| Untrusted arguments | Model output can be shaped by content an attacker wrote |
| MCP | Standardises distribution, not design |
Next
You have tools. Now the loop that uses them repeatedly: The Agent Loop.
What Is an Agent?
What separates an agent from a chatbot and a workflow, the four parts every agent has, and the honest guide to when you should not build one
The Agent Loop
ReAct and the think-act-observe cycle — how iteration works, why termination is the hardest part, and the limits every agent needs