MCP Tool Descriptions: Best Practices, Measured on 288 Real Tools
How to write an MCP tool description, with what 288 tools from 14 public servers actually shipped on 13 August 2026: lengths, real examples, and the patterns that tell a model which tool to pick.
A tool's description is the text a model reads when it decides which of your tools to call. The inputSchema tells it how to call a tool; the description tells it whether to. Get the schema wrong and the call fails. Get the description wrong and the call never happens, or the wrong tool gets called, and nothing errors.
This page sets out what to put in one, and checks each point against what real servers ship. Every figure below comes from the tools/list responses of 14 public MCP servers, read on 13 August 2026: 288 tools, all stored as returned.
TL;DR:
- Every one of the 288 tools carried a description. Leaving it out is not the common mistake; writing one that does not help a model choose is.
- Lengths ran from 14 to 8,079 characters. The median was 220. Outside the one game server that supplied 213 of the tools, the median was 199.
- The useful descriptions say when to use the tool relative to its siblings, and the best real examples do it in one sentence: "Use after web_search_exa when highlights are insufficient".
titleis not a second description. It appeared on 29 of the 288 tools (10.1%) and is meant for a display name.
What the spec says a description is for
The spec defines description as a "Human-readable description of functionality", and title as an "Optional human-readable name of the tool for display purposes" [1]. In practice the reader that matters is the model: a client hands the tool list to the model, and the model picks a tool from the names and descriptions in front of it.
That has a cost side. Every description is sent along with every other tool on the server, so a long one is paid for on each request that includes your server, not only when the tool is used.
What 288 real descriptions looked like
| Server | Tools | Median description length (characters) |
|---|---|---|
game.spacemolt.com |
213 | 230 |
crashstory-mcp-production.up.railway.app |
18 | 199 |
mcp.roundtable.now |
13 | 175 |
aws-mcp.us-east-1.api.aws |
9 | 662 |
chainflip-broker.io |
6 | 149 |
knowledge-mcp.global.api.aws |
5 | 662 |
gitmcp.io/docs |
5 | 162 |
huggingface.co |
4 | 366 |
mcp.deepwiki.com |
3 | 59 |
docs.x.com |
3 | 573 |
learn.microsoft.com |
3 | 894 |
mcp.exa.ai |
2 | 566 |
mcp.context7.com |
2 | 2,006 |
docs.mcp.cloudflare.com |
2 | 535 |
Read across the whole set, 17 descriptions were under 40 characters and 30 were over 1,000. The shortest was dock on the game server, at 14 characters: "Dock at a base". The longest, on the same server, ran to 8,079 characters for a single tool. Outside that server, 2 of 75 descriptions were under 40 characters and 10 were over 1,000.
The search and documentation servers (Microsoft Learn, Context7, Exa, X, Cloudflare) wrote the longest descriptions, and they are also the ones whose tools come in pairs a model could confuse: a search tool and a fetch tool over the same content.
Best practices, with real examples
1. Say what the tool does in the first sentence
The first sentence carries the decision. Microsoft Learn's microsoft_docs_search opens: "Search official Microsoft/Azure documentation to find the most relevant and trustworthy content for a user's query." A model knows the tool's job before it reaches the details.
2. Say when to use it instead of its siblings
This is the part most descriptions leave out, and it is the part that decides between two plausible tools. The clearest example we read is Exa's web_fetch_exa:
Read a webpage's full content as clean markdown. Use after web_search_exa when highlights are insufficient or to read any URL.
Microsoft Learn does the same from the other side: microsoft_docs_fetch says "Use this tool AFTER microsoft_docs_search when you identify specific high-value pages that need complete content."
Compare DeepWiki's read_wiki_contents, at 45 characters: "View documentation about a GitHub repository." It is accurate, and on its own it does not say how it differs from its sibling read_wiki_structure ("Get a list of documentation topics for a GitHub repository."). The difference is there in the names; the descriptions leave the model to infer it.
3. State an order the model must follow, as an instruction
If one tool needs the output of another, say so plainly. Context7's query-docs does: "You must call 'Resolve Context7 Library ID' tool first to obtain the exact Context7-compatible library ID required to use this tool". Its partner resolve-library-id repeats the rule from its own side and adds a call budget: "Do not call this tool more than 3 times per question."
4. Say what comes back
A model plans its next step around the result. Microsoft Learn's search tool says it "returns up to 10 high-quality content chunks (each max 500 tokens)", and Exa ends with "Returns: Clean text content and metadata from the page(s)." Neither needs an outputSchema to set that expectation.
5. Keep it to hundreds of characters, not tens or thousands
A one-line description saves tokens and costs choices: "Dock at a base" is enough for a game where the verb is the whole story, and too little for a tool with a sibling. A manual-length one does the opposite: the 2,006-character resolve-library-id includes a response format and a selection process, all of which is sent with every request. The examples quoted on this page that do this well run from 270 to 1,065 characters. Put the parameter details in the schema's own description fields, where they describe the one argument they belong to.
6. Keep title short and leave the explaining to description
title is a display name: Microsoft's microsoft_docs_search carries "Microsoft Docs Search", Chainflip's start_dca_swap carries "Start DCA Swap". One tool in our sample used it as a second description instead, with a 165-character sentence where a name belongs. Only 29 of 288 tools set a title at all, so a client cannot rely on it, which is one more reason the name should read well on its own.
Example: a description before and after
An illustrative tool, not one from our sample, for an invoicing server with a list_invoices sibling:
Before:
{"name": "get_invoice", "description": "Gets an invoice."}
After:
{
"name": "get_invoice",
"description": "Fetch one invoice by its id, with line items and payment status. Use after list_invoices when you need the full detail of a specific invoice; use list_invoices to search by customer or date. Returns the invoice as JSON, or an error if the id does not exist."
}
The second one answers the three questions a model has: what it does, when to choose it over list_invoices, and what it will get back. It is 257 characters.
Check what your own server sends
Your descriptions are part of the tools/list response, alongside every other field a tool can carry; the tools/list guide covers each one and how often real servers fill it. To see what your own server returns, paste its URL into the MCP connection test: it calls tools/list and shows every tool name and whether the tools carry descriptions.
Sources
[1] Model Context Protocol specification, revision 2026-07-28, Server: Tools. https://modelcontextprotocol.io/specification/2026-07-28/server/tools