Curriculum › Tool Design & MCP Integration · 18% of the exam

Tool schema design principles

What you'll be able to do

  • Write tool names and descriptions for the selection moment, not the implementation
  • Keep parameter schemas tight enough that invalid calls are structurally impossible
  • Recognize when two tools overlap and should be merged or clearly partitioned
  • Design for a model choosing among many tools, not calling the one tool you tested
  • Treat a tool description as documentation aimed at the model, not the maintainer

What you’ll be able to do

  • Write tool names and descriptions for the selection moment, not the implementation
  • Keep parameter schemas tight enough that invalid calls are structurally impossible
  • Recognize when two tools overlap and should be merged or clearly partitioned
  • Design for a model choosing among many tools, not calling the one tool you tested

What you need to know

A tool description is read at the wrong time to explain itself

By the time a tool's description matters, the model has already committed to reading it as a decision aid: does this tool do what I need, right now, given this request? A description that explains internals — "queries the v2 inventory microservice" — answers a question nobody asked at that moment. A description that explains effect and scope — "look up current stock for a single SKU by exact ID" — answers the actual question.

This distinction gets harder, not easier, as an application grows. A single well-described tool is forgiving; ten tools with vague, overlapping descriptions turn every call into a coin flip the architect can't debug from the outside, because the failure isn't in the tool's code — it's in which tool got picked.

Tight schemas remove a whole failure class

A parameter schema is not documentation. It's an enforcement boundary. Every value the schema doesn't rule out is a value your handler has to defend against at runtime — and defending at runtime means the failure surfaces as a confusing tool error instead of never happening.

before — schema accepts anything, handler defends
{ "status": { "type": "string" } } # handler must now check: is "shiped" a typo? # is "STATUS_UNKNOWN" valid? is "" valid?
after — schema rules out the invalid states
{ "status": { "type": "string", "enum": ["pending", "shipped", "delivered", "cancelled"] } } # an invalid value is now a schema-validation # failure, not a silent bad call the handler must catch

The architectural point: an enum, a bounded number range, or a fixed date format isn't extra ceremony — it converts an entire category of bug from "discovered in production when the handler mishandles it" to "impossible to construct in the first place."

Overlap is a selection-time bug, not a code smell

Two tools can each be individually well-written and still break the system together, if their descriptions both plausibly cover the same request. get_customer_by_email and search_customers with a filter on email look redundant to a human skimming the code, but the actual failure mode is worse than redundancy: the model has no reliable way to know which one you intended for the ambiguous case, and it will pick inconsistently across otherwise-identical requests.

The fix is architectural, not textual — merge the overlapping pair into one tool with a parameter, or partition their descriptions so the boundary between them is unambiguous ("use this only when you already have the exact ID"). A better sentence in one description while the other tool still overlaps doesn't remove the ambiguity; it just moves it.

Key concept

A tool schema is a contract for a reader that can’t ask a follow-up question. Everything the schema doesn’t constrain becomes a runtime defense; everything the description doesn’t disambiguate becomes a selection error.

When a scenario describes a model "calling the wrong tool" or "constructing an invalid call," the fix under test is almost always schema or description design, not a smarter model or a longer prompt.

Practice scenario

ScenarioAn architecture has three tools — update_order, modify_order, and edit_order_details — added over time by different engineers, each doing a slightly different subset of the same underlying update. Calls to the wrong one are now a recurring bug report.
Work it through, then open this

The bug isn’t in any single tool’s code — it’s that three descriptions cover overlapping ground with no disambiguating signal. The fix is consolidation: one update_order tool with parameters covering the full range of what the three used to split apart, and a schema that makes invalid combinations of those parameters unconstructable. Renaming the three tools without merging them would not fix this; the ambiguity is structural, not lexical.

Build exercise — Audit a tool for selection ambiguity

Intermediate · 25 min

What you’ll learn

  • Reading a tool description the way a selecting model reads it
  • Finding parameter fields that don’t structurally rule out invalid values
  • Spotting a second tool that silently competes for the same requests
  1. Take a tool your application already exposes and list every other tool whose description could plausibly also handle the same sample request.

    • Why: Overlap is invisible from inside a single tool’s code — it only shows up when you compare descriptions side by side.
    • You should see: Either a clean partition, or two tools that would both look reasonable to a model receiving the same request.
  2. For each parameter, ask whether an invalid value can currently be constructed. Convert free-text fields with a small fixed set of valid values into an enum.

    • Why: Every unconstrained parameter is a defense your handler has to write and a failure mode your handler has to explain.
    • You should see: A shorter list of “things the handler must validate” and a schema that now does that work instead.

Exam traps

Naming a tool after its internal implementation instead of its effect

A name like query_v2_service tells the model nothing about when to use it. Names should describe effect and scope.

Writing a description for a human maintainer instead of the calling model

The audience at call time is the model deciding whether this tool fits the current request — not a future engineer reading the source.

Leaving a parameter’s format unconstrained when only a few values are valid

An unconstrained field pushes validation into the handler and turns a preventable error into a runtime one.

Shipping two tools whose descriptions could both plausibly apply to the same request

This is a selection-time bug, not a documentation issue. Merge or clearly partition them.

Assuming a working demo with one tool proves the schema at ten tools

Overlap and ambiguity are invisible with a single tool and only appear once there’s something to be confused with.

Making a required field optional to be “flexible”

It reintroduces the invalid states the schema existed to rule out, in exchange for convenience nobody asked for.

Sources

Quick check

A team's stdio-based MCP server, built for one engineer's local agent, now needs to serve three more engineers' agents simultaneously. What must change?