Skip to main content
Chapter 3 Mastering MCP Tools — Give AI the Power to Act

Designing Tool Schemas That AI Models Love

18 min read Lesson 9 / 40 Preview

Designing Tool Schemas That AI Models Love

The difference between an MCP server that works flawlessly and one that confuses AI models comes down to tool design. A well-designed tool schema tells the AI exactly what the tool does, what inputs it needs, and what output to expect.

The Three Pillars of Tool Design

1. Clear, Action-Oriented Names

❌ Bad:   "data"            — What data? What action?
❌ Bad:   "process-thing"   — Vague, unhelpful
✅ Good:  "search-users"    — Clear action + target
✅ Good:  "create-invoice"  — Specific, unambiguous
✅ Good:  "get-order-status" — Descriptive verb + noun

2. Descriptive Tool Descriptions

The description is what the AI reads to decide whether to use your tool. Be specific:

// ❌ Bad: Too vague
server.tool("query", "Query the database", ...);

// ✅ Good: Specific about what, when, and limitations
server.tool(
  "search-products",
  "Search the product catalog by name, category, or price range. Returns up to 20 matching products with name, price, and availability. Use this when the user asks about products, inventory, or pricing.",
  ...
);

3. Well-Annotated Input Schemas

Every parameter needs a clear description:

server.tool(
  "search-products",
  "Search the product catalog",
  {
    query: z.string()
      .describe("Search term to match against product name and description"),
    category: z.string().optional()
      .describe("Filter by category slug (e.g., 'electronics', 'clothing')"),
    min_price: z.number().min(0).optional()
      .describe("Minimum price in USD (inclusive)"),
    max_price: z.number().min(0).optional()
      .describe("Maximum price in USD (inclusive)"),
    limit: z.number().min(1).max(50).default(20)
      .describe("Maximum number of results to return (default: 20)"),
  },
  async ({ query, category, min_price, max_price, limit }) => {
    // Implementation
  }
);

Tool Output Best Practices

Structure your output so the AI can parse and reason about it:

// ❌ Bad: Unstructured blob
return { content: [{ type: "text", text: "John Smith 30 john@example.com active" }] };

// ✅ Good: Structured, labeled output
return {
  content: [{
    type: "text",
    text: [
      "## User Found",
      "",
      "| Field | Value |",
      "|-------|-------|",
      `| Name | ${user.name} |`,
      `| Age | ${user.age} |`,
      `| Email | ${user.email} |`,
      `| Status | ${user.status} |`,
    ].join("\n"),
  }],
};

Annotation Metadata

MCP supports tool annotations that help clients display UI hints:

server.tool(
  "delete-user",
  "Permanently delete a user account and all associated data",
  { userId: z.string().uuid() },
  async ({ userId }) => { /* ... */ },
  {
    annotations: {
      title: "Delete User Account",
      readOnlyHint: false,
      destructiveHint: true,    // Warns the user this is destructive
      idempotentHint: true,     // Safe to retry
      openWorldHint: false,     // Does not access external services
    },
  }
);

The "Golden Rule" of Tool Design

Design your tools as if the AI model is a smart junior developer who has never seen your codebase. It can follow instructions perfectly, but it needs clear, explicit guidance about:

  • What the tool does
  • What each parameter means
  • What values are valid
  • What the output format looks like
  • When to use this tool vs. another

Key Takeaway

Great tool design is the difference between AI that fumbles and AI that flows. Use action-oriented names, write descriptions the AI can reason about, annotate every parameter, and structure output for easy parsing. The 5 minutes you spend on schema design saves hours of debugging later.