Module 3 of 10, lesson 1 of 5
Tools and MCP
Follow a tool call from end to end and design tools a model uses correctly.
Much of an agent’s quality is decided by its tools.
The model executes nothing
A tool call happens in four steps:
- You send the model the conversation and the list of tools, with their descriptions and schemas.
- The model replies with a structured request: this tool, these arguments.
- Your code validates that request and runs it.
- You send the result back to the model, which continues.
Step 3 is your control point: authorization, argument validation, logging. The model proposes, your code decides.
Writing a good tool
- The model reads the name and description: they’re part of the prompt.
- Prefer a few well-separated tools to many overlapping ones.
- Return errors that explain what to fix. The model can then recover by itself.
- Limit result size: every response uses up context.
- Make writes idempotent, because an agent may repeat the same action.
MCP
Model Context Protocol is an open standard for connecting an agent to data sources and tools. A host embeds a client, the client connects to servers, and each server exposes what it can do. A tool written once works with any compatible client.
MCP solves connection, not trust. A third-party server can describe its tools misleadingly or return booby-trapped content. Treat it like a dependency: audit it.
The model proposes, your code validates and executes.
Worked example: An error the model can act on
The model proposes, your code decides. When a call is refused, the message goes back to the model, so it must say what to do next.
function refundOrder(input, orders) {
const order = orders[input.orderId];
if (!order) return { error: 'Unknown order. Ask the customer to confirm the number.' };
if (input.amount > order.total) {
return { error: `Amount too high. The most you can refund is ${order.total}.` };
}
return { refunded: input.amount };
}
const orders = { 4512: { total: 80 } };
refundOrder({ orderId: 4512, amount: 120 }, orders);
{ error: 'Amount too high. The most you can refund is 80.' }
A bare “invalid input” leaves the model guessing. Here it gets the limit, and it can correct the call on its own.
Try it in the editor
// registry: { name: { schema, run } }async function execute(block, registry) { const tool = registry[block.name]; const output = await tool.run(block.input); return { type: 'tool_result', tool_use_id: block.id, content: JSON.stringify(output) };}module.exports = { execute };