Skip to main content
All posts

Why LLMs Silently Skip Your MCP Tools (And How to Fix It)

March 24, 2026 · 8 min read

You built an MCP server. You defined your tools. Claude connects, discovers them... and then never calls them. No error. No warning. It just ignores them.

This happens more often than you'd think. The Model Context Protocol spec is loose enough that technically valid tool definitions can be practically useless to an LLM. Here's what goes wrong and how to fix it.

1. Vague descriptions

Bad

{
  "name": "get_data",
  "description": "Gets data"
}

An LLM picks tools based on descriptions. "Gets data" tells it nothing. Which data? From where? When should it use this instead of another tool?

Good

{
  "name": "get_customer_orders",
  "description": "Retrieve all orders for a customer by
    their customer ID. Returns order date, total,
    status, and line items. Use when the user asks
    about purchase history or order status."
}

The description should tell the LLM: what it does, what it returns, and whento use it. 10–300 characters. Be specific.

2. Missing parameter descriptions

Bad

"properties": {
  "id": { "type": "string" },
  "fmt": { "type": "string" }
}

The LLM has to guess what id means and what values fmt accepts. It will guess wrong.

Good

"properties": {
  "customer_id": {
    "type": "string",
    "description": "Unique customer identifier,
      e.g. 'cust_abc123'"
  },
  "format": {
    "type": "string",
    "enum": ["summary", "detailed"],
    "description": "Response detail level.
      'summary' = totals only,
      'detailed' = line items."
  }
},
"required": ["customer_id"]

Every parameter needs a description. Enums help the LLM pick valid values. requiredtells it what's mandatory.

3. No annotations

Annotations are MCP behavior hints that tell the LLM what side effects a tool has:

"annotations": {
  "readOnlyHint": true,
  "destructiveHint": false,
  "idempotentHint": true,
  "openWorldHint": false
}

Without these, the LLM doesn't know if calling your tool will delete data, modify state, or is safe to retry. Claude and other MCP clients use these hints to decide whether to auto-approve tool calls or ask the user first.

Critical: If your tool is named delete_*, remove_*, or destroy_* and you haven't set destructiveHint: true, you're asking for trouble.

4. No output schema

Most MCP servers omit outputSchema. This means the LLM doesn't know what your tool returns until it calls it. For chained tool calls (where output from tool A feeds into tool B), this is a problem.

"outputSchema": {
  "type": "object",
  "description": "Customer orders with totals",
  "properties": {
    "orders": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "order_id": { "type": "string" },
          "total": { "type": "number" },
          "status": {
            "type": "string",
            "enum": ["pending", "shipped",
                     "delivered"]
          }
        }
      }
    }
  }
}

5. Duplicate or cryptic names

Tool names should be unique and descriptive. handler1, process, do_thingtell the LLM nothing. The name is the first signal the LLM uses to match your tool to a user's request.

Use the pattern: verb_noun get_orders, create_invoice, search_products, delete_user.

How to check your tools

You can validate your tools/list response against these rules (and more) with the MCP Server Validator. Paste your JSON or point it at a URL — it runs 9 checks and gives you a score.

For CI/CD, there's a GitHub Actions workflow that fails the build if your tool definitions don't pass.

The checklist

Before shipping your MCP server:

  • Every tool has a descriptive name (verb_noun)
  • Every tool has a description (10–300 chars, explains what/when/why)
  • Every parameter has a description
  • required array is set on inputSchema
  • Enums used for constrained values
  • Annotations set (especially destructiveHint for write/delete operations)
  • Output schemas defined for tools used in chains
  • No duplicate tool names
  • Tested with at least one LLM client (Claude, Cursor, etc.)

Validate your MCP tools now

The MCP spec is permissive — it won't reject bad definitions. But LLMs are picky. The difference between a tool that works and one that gets silently skipped is usually a better description and a few annotations.