MCP Tool Schema Design: Writing Descriptions AI Agents Actually Understand
How to write MCP tool names, descriptions, and input schemas that AI agents interpret correctly — with before/after examples, a checklist, and the 2025 annotation spec.
Mohammed Kafeel
Machine Learning Researcher
On this page
- Why Your Tool Descriptions Are Failing Your AI Agent
- How AI Agents Actually Read Tool Schemas
- The Anatomy of a Well-Designed MCP Tool Schema
- Good vs Bad: Side-by-Side Examples
- 7 Rules for Writing Descriptions AI Agents Actually Understand
- Semantic Annotations: The 2025 Spec Addition You're Probably Skipping
- Context Window Awareness and Tool Decomposition
- Quick Reference Checklist
- Key Takeaways
- FAQ
- Useful Resources
Your MCP tool descriptions are the only instructions an AI agent gets when deciding which tool to call and how to use it. Vague descriptions cause wrong tool selections, malformed inputs, and ballooning token costs.
This guide shows you exactly how to write tool schemas that AI agents interpret correctly - with real before/after examples, a quick-reference checklist, and the 2025 annotation spec most developers are still skipping.
In a Nutshell (TL;DR)
Your tool description is the agent's only instruction manual - everything implicit to you must be explicit in the schema.
Put constraints in the schema (
pattern,enum,minLength), not in prose. Schema keywords enforce; text only suggests.Name tools with verb + object and namespace related tools - it's the fastest win for correct tool selection.
Use the 2025 annotations (
readOnlyHint,destructiveHint,idempotentHint,openWorldHint) - most servers skip them entirely.
Why Your Tool Descriptions Are Failing Your AI Agent
One developer's MCP integration with Yahoo Finance had a description that read: "Either use period parameter or use start and end."
That single ambiguous line caused the AI agent to generate unnecessarily broad date ranges on every query - and token costs jumped 67% before anyone noticed.
Another developer building an MCP client from scratch spent $30 on Claude API calls and $10 on OpenAI during development, largely because poorly scoped tool definitions made the agent call tools repeatedly, fill context windows, and retry failed invocations.
These aren't edge cases. They're what happens when you treat tool descriptions as an afterthought.
The fix isn't complicated - but it requires understanding how an AI agent actually reads your schema.
How AI Agents Actually Read Tool Schemas
An AI agent has no intuition. It only has what you write.
When an agent connects to your MCP server, it goes through a predictable workflow:
Discovery - The agent queries your server for a list of available tools and reads every name, description, and parameter definition.
Selection - Based on the user's request and your descriptions, the agent picks the tool it thinks is most relevant.
Invocation - It constructs a JSON payload matching your input schema and calls the tool.
Execution - Your server runs the tool and returns a result.
Response - The agent uses that result to answer the user.
The critical step is Selection. The agent is essentially doing semantic matching between the user's intent and your tool description. If your description is vague, ambiguous, or missing key context, the agent either picks the wrong tool, constructs a malformed request, or - worst of all - confidently does the wrong thing.
What makes this hard: Everything that's obvious to a human developer (implicit domain knowledge, naming conventions, business context) is completely invisible to the agent unless you write it down explicitly.
If you're still getting your bearings on the protocol itself, start with what MCP is and why agents need it, then come back here for the schema details.
The Anatomy of a Well-Designed MCP Tool Schema
A complete MCP tool schema has four components, and all four matter.
| Component | What It Does | Common Mistake |
|---|---|---|
name |
Unique identifier the agent uses to call the tool | Vague names like get_data or process |
description |
Explains what the tool does, when to use it, and what it returns | Too short, too generic, or missing "when to use" context |
inputSchema |
JSON Schema defining parameters, types, and constraints | Using text descriptions instead of schema keywords |
annotations |
Semantic hints about tool behavior (read-only, destructive, etc.) | Almost always missing entirely |
Tools are only one of MCP's primitives. If you're unsure whether an action even belongs in a tool, see MCP tools vs resources vs prompts - reads should usually be resources, not tools.
Good vs Bad: Side-by-Side Examples
Example 1: Flight Search (Bad)
{
"name": "searchFlights",
"description": "Search for flights. Origin and destination must be cities. Date must be in the future.",
"inputSchema": {
"type": "object",
"properties": {
"origin": {
"type": "string",
"description": "Departure city. Must be a real city name."
},
"destination": {
"type": "string",
"description": "Arrival city. Must be different from origin."
},
"date": {
"type": "string",
"description": "Travel date. Must be in YYYY-MM-DD format and after today."
}
},
"required": ["origin", "destination", "date"]
}
}
What's wrong here:
Constraints like "must be a real city name" and "after today" are written in plain text - the agent can read them, but can't enforce them. The schema can.
No format constraint on
date(nopatternorformatkeyword), so the agent might pass"tomorrow"or"next Friday"and your server breaks.No
additionalProperties: false, so the agent might pass extra fields that cause unexpected behavior.The description doesn't say what the tool returns.
Example 2: Slack Channel Creation (Good)
{
"name": "create_channel",
"description": "Creates a new channel in a Slack workspace. Use this when a user wants to set up a new communication channel for a team or project. Returns the created channel object including its ID, name, and creation timestamp.",
"inputSchema": {
"type": "object",
"properties": {
"team_id": {
"type": "string",
"minLength": 1,
"description": "The Slack workspace ID (e.g., 'T01234ABCD'). Find this in your Slack admin settings."
},
"channel_name": {
"type": "string",
"pattern": "^[a-z0-9-]+$",
"maxLength": 80,
"description": "Lowercase letters, numbers, and hyphens only. No spaces or special characters."
},
"is_private": {
"type": "boolean",
"description": "Set to true for private channels visible only to invited members. Defaults to false (public)."
}
},
"required": ["team_id", "channel_name"],
"additionalProperties": false
}
}
What's right here:
The description tells the agent what it does, when to use it, and what it returns - all in three sentences.
patternenforces the channel name format at the schema level, not in prose.maxLengthis a hard constraint, not a suggestion.additionalProperties: falseprevents the agent from hallucinating extra fields.The example value
'T01234ABCD'inteam_idgives the agent a concrete reference point.
The Yahoo Finance Fix
Here's the real-world example from earlier, simplified:
| Version | Description |
|---|---|
| ❌ Bad | "Either use period parameter or use start and end" |
| ✅ Good | start_date (string, format: yyyy-mm-dd) and end_date (string, format: yyyy-mm-dd) as explicit, separate parameters with clear descriptions |
The ambiguous "either/or" phrasing left the agent guessing. The explicit parameter split removed all ambiguity - and cut token costs by 67%.
7 Rules for Writing Descriptions AI Agents Actually Understand
Rule 1: Name Tools with Verb + Object
Use a clear action verb paired with a specific object. This is the fastest way to help an agent select the right tool.
✅
create_meeting,search_user_by_id,delete_invoice❌
schedule,get_data,process,manage
If you haven't stood up a server yet, our tutorial on building your MCP server shows where these names live in the code.
When you have multiple tools in the same domain, use namespacing:
hr_get_users,hr_create_user,hr_deactivate_usercalendar_add_event,calendar_list_events,calendar_delete_event
This grouping helps the agent categorize tools quickly, especially when your server exposes 20+ tools.
Rule 2: Write Descriptions in Three Parts
Every tool description should answer three questions in order:
What does it do? (one sentence, action-first)
When should the agent use it? (context that prevents wrong selection)
What does it return? (so the agent knows what to do with the result)
"Retrieves the 30-day sales report for a specified region. Use this when a user asks for sales performance, revenue summaries, or regional breakdowns. Returns a JSON object with total_revenue, units_sold, and top_products array."
That's 40 words. It's enough. Don't pad it.
Rule 3: Put Constraints in the Schema, Not in Prose
If a constraint can be expressed as a JSON Schema keyword, use it. Don't describe it in the description field.
| Constraint | Wrong (prose) | Right (schema keyword) |
|---|---|---|
| Format | "Must be YYYY-MM-DD" |
"format": "date" or "pattern": "^\\d{4}-\\d{2}-\\d{2}$" |
| Length | "Max 80 characters" |
"maxLength": 80 |
| Range | "Between 1 and 100" |
"minimum": 1, "maximum": 100 |
| Allowed values | "Either 'asc' or 'desc'" |
"enum": ["asc", "desc"] |
| Required | "This field is required" |
Add to "required" array |
The agent can read prose constraints - but it might not follow them. Schema keywords are enforced at validation time. Use both when it helps clarity, but never rely on prose alone.
Rule 4: Always Include an Example Value
Add a concrete example to any parameter where the format isn't obvious. One example is worth ten sentences of description.
"region_code": {
"type": "string",
"enum": ["US-WEST", "US-EAST", "EU-CENTRAL", "APAC"],
"description": "The sales region to query (e.g., 'US-WEST')."
}
For IDs, timestamps, and codes especially - the agent will generate a plausible-looking but wrong value if you don't show it what "right" looks like.
Rule 5: Always Define What the Tool Returns
Most developers describe inputs carefully and completely ignore outputs. This is a mistake.
The agent needs to know what it's getting back so it can:
Decide whether to call another tool with the result
Extract the right field to answer the user's question
Know whether the tool succeeded or failed
Add a one-sentence return description to every tool:
"Returns the created user object with fields: id, email, created_at, and role." "Returns a boolean: true if deletion succeeded, false if the record was not found."
Rule 6: Keep Tools Focused - One Job Per Tool
Avoid "mega-tools" that do multiple things based on a parameter flag. They confuse agents and make schemas harder to maintain.
If you have a tool like manage_user that creates, updates, or deletes based on an action parameter - split it:
create_userupdate_userdelete_user
Each tool gets a clear, unambiguous description. The agent picks the right one without needing to reason about an action enum. Developers who've built MCP clients consistently report this as one of the most impactful structural changes you can make.
Rule 7: Use additionalProperties: false
Always close your schema. Adding "additionalProperties": false to your input schema prevents the agent from hallucinating extra fields that your server doesn't expect - and that can cause silent failures or unexpected behavior.
"inputSchema": {
"type": "object",
"properties": { ... },
"required": ["field1", "field2"],
"additionalProperties": false
}
It's one line. Add it to every tool.
Semantic Annotations: The 2025 Spec Addition You're Probably Skipping
The March 2025 MCP spec update added four semantic annotations - and most production servers don't use any of them.
Annotations are hints that tell the agent (and the MCP client) about the nature of a tool's operation. They don't enforce behavior, but they help agents make safer decisions about when and how to call tools.
| Annotation | Value | What It Signals |
|---|---|---|
readOnlyHint |
true |
Tool only reads data, never modifies it |
destructiveHint |
true |
Tool may delete or permanently alter data |
idempotentHint |
true |
Safe to call multiple times with the same input |
openWorldHint |
true |
Tool interacts with external systems (APIs, web) |
Why this matters: An agent that knows a tool is destructive can ask for confirmation before calling it. An agent that knows a tool is idempotent can safely retry on failure. Without these hints, the agent has no way to distinguish a read from a delete.
{
"name": "delete_invoice",
"description": "Permanently deletes an invoice by ID. This action cannot be undone.",
"annotations": {
"destructiveHint": true,
"idempotentHint": false,
"readOnlyHint": false
}
}
Important: Annotations are hints, not guarantees. Your server must still enforce its own security and validation - don't rely on a client respecting
destructiveHintas a safety mechanism. (A malicious server can weaponize the description field itself - see MCP tool poisoning via schema.)
Context Window Awareness and Tool Decomposition
Every tool definition you expose costs tokens - before the agent does anything.
This is a real operational concern. The GitHub MCP server, for example, exposes so many tools that its definitions alone can consume a significant portion of a model's context window. One developer building a multi-server MCP client found that tool definitions, combined with conversation history and responses, made token usage completely unpredictable.
Practical steps to manage this:
Keep descriptions concise. Every word in a tool description is a token. Say what needs to be said, nothing more.
Expose only the tools the agent needs for the current task. If your server has 50 tools but the agent only needs 5 for a given workflow, consider dynamic tool registration or scoped server configurations.
Decompose mega-tools. Smaller, focused tools have smaller schemas. They're also easier for the agent to reason about, which means fewer retry loops - and lower costs.
Test with your actual model. Some models handle complex tool schemas significantly better than smaller, faster tiers. If you're hitting tool selection errors, the model tier matters as much as the schema quality. (Before that, sanity-check the schemas themselves - our guide to testing your tool schemas covers MCP Inspector.)
Quick Reference Checklist
Use this before shipping any MCP tool:
Naming
Tool name uses verb + object pattern (
create_invoice, notinvoice)Related tools share a namespace prefix (
billing_,hr_,calendar_)No generic names:
get_data,process,manage,handle
Description
Answers: what it does, when to use it, what it returns
Written in plain language, no jargon without explanation
Under ~100 words (concise but complete)
Input Schema
Every parameter has a
typeRequired parameters are listed in the
requiredarrayConstraints use schema keywords (
pattern,enum,minLength,maximum) not proseExample values included for IDs, codes, and formatted strings
additionalProperties: falseis setOptional parameters have sensible defaults documented
Annotations (2025 spec)
readOnlyHintset for read-only toolsdestructiveHintset for tools that delete or modify dataidempotentHintset where applicableopenWorldHintset for tools calling external APIs
Output
Description includes what the tool returns (fields, type, structure)
Error conditions are documented
Key Takeaways
Your tool description is the agent's only instruction manual. Everything implicit to you must be explicit in the schema.
Put constraints in the schema, not in prose.
pattern,enum,minLengthenforce; text descriptions suggest.Name tools with verb + object, use namespacing. It's the fastest win for correct tool selection.
Always describe what the tool returns. Agents need to know what they're getting back.
One tool, one job. Mega-tools confuse agents and bloat schemas.
Use the 2025 annotations.
readOnlyHint,destructiveHint,idempotentHint,openWorldHint- most servers skip these entirely.Every tool definition costs tokens. Keep descriptions tight and expose only what the agent needs.
FAQ
What is MCP tool schema design?
MCP tool schema design is the practice of writing the name, description, and inputSchema fields for tools exposed by an MCP (Model Context Protocol) server. These fields are the only information an AI agent has when deciding which tool to call and how to construct its input - so their quality directly determines whether the agent behaves correctly.
Why do AI agents pick the wrong tool?
Usually because the tool description is too vague or two tools have overlapping descriptions. The agent does semantic matching between the user's request and your descriptions. If get_report and fetch_data have similar descriptions, the agent will guess - and guess wrong roughly half the time. Specific, distinct descriptions eliminate this ambiguity.
Should I put constraints in the description or the JSON Schema?
Both, ideally - but always in the JSON Schema first. Schema keywords like pattern, enum, and maxLength are enforced at validation time. A constraint written only in prose is a suggestion the agent may or may not follow. Use prose to explain why a constraint exists; use schema keywords to enforce it.
How long should a tool description be?
Long enough to answer three questions: what it does, when to use it, and what it returns. In practice, that's usually 2-4 sentences or 40-80 words. Longer descriptions waste context window tokens and dilute the signal. Shorter descriptions leave the agent guessing.
What are MCP tool annotations and do I need them?
Annotations are semantic hints added to the March 2025 MCP spec: readOnlyHint, destructiveHint, idempotentHint, and openWorldHint. They tell the agent and client about the nature of a tool's operation - whether it's safe to retry, whether it modifies data, whether it calls external systems. They're not enforced by the spec, but they help agents make safer decisions. You should use them, especially destructiveHint for any tool that deletes or permanently modifies data.
Does tool schema quality affect API costs?
Yes, significantly. Every tool definition is loaded into the context window before the agent does anything. Verbose schemas, mega-tools with large parameter sets, and vague descriptions that cause retry loops all increase token usage. One developer reported spending $30 on Claude API calls during MCP development largely due to poor tool definitions causing repeated invocations and context overflow.
Useful Resources
- MCP Official Documentation - Tools Concept - Anthropic's canonical guide to MCP tool design
- MCP Specification (2025-06-18) - Server Tools - Full spec including the 2025 annotation additions
- JSON Schema Specification - Reference for all schema keywords (
pattern,enum,minLength, etc.) - MCP GitHub Repository - Source, issues, and community discussions
- Anthropic - Introducing the Model Context Protocol - Original context on why MCP was built
At Ginger Labs, we design MCP servers for production AI agents, and well-written tool schemas are consistently the highest-leverage change teams make - whether you start with the schema constraints, the annotations, or the tool decomposition.
Keep reading
The Three-Layer AI Agent Stack: MCP, A2A, and Streamable HTTP Explained
MCP, A2A, and Streamable HTTP are the three protocols that form the modern AI agent stack. Here's exactly how they fit together — and why it matters for every developer building with AI.
Best MCP Servers in 2026: GitHub, Notion, Google Drive, and More
There are over 9,600 MCP servers out there — but only a handful are worth your time. Here's a curated breakdown of the best MCP servers in 2026, with setup tips and real use cases.
Connecting Claude Code to Internal Tools with MCP: A Developer's Guide
A hands-on guide to connecting Claude Code to your internal tools via MCP — setup, real-world use cases, security best practices, and troubleshooting for developers.



