Senior · 6 chapters
Building a server
Choosing the surface, keeping tools orthogonal, returning model-legible errors, testing it in isolation from any agent
A server with a bloated surface or opaque failures makes agents unreliable before prompting can compensate.
Read these first
What you will know
Build a working server with a small, orthogonal tool set
Keep schemas narrow and non-overlapping so tool selection remains reliable as the model sees more capabilities.
Test it in isolation, with no agent involved
Direct calls expose protocol, schema, serialization, and lifecycle defects without conflating them with planning or prompt behavior.
Return errors a model can act on
Include a stable failure category, the relevant input problem, and a safe next action instead of stack traces or vague status messages.
Compare two candidate surfaces against representative tasks and record which tools are omitted and why
Removing redundant operations reduces selection ambiguity, permission exposure, and the amount of tool documentation in context.
Hand it to someone else and have them use it without asking questions
A fresh user should discover required inputs, constraints, and recovery paths from the exposed descriptions and responses alone.
Chapters
- 1
Orthogonality in a tool surface
An issue tracker exposing list_issues, search_issues, find_issues_by_assignee and get_sprint_issues has four names competing for one job, and sharpening all four descriptions cannot settle a tie the surface created. State the overlap precisely — some task in scope has two reasonable tools — by marking a table of real tasks against the tools a careful reader would consider defensible, then collapse the set into one query_issues with a filter object, which moves the decision from unvalidated ranking into a schema that validates. The surface you register on the server is the design artefact everything in this topic works on.
- 2
Tool count and selection accuracy
Nineteen tools, one per CLI subcommand, is how selection accuracy slides from 94% to 81% over two quarters: each addition can conflict with every existing one, so pairwise disambiguation grows faster than the surface does — 73% more tools between Q1 and Q3 and 211% more pairs. Run two candidate surfaces against the same representative tasks, read completion counts as weak evidence rather than a verdict, and record which operations you omitted and why. Deleting a tool two teams already call is a rollout: alias the old names onto the consolidated tool, keep a retired one callable but unlisted, and leave a reverse edge for the caller that cannot migrate.
- 3
The blast radius of a misroute
Better descriptions lower how often a selection goes wrong and change nothing about what a wrong selection can reach; 93% accuracy over 64 eval tasks is still four or five wrong selections a pass. Separate read surfaces from write ones so an ambiguous choice lands on a query, make destructive operations name their target explicitly and carry a precondition instead of defaulting to a current or last-used one, and spend confirmation only on the few operations whose cost is irreversible. None of these depend on how good your schemas are, which is the point: they are what you design for the misroute you will still get.
- 4
Actionable tool errors
A create_calendar_event that answers a non-IANA timezone with HTTP 400 and \"Invalid request\" leaves the agent guessing six times over 9.4 seconds and 11,200 tokens before telling the user the calendar is down. An actionable replacement carries a stable machine code such as invalid_timezone, the value received, the constraint as an accepted form with an example, and a signal that an unchanged retry cannot help. Splitting one 500 into 401, 404 and 429 corrects the transport and not the behaviour, because the model never sees a status; what shows the new responses are better is retries per failure category, success on the call after the first failure, and how often a run ends with the agent declaring the integration broken.
- 5
Direct calls and agent runs
Direct calls against the server catch protocol, schema, serialisation and lifecycle defects in seconds, with no planner muddying which one fired, and they fire error branches an agent reaches only by accident. What they structurally cannot catch is whether the description and schema make this the obvious tool for the job it exists for, because the script never chose — you did, when you wrote the call. An agent run is not a superset: it is a noisier instrument over a smaller sample, exercising 6 of 14 tools on a 20-task set. Work out what each one sees, and what you are accepting when a demo tomorrow leaves time for only one.
- 6
The fresh-subject handoff
Hand the server to an engineer on another team with nothing but what it exposes, and count the questions: what format since wants, whether limit has a ceiling, what to do when a call returns rate_limited. Each is a defect rather than a question, because the model has nobody to ask, and each is located in exactly one of three places — a schema, a description or an error body. This chapter turns the handoff into a repeatable acceptance test with a fixed task list and a logged record, and works the asymmetric cases: a tool a human uses fine and an agent cannot, and the reverse.
External resources
- Resilient Write: A Six-Layer Durable Write Surface for LLM Coding Agentsarxiv.org
Six-layer durable writes for LLM coding agents: MCP tools, failure handling and testing.
- Build an MCP servermodelcontextprotocol.io
Walks through building MCP servers: choosing surfaces, orthogonal tools, model-legible errors, and isolated testing.
- MCP Builder — Anthropic agent skillmcpservers.org
Anthropic's own scaffolding recipe for a new MCP server.
- MCP server: A step-by-step guide to building from scratchcomposio.dev
Walks through building an MCP server, from tool design and errors to isolated testing.
- 07 MCP in Practice: stdio vs Streamable HTTPRyan Banze
Covers structured return types and error handling in a working server.
- Build and Ship Any MCP Server in MINUTES (Full Guide)Cole Medin
Shows building and shipping an MCP server: tool design, model-legible errors, and isolated testing.