# Tools & function calling

Canonical URL: https://agentlearn.dev/learn/agents/tools
Author: [Hemanth HM](https://h3manth.com)
Track: agents
Reading time: 10 minutes

A tool call is an untrusted request to application code. A schema describes the request; authorization determines whether it may run.

## Keep the boundary outside the model

The model can propose lookupOrder({orderId}). Your application must check the argument type and verify that the authenticated customer may access that order. Hiding another customer's order from the prompt is not an access-control system. The same checks must hold even if the model outputs a malicious or malformed request.

## How it works

Prefer narrow tools with explicit input and output schemas. Return structured errors such as NOT_FOUND or FORBIDDEN rather than fabricated success text. Separate read-only lookups from writes. A refund tool also needs approval rules, amount limits, an idempotency key, and an audit trail. Never turn an arbitrary model-provided string into shell code or a database query.

## A concrete example

A valid order ID might still belong to another customer. The exercise accepts a syntactically correct request but enforces ownership before revealing the order. In production, derive identity from the authenticated session, not a customerId that the model supplies.

## Apply it to your assistant

Change orderId to B200 and confirm the ownership check rejects it. Before running the exercise, predict the result. Afterward, explain which assumption changed and add one case where the system should refuse, ask for clarification, or escalate.

All exercise inputs and outputs are deterministic teaching examples. No language model is called. Run the same idea against a versioned dataset before making a production claim.


## Key takeaway

Validate syntax, enforce identity-based authorization, and constrain side effects independently.

## JavaScript exercise: Tools & function calling · code experiment

Change orderId to B200 and confirm the ownership check rejects it.

```javascript
const sessionCustomer = 'customer-1';
const orders = { A100: { owner: 'customer-1', status: 'shipped' }, B200: { owner: 'customer-2', status: 'pending' } };
function lookupOrder(orderId) {
  if (typeof orderId !== 'string') return { error: 'INVALID_ARGUMENT' };
  const order = orders[orderId];
  if (!order || order.owner !== sessionCustomer) return { error: 'NOT_AVAILABLE' };
  return { status: order.status };
}
console.log(lookupOrder('A100'));
```

## Knowledge check

A model provides a correctly shaped request for another customer's order. What should happen?

1. Execute because the schema is valid
2. Reject using server-side ownership checks
3. Ask the model whether it is safe

Answer: Reject using server-side ownership checks

Schema validation and authorization solve different problems. The authenticated principal, not the model, determines access.

## Sources

- [Model Context Protocol specification](https://modelcontextprotocol.io/specification/2026-07-28) — MCP contributors, 2026-07-28. Versioned protocol reference. Implementation details should be checked against the version you deploy.
