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.

MK

Mohammed Kafeel

Machine Learning Researcher

June 24, 202611 min read
On this page

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:

  1. Discovery - The agent queries your server for a list of available tools and reads every name, description, and parameter definition.

  2. Selection - Based on the user's request and your descriptions, the agent picks the tool it thinks is most relevant.

  3. Invocation - It constructs a JSON payload matching your input schema and calls the tool.

  4. Execution - Your server runs the tool and returns a result.

  5. 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 (no pattern or format keyword), 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.

  • pattern enforces the channel name format at the schema level, not in prose.

  • maxLength is a hard constraint, not a suggestion.

  • additionalProperties: false prevents the agent from hallucinating extra fields.

  • The example value 'T01234ABCD' in team_id gives 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_user

  • calendar_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:

  1. What does it do? (one sentence, action-first)

  2. When should the agent use it? (context that prevents wrong selection)

  3. 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_user

  • update_user

  • delete_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 destructiveHint as 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, not invoice)

  • 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 type

  • Required parameters are listed in the required array

  • Constraints use schema keywords (pattern, enum, minLength, maximum) not prose

  • Example values included for IDs, codes, and formatted strings

  • additionalProperties: false is set

  • Optional parameters have sensible defaults documented

Annotations (2025 spec)

  • readOnlyHint set for read-only tools

  • destructiveHint set for tools that delete or modify data

  • idempotentHint set where applicable

  • openWorldHint set 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, minLength enforce; 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


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.