Connecting Claude to Your Business Tools: A Practical Guide to Tool Calling
Tool calling is how an AI model stops talking and starts doing — reading your CRM, updating a record, sending an email. A hands-on guide to designing tools models can use reliably.
- Tool Calling
- Integrations
- Claude
- MCP

A model on its own can only produce text. The moment you want it to check an order, update a CRM record, or trigger a workflow, you need tool calling — a structured way for the model to say "call this function with these arguments" and for your code to run it and hand back the result. This is the bridge between a chatbot and something that does real work.
The concept is standard across Claude, GPT, and Gemini, and increasingly across the Model Context Protocol (MCP). What separates a reliable integration from a flaky one is entirely in how you design the tools — so that is what this guide is about.
Anatomy of a tool
A tool is three things: a name, a description, and an input schema. The model reads all three to decide when and how to call it.
const getOrderStatus = {
name: 'get_order_status',
description:
'Look up the current status of a customer order by its id. ' +
'Use when a customer asks where their order is.',
input_schema: {
type: 'object',
properties: {
orderId: {
type: 'string',
description: 'The order id, e.g. "ORD-10432". Ask the customer if unknown.',
},
},
required: ['orderId'],
},
} as constThe description is not documentation for you — it is a prompt for the model. "Use when a customer asks where their order is" tells the model the trigger; "Ask the customer if unknown" tells it what to do when it lacks the argument. Vague descriptions are the number one cause of tools the model calls at the wrong time or not at all.
The execution loop
You send the model the tools it may use. It replies either with text or with a tool call. You run the tool, send the result back, and it continues — possibly calling another tool — until it produces a final answer.
async function converse(messages: Message[]) {
let res = await model.chat({ messages, tools: TOOLS })
while (res.stopReason === 'tool_use') {
const outputs = await Promise.all(
res.toolCalls.map(async (call) => ({
toolCallId: call.id,
content: await execute(call.name, call.input), // your real function
})),
)
messages.push(res.assistantTurn, { role: 'tool', content: outputs })
res = await model.chat({ messages, tools: TOOLS })
}
return res.text
}Designing tools the model uses well
A few rules earn their keep on every integration we build:
- One clear job per tool. Prefer "get_order_status" and "cancel_order" over one "manage_order" with a mode flag. Focused tools are chosen correctly far more often.
- Validate every argument. The model can produce malformed input. Treat tool arguments exactly like untrusted user input — validate before you touch a database or an API.
- Make writes explicit and reversible. Tools that change data should require unambiguous arguments and, where it matters, a confirmation step. Never let a model delete something on an inferred id.
- Scope permissions to the tool. The credential a read-only lookup tool uses should not be able to write. The model orchestrates; your permissions decide what is actually possible.
A note on MCP
The Model Context Protocol standardises this pattern as a server: you expose your tools once, over MCP, and any compatible model or client can use them. If you are integrating the same systems across several assistants, an MCP server saves you re-describing tools per project. The design rules above do not change — MCP is a cleaner distribution mechanism for exactly the tools we just designed.
Get the tools right and the model becomes genuinely useful: it reads your systems, takes safe actions, and stays inside the guardrails your code enforces. Get them vague and it flails. The intelligence is in the boundary you design, not just the model behind it.
Explore AI & Automation
