Skip to content
Tool design guide

How to write MCP tool descriptions agents can use

An agent chooses and calls your tool from a name, a few sentences, and a schema. Write them for a reader that cannot ask a follow-up, then let agents tell you where they still guessed.

For
Developers building MCP servers and tool catalogs for LLM agents
Question
Write MCP tool descriptions, schemas, and annotations agents use correctly
Start with
Take the tool agents retry most, rewrite its description and error text, and compare schema_feedback before and after.
Updated
defined termsread before the method
Tool description
The name, description, and schema field text a client passes to the model before a call.Not your docs site, which the agent may never open.
Annotations
MCP behavior hints: readOnlyHint, destructiveHint, idempotentHint, and openWorldHint.Hints, not guarantees. The spec says to treat them as untrusted unless the server is trusted.
Actionable error
A result with isError set that names what was wrong and what is accepted.Not a stack trace or a bare status code.

Each term is paired with the thing it is not. Most agent research arguments are really vocabulary arguments.

01 / 07Principles

Three things to hold on to

01Selection

The name and first sentence decide the call

Some clients load descriptions only on search or selection. Name the tool by its job and put the job first.

02Contract

Say what goes in, what comes out, and what changes

Formats with examples, side effects in plain words, and annotations that match the handler.

03Evidence

Let the agent point at the confusing line

schema_feedback and docs_feedback reports name the tool and the field that forced a guess.

02 / 07Method

The argument, in order

Selection and inputs

Name the job, draw the boundary, show the format

An agent cannot ask what a field means, so every gap becomes a guess or a retry. Name tools with a verb and the object an agent looks for, not an internal name or a generic verb like run. The MCP spec recommends tool names use only letters, digits, underscores, hyphens, and dots. Open with the job, then say when a neighboring tool fits better.

Give every field a format, default, and example, and use enums for closed sets. The illustrative tool below, rewritten:

  • search_orders: Find orders by date range and status. Use get_order when you already have an order ID.
  • since: ISO 8601 date, inclusive, for example 2026-09-15. Defaults to 30 days ago.
  • status: one of pending, paid, refunded. Omit to include all.
  • annotations: readOnlyHint true
Side effects

Declare side effects in words and in annotations

Say plainly whether a tool reads, creates, updates, or deletes, then set the matching annotations. readOnlyHint defaults to false and destructiveHint to true, so an unannotated tool looks like a destructive write to any client that checks.

An observed, public case: in Browser Use issue #5239, 16 tools shipped without annotations, and Codex CLI 0.142.5, in a non-interactive run with approval_policy=never, cancelled a call to the read-only browser_get_state. PR #5246 added readOnlyHint to the five read-only tools, left one that can write artifacts unannotated, and was merged on August 3, 2026. Mark only what is true.

Errors and references

Return errors an agent can act on, and name only real tools

Return input problems as a tool result with isError true, not a protocol error, so the model can read it and retry. Name the field, what arrived, and what is accepted. "since must be an ISO 8601 date such as 2026-09-15, received 15/09/2026" is a next call. "Invalid input" is another guess.

Every tool named in a description, instruction, or result must exist in tools/list, spelled exactly. The public GitMCP report observed every search response recommending fetch_url_content, while the registered tool is fetch_generic_url_content. The agents in that study bridged the gap. A literal client would not.

Evidence

Let agents show you which line made them guess

You cannot read your own description like a first-time agent, but the agent can tell you. With submit_agent_feedback in the catalog, an agent that had to guess can file schema_feedback or docs_feedback naming the tool, what confused it, and what would have helped.

Group those reports by tool. When several point at the same field, that line is the rewrite. They are stated evidence, so check each claim against the schema first.

03 / 07One tool, two readers

Two records of the same workNeither one is wrong. They answer different questions.

split viewsame tool

What the author shipped, and what an agent reported about it

tools/listas shipped
name         search
description  "Search orders."
since        string
status       string
annotations  (none)

Accurate to its author. Every field is a guess for its user.

stated · the agent said it
report_207via submit_agent_feedback

I needed last week’s paid orders. since accepted 2026-09-15 and returned an empty list, so I could not tell if there were none or my format was wrong. An example for since and the status values would have made it one call.

lane=schema_feedback · outcome=partial_success · satisfaction=2/5

Illustrative, not customer evidence. The description is incomplete, not wrong, and only its reader could say where.

04 / 07Boundary

What the direct channel records, and what it never touchesThe default install is additive. It adds two tools and changes nothing else.

Records

The research submission

  • schema_feedback and docs_feedback reports the agent chooses to file
  • The tool name, and what the agent says was confusing or missing
  • The change the agent says would have helped
  • An optional failure type such as bad_tool_description
Leaves alone

Everything else

  • Your tool names, descriptions, schemas, and annotations
  • Arguments and results of your existing tools
  • Any automatic rewrite of your descriptions
  • A claim that one report speaks for every client
05 / 07Install

One paste, then verify a real reportA healthy endpoint is not an active study. The inbox record is the proof.

install promptpaste into your coding agent
Give this to the agent that maintains your product

Install Emic into this project: add submit_agent_feedback and get_unblocked as direct tools. Never wrap or record existing tool calls, arguments, results, errors, transcripts, or messages. Additive only, plain HTTP, zero dependencies. Full instructions: https://emic.sh/llms-full.txt

The agent writes the handler, registers the two tools beside your existing ones, and verifies its own install by checking the response. Nothing is placed in front of the tools you already ship.

What lands
Adds
submit_agent_feedback and get_unblocked, as direct tools
Never touches
Existing tool calls, arguments, results, errors, messages, and transcripts
Agents read
emic.sh/llms-full.txt
Start with
Take the tool agents retry most, rewrite its description and error text, and compare schema_feedback before and after.
06 / 07Questions

Questions teams ask before starting

How long should an MCP tool description be?

Long enough for the job, the boundary with neighboring tools, input formats, and side effects. Put the job first and move background to your docs.

How do I find out which descriptions confuse agents?

Ask them. With a feedback tool in the catalog, agents can file schema_feedback naming the tool and the field. Filing needs the tool and a filing norm to be visible, so verify one real report first.

Do MCP annotations change what clients do?

Some clients use them to decide what runs without approval, so an unannotated read-only tool can be blocked.

07 / 07Continue
Find the confusing line

Ask the agents which description made them guess

Add the feedback tool beside your MCP tools, read schema_feedback by tool, and rewrite the line agents point at.

Free covers 2,000 feedback events a month, no card. Prefer help? The assisted 14-day pilot is free too. Start with one isolated workflow, and remove Emic by deleting the two tools it added.

  • One paste to install
  • 0ms on your hot path
  • Free tier, no card
  • Two added tools to remove