# Write tool descriptions an agent can act on.

> How to write tool names, descriptions and JSON schemas that help an AI agent choose correctly, and why tool text deserves review like interface copy.

Published: 2026-09-11  
Updated: 2026-10-13  
Changelog: 2026-10-14: Separated schema validation from model behaviour, removed unmeasured performance claims, and kept the existing fixture route.  
Changelog: 2026-09-18: Retitled away from the X-not-Y headline template while keeping tool descriptions in the title, H1 and card; body unchanged.  
Canonical: https://agentexperience.tech/insights/tool-descriptions/  
Tags: tools, documentation, tool selection, json schema

**Summary**

A tool name, its description, and its input schema are the interface an agent uses to decide what happens next, which makes them product copy rather than code comments. Write what the action is for, when it is the right choice, when it is not, what it needs, and what changes on success. Name the nearest neighbouring tool explicitly. Put constraints in the schema, not only in prose. Treat safety annotations as selection hints and enforce boundaries in the server. Then version and test the descriptions like any other part of the interface.

1. Tool descriptions are a decision surface; the other context an agent can inspect depends on its harness and available sources.
2. A description worth shipping says what the tool does in task language, when it is the right and the wrong choice, what it needs, what changes on success and what it returns.
3. Name the nearest neighbouring tool, and put closed sets in the schema as an enum with additionalProperties set to false, because the schema can be checked by a machine and prose cannot.
4. The MCP specification treats annotations such as readOnlyHint as untrusted unless the server is trusted, so write the boundary in the description and enforce it in the server.
5. Describe return values and error codes, so an agent can tell not found from not permitted and recover rather than retry the wrong thing.
6. Keep descriptions in version control, diff them in review, keep a regression case for each selection mistake you fix, and record when they were last verified.

A tool name, its description, and its inputs are part of the experience an agent uses to decide what happens next.

When an agent has several possible actions, vague language causes a familiar product problem: the right capability is there, but it is hard to recognise. The agent can then pick the wrong tool, take unnecessary steps, or ask for information the system already has.

## Why do tool descriptions matter so much?

The description is one of the surfaces an agent can use to choose a tool. What else it can inspect depends on the harness, available documentation and prior context. Write the description so the choice does not depend on unstated history.

Several research systems treat tool documentation as part of the tool-use interface. Hsieh et al. (2023), in *Tool Documentation Enables Zero-Shot Tool-Usage with Large Language Models*, compare documentation-only prompting against few-shot demonstrations across several tasks and argue that tool documentation deserves first-class treatment in its own right. Gorilla (Patil et al., NeurIPS 2024) pairs API-document retrieval with fine-tuning specifically so models can adapt as documentation changes. Guo et al. (2026) go further and study *rewriting* tool descriptions as an optimisation target for reliable tool use in large candidate sets. Across the tool-use benchmarks, the recurring failure modes are the same short list: wrong-tool selection, malformed parameters, tool bypass, and documentation drift. Wording can contribute to these failures, alongside model behaviour, retrieval, validation and harness design. Diagnose the observed failure before choosing a fix.

## Describe the decision, not just the endpoint

A useful tool description explains what the action is for, when it is the right choice, what it needs, and what changes when it succeeds. That gives an agent more to go on than a label that only mirrors an internal API name.

Compare these two definitions of the same capability. Both are invented for illustration and describe no real product.

```json
{
  "name": "post_v2_notify",
  "description": "Calls the notification service.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "uid": { "type": "string" },
      "tpl": { "type": "string" },
      "ch": { "type": "string" }
    },
    "required": ["uid", "tpl", "ch"]
  }
}
```

```json
{
  "name": "send_customer_notification",
  "description": "Send a transactional notification to one customer about an order they placed, for example a shipping confirmation or a delivery delay. Use this only for order-related messages the customer expects. Do not use it for marketing, for internal alerts (use notify_team), or for bulk sends (use schedule_campaign). The message is delivered immediately and cannot be recalled.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "customer_id": {
        "type": "string",
        "description": "The customer's stable ID, as returned by find_customer. Not an email address."
      },
      "template": {
        "type": "string",
        "enum": ["shipping_confirmation", "delivery_delay", "order_cancelled"],
        "description": "Which transactional template to send. Each has a fixed set of required variables."
      },
      "channel": {
        "type": "string",
        "enum": ["email", "sms"],
        "description": "SMS is only available for customers who have a verified mobile number."
      }
    },
    "required": ["customer_id", "template", "channel"],
    "additionalProperties": false
  },
  "annotations": { "readOnlyHint": false, "destructiveHint": false, "openWorldHint": true }
}
```

The second version makes more of the decision explicit. It is an illustrative rewrite, not a measured improvement; test whether it reduces selection and argument errors in your own task set. It states the purpose, the exclusions, the neighbours by name, the irreversibility, the identifier format, and the constraint on SMS. `enum` and `additionalProperties: false` do work that prose alone cannot, because a machine can check them. The [JSON Schema enum reference](https://json-schema.org/understanding-json-schema/reference/enum) defines a closed set of valid values. Check the schema dialect and subset supported by your validator and tool-calling runtime.

A description worth shipping answers six questions:

1. **What does this do**, in task language?
2. **When is it the right choice?**
3. **When is it the wrong choice,** and what should be used instead?
4. **What does it need**, and where does that come from?
5. **What changes** when it succeeds?
6. **What does it return**, in a shape the agent can act on?

## Make boundaries legible

Say when a tool reads information, changes something, reaches an external system, or needs a person to approve the next step. Clear boundaries help teams design better handoffs and make it easier to spot when a workflow needs a safer route.

MCP defines annotations for this (read-only, destructive, and open-world hints), and OpenAI’s plugin and tool documentation describes similar safety metadata that guides selection. Use them, but remember what they are.

The MCP specification (2026-07-28) states that tool annotations are untrusted unless they come from a trusted server. The practical rule holds across the stack: **the model reasons over metadata; the harness enforces execution.** A tool annotated read-only still needs server-side enforcement. A destructive tool still needs confirmation and guardrails even if the model appears to understand the risk. Mislabelling a hint is worse than omitting it, because auto-approval interfaces may act on it.

So write the boundary twice. Once in the description, where it informs the agent’s choice and the approval screen a person will read: see [Human approval workflows for AI agents](/insights/approval-is-a-workflow/). Once in the server, where it is actually enforced.

![A tool definition as a stack of parts, each with its reader. The model reads the name and description: the purpose, when not to use the tool and the neighbouring tool. The runtime validates the input schema: the source of each identifier, enums and no extra fields. The client reads annotations such as read-only and destructive as hints only. A person reads the boundary on the approval screen as it was written. Set apart and highlighted, the server and harness enforce the boundary: they validate, authorise the caller and guard side effects.](https://agentexperience.tech/diagrams/tool-definition-layers.svg)

*Figure: Each part of a tool definition has a different reader, and only the server enforces the boundary.*

## Write the parameters as carefully as the description

Parameter contracts deserve their own checks. These five habits make the contract easier to inspect and validate:

- **Name the source of every identifier.** “As returned by `find_customer`” names a concrete source instead of leaving the caller to guess.
- **Use `enum` when the set is closed.** A validator enforcing the schema can reject values outside that set. A model may still propose an invalid value; the schema does not guarantee model behaviour or tool selection.
- **State units, formats, and timezones explicitly.** `amount_minor` (integer, minor units) is unambiguous; `amount` is not.
- **Say what happens when an optional field is omitted.** Defaults are invisible unless documented.
- **Set `additionalProperties: false`** and test that the server rejects undeclared fields instead of silently dropping them.

Return values deserve the same care. If the output is a status the agent must branch on, describe the possible statuses. If failure is expressed as a structured error rather than an exception, say so and enumerate the codes. An agent that cannot distinguish “not found” from “not permitted” will retry the wrong thing. That distinction separates a retry from a recovery, as covered in [Record retries as product history](/insights/retries-are-product-history/).

## Keep the catalogue intentional

More tools do not automatically create more capability. Start with the tools that matter for the workflow, remove overlap, and make the difference between neighbouring actions easy to understand.

Every tool in the catalogue costs context and adds a chance to choose wrong. Plausible-looking neighbours are a useful review target. Compare confusing pairs in your task set rather than assuming catalogue size alone predicts selection accuracy.

Three pruning heuristics:

- **If two tools need a paragraph to distinguish, merge them or rename them.** The paragraph is evidence that the boundary is in your head, not in the product.
- **Remove tools no workflow uses.** A capability kept “in case” is a permanent tax on every decision.
- **Prefer one tool with a clear enum over five near-identical tools.** An enum can make a shared input contract explicit; test whether combining those actions helps the intended tasks.

[Agent tool catalogues need a pruning strategy](/insights/agent-tool-catalogs/) covers this in depth.

## Version and test the descriptions like code

Tool text drifts. The API changes, the enum grows, the neighbouring tool is renamed, and the description quietly becomes wrong. A wrong description is more dangerous than a missing one, because the agent follows it confidently.

Public evaluation infrastructure has had to work around this: StableToolBench (ACL 2024 Findings) introduced simulated APIs and caching because real APIs drift constantly, and Wu et al. (ACL 2026 Findings) argue that static toolsets are unrealistic and that continual documentation adaptation is needed as APIs version, deprecate, and reappear.

[Use the MCP tool-description test-case fixture](/resources/mcp-tool-description-test-cases/) to review a complete public example with target intent, nearest tool, valid and schema-invalid inputs, result shape, and a changed retry path. It is a fixture for interface review, not a benchmark or a prediction of tool-use behaviour.

Four practices help:

1. **Keep descriptions in version control**, next to the implementation, and review them in the same pull request that changes behaviour.
2. **Keep a regression case for every selection mistake you have fixed.** When an agent once confused two tools, that pair becomes a permanent check. See [An agent evaluation loop turns one failure into a standing check](/insights/build-a-reliable-agent-evaluation-loop/).
3. **Diff descriptions in review.** A one-word change to a description can change which tool gets chosen, so review it like a behaviour change.
4. **Date the catalogue.** Knowing when the descriptions were last verified against the API is worth more than most metadata you could add.

## A one-question review

Before shipping a tool definition, hand it to someone who does not work on your system.

If they would need to already know it to choose correctly, the description is not finished. If they would need to ask which of two tools you meant, the catalogue is not finished. If they would choose correctly but could not tell whether the action is reversible, the boundary is not finished.

That check is also the fastest first pass in a broader review. See [Run an Agent Experience review](/insights/run-an-ax-review/).

## Frequently asked questions

**What makes a good tool description for an AI agent?**
A good tool description states what the action is for, when it is the right choice, when it is not, what it needs, and what changes when it succeeds. It uses the language of the task rather than the internal API, and it names its nearest neighbour explicitly so the agent can tell two similar tools apart.

**How long should a tool description be?**
Long enough to make the choice unambiguous and short enough to stay in context alongside every other tool. A common rule of thumb (practitioner guidance rather than a measured figure) is a few sentences for the tool plus one clear sentence per parameter. Descriptions compete for the same context window, so a bloated catalogue makes every description less useful.

**Do tool annotations like `readOnlyHint` keep an agent safe?**
No. The MCP specification (2026-07-28) states that tool annotations are untrusted unless they come from a trusted server, and OpenAI’s tool documentation describes them as hints. They can inform selection and interface design; the server and harness must still validate schemas, authorise the caller, and enforce side-effect boundaries.

**Should tool descriptions be versioned and tested?**
Yes. Treat them as code: review them in pull requests, diff them, and keep a regression case for each selection mistake you have fixed. Research on evolving tool ecosystems argues that static toolsets are unrealistic and that agents need continual documentation adaptation as APIs version and deprecate (Wu et al., ACL 2026 Findings).

A practical review starts with one question: could a capable new teammate choose this tool correctly from what is written here?
