Tools

Tool descriptions are product surfaces.

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

In short. 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, not 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.

When an agent has several possible actions, vague language creates a familiar product problem: the right capability is present, but it is hard to recognise. The result can be the wrong tool, unnecessary steps, or a request for information the system already has.

Why do tool descriptions matter so much?

Because for the agent, the description is the tool. It has no colleague to ask, no changelog to skim, and no memory of last quarter’s migration. It has the text in front of it at the moment of choice.

The research literature has converged on treating tool documentation as infrastructure rather than copywriting. 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. And across the tool-use benchmarks, the recurring failure modes are the same short list: wrong-tool selection, malformed parameters, tool bypass, and documentation drift.

Every one of those is a writing problem before it is a modelling problem.

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 a clearer route 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.

{
  "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"]
  }
}
{
  "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 costs about ninety extra words and removes most of the reasons an agent would get this wrong. It states the purpose, the exclusions, the neighbours by name, the irreversibility, the identifier format, and the constraint on SMS. Note that enum and additionalProperties: false are doing work that prose alone cannot: they are machine-checkable. JSON Schema’s 2020-12 meta-schema remains the compatibility anchor for this, and structured-output and function-calling guides across the major platforms are built on it.

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. Then 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, deliberately. Once in the description, where it informs the agent’s choice and the approval screen a person will read — see Human approval is a workflow, not a pop-up. Once in the server, where it is actually enforced.

Write the parameters as carefully as the description

Most malformed-call failures come from parameters, not from the tool sentence.

Five habits remove most of them:

  • Name the source of every identifier. “As returned by find_customer” saves an entire round trip of guessing.
  • Use enum when the set is closed. A model cannot invent a value that the schema does not permit.
  • 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 so a hallucinated field fails loudly rather than being silently dropped.

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 is what makes the difference between a retry and a recovery, as covered in Retries are product history, not a clean slate.

Keep the catalog 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 catalog costs context and adds a chance to choose wrong. Selection difficulty tracks the number of plausible-looking neighbours more than the total count — twenty clearly distinct tools are easier to choose between than six that overlap.

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. The schema can carry the distinction more reliably than five descriptions can.

An agent’s tool catalog needs a pruning strategy 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 — and a wrong description is more dangerous than a missing one, because it is confidently followed.

Public evaluation infrastructure has had to engineer around exactly 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.

Four practices that make this manageable:

  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 Build an evaluation loop that improves the product.
  3. Diff descriptions in review. A one-word change to a description can change which tool gets chosen; treat it with the seriousness of a behaviour change.
  4. Date the catalog. 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 catalog 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.

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 catalog 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 improve 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?

Read this guide as markdown