MCP Tool Design: Schemas, Descriptions, and Structured Outputs

An MCP tool is an interface for model-assisted action. Its quality determines whether a model can select the right operation, provide valid arguments, understand the result, and recover from failure.
Protocol compliance is only the starting point. A technically valid tool can still be ambiguous, overpowered, or difficult to operate safely.
TL;DR
- Design tools around user jobs, not backend endpoints.
- Names and descriptions should explain intent, boundaries, and side effects.
- Input schemas should be narrow, typed, and difficult to misuse.
- Structured outputs should separate machine-readable facts from display text.
- Annotations and schemas help hosts, but never replace authorization.
Start with the user job
Suppose an order API has 40 endpoints. Mirroring those endpoints creates a large catalog that forces the model to understand implementation detail. A better MCP surface might expose readordersummary, checkrefundeligibility, and createapprovedrefund.
Each operation represents a recognizable task. The server can compose backend calls, normalize errors, and apply domain rules behind that contract.
Use one tool when inputs, permission boundary, and outcome form one coherent action. Split tools when they require different approvals, credentials, or failure policies.
Names that survive a large catalog
Names should be unique, stable, and descriptive. Prefer a domain-action pattern such as ordersgetstatus or tickets_create. Avoid vague verbs such as run, process, or handle.
The description should explain what the operation does, when to use it, what it excludes, whether it changes state, and which preconditions apply.
Do not write promotional descriptions. Models need discriminating details, not claims that every tool is powerful or intelligent.
Design bounded input schemas
JSON Schema lets a host validate proposed arguments before routing. Use required fields, enums, numerical bounds, string patterns, and nested objects only where they reduce ambiguity.
For a refund tool, prefer orderid, reasoncode, amount, and currency over one free-form request. Constrain reason_code to known values and amount to a positive maximum.
Avoid arguments that create open-ended authority:
- Arbitrary URLs that enable server-side request forgery.
- Raw SQL without a restricted query layer.
- Shell commands without a sandbox and allowlist.
- Filesystem paths without normalized root checks.
- Generic headers or credentials supplied by the model.
Defaults deserve caution. A missing dry_run value should not silently become destructive execution.
Separate validation from authorization
A schema answers whether arguments have the expected shape. Authorization answers whether this user may perform this action on this object now.
The host should validate before routing. The server should validate again and enforce domain authorization. Downstream services should retain business controls.
Structured outputs
Tools may return content for a model and structured data for applications. Define an output schema when stable machine-readable fields matter.
An order result might include orderid, status, estimateddelivery, sourceupdatedat, and a short summary. The host can render fields, store them in traces, and provide the summary to the model.
Avoid returning an entire backend payload. Large outputs raise context cost, leak unnecessary fields, and are harder to test.
Errors are part of tool design
| Failure | Example | Expected host behavior |
|---|---|---|
| Invalid input | Unknown reason code | Ask for correction |
| Permission denial | User cannot access order | Stop and explain boundary |
| Business rejection | Refund window closed | Present the rule |
| Transient failure | Upstream timeout | Retry if safe and bounded |
| Ambiguous write | Connection lost after submission | Reconcile before retry |
Do not convert every exception into a success-looking sentence. Reliable agents need explicit failure state.
Tool annotations and trust
Metadata can suggest whether a tool is read-only, destructive, idempotent, or connected to the external world. Treat annotations as hints from the server, not proof.
A buggy server can label a destructive operation read-only. The host should combine reviewed configuration, server trust, user policy, and runtime controls.
Test the model-facing contract
Test whether models select the right tool across realistic and adversarial prompts, omit it when irrelevant, provide valid arguments, and interpret errors correctly.
Create negative cases: similar names, missing permissions, maximum values, prompt injection in results, timeouts, and duplicate writes.
Common mistakes
- Mirroring every REST endpoint.
- Descriptions that only repeat the tool name.
- One unrestricted text argument.
- Enormous raw responses.
- Treating annotations as security controls.
- Changing schemas without compatibility planning.
My Take
Tool design is product design for a non-deterministic caller. The contract must guide the model, constrain the system, inform the user, and support operations. A smaller well-designed surface usually outperforms a large complete one.
Continue learning
Review [Tool Permissions and Least Privilege](/tool-permissions-and-least-privilege/) and [MCP Security and Permissions](/mcp-security-and-permissions/).