An MCP server's real user is a model reading tool descriptions under pressure. Design every tool so the calling agent can pick it, call it right, and recover from failure without a human explaining the server.
When to use
- Building a new MCP server or adding tools to an existing one
- Reviewing tool schemas, descriptions, or auth design before shipping a server
- A client asks to expose an internal API or dataset to agents
Tool design
- Tools are verbs scoped to one outcome (
save_skill,pull_skill) — not a genericqueryescape hatch that moves the API docs into the caller's head. - Descriptions state what the tool returns, what it requires, and when NOT to use it; the first sentence alone must be enough to choose correctly.
- Inputs: flat JSON-schema objects, defaults documented in the description, enums for closed sets, hard caps on every string and list.
- Return structured results plus a compact text rendering; include a
next stephint when a workflow continues (a follow-up tool, a URL, a report-outcome call).
Auth & tenancy
- Derive the tenant from the validated credential server-side — never from a tool argument; one URL serves every tenant with full isolation.
- Tier access: read-only public tools work with no credential wherever the data allows; credentials unlock scoped writes; plan/role gates sit on the write path.
- Failed auth returns an instruction, not a rejection: name the header, where to get the credential, and what works without one.
Behavior
- Stateless per request unless the protocol demands otherwise; every tool call must be safe to retry or explicitly say it isn't.
- Errors are tool results (
isError: true) with a message the AGENT can act on — include the failing field and a valid example, never a bare stack trace. - New tools land additively; renames keep the old name serving a deprecation pointer for a release.
initialize.instructionsis onboarding: say what the server is for, name the entry-point tool, and state the caller's current access tier.
Examples
Good error: "workspace key required: send header 'x-uplift-key: upk_...'
(create one at dashboard.example.com). Public reads work without it."
Bad error: "401 Unauthorized"
Good description: "Fetches one skill as installable markdown - public skills need
no key; a workspace key adds your workspace's own."
Bad description: "Gets a skill." — choosable only by trial and error.