First MCP server tool design
Building an MCP server is mostly an API design problem with one extra constraint: the caller is a model, not a person. Naming and arguments matter more than transport.
Published02 May 2026
Updated
Read time3 min · 528 words
Tool focusMCP, Anthropic, Claude Code
The first time you build a Model Context Protocol server, the tempting move is to start from the transport. Should it be stdio? HTTP? SSE? The answer matters, but not yet. Long before transport, the question is what your tool surface looks like to the caller — and the caller is a language model, not a developer.
Name tools the way you would name buttons
A model picks a tool by reading its name and description. That is the entire interface. So the naming has to be unambiguous in isolation. search_documents is a fine name. query is not — it could mean anything.
A good test: if you stripped your server down to a list of tool names with no descriptions, would a model reading them know which to call for a given task? If the answer is no, the names need work.
Arguments are not for the developer, they are for the model
Argument design follows the same rule. The model reads the argument schema and infers what to fill in. So argument names should describe the meaning of the value, not just the type. customer_id is better than id. published_after_iso8601 is better than date_filter.
Default values are a quiet superpower. Every argument that has a sensible default is one fewer thing the model has to guess. A tool with three arguments and three good defaults will be called correctly far more often than a tool with three required arguments.
Errors are part of the tool surface
When a tool fails, the model reads the error message. So error messages have to be useful as input to the model, not just as log lines for the developer. permission_denied: caller lacks scope read:invoices is something the model can react to. 500 internal server error is not.
A practical pattern is to return errors that name the specific scope, the specific input, or the specific precondition that failed. The model can then either retry with corrected input or escalate cleanly. Both outcomes are better than the silent loop where the model retries the same call with the same input and you wonder why your logs are noisy.
Scopes are the security boundary
Authentication and authorisation on an MCP server are the same problem as on any other API. The agent does not get a parallel identity universe. Per-user scopes apply, audit logs apply, secret rotation applies. The most common failure mode is treating the MCP server as an internal trusted thing that the agent calls on the user's behalf without thinking carefully about whose credentials the agent is actually holding.
A simple rule: if the call would require an OAuth token in a normal API context, it requires one in MCP context too. The transport is just plumbing.
Then choose the transport
Once the tool surface, arguments, errors, and scopes are in good shape, the transport choice is mostly a deployment question. stdio for local single-developer integration. HTTP for shared internal services. SSE where the tool produces a stream the agent should react to. None of these choices fix a poorly designed tool surface, and a well-designed tool surface survives a transport switch later.
Related notes
07 May 2026 · 3 min
Eval suites for codebase-specific agent use
Most AI rollouts skip evals because they feel like overhead. A small, codebase-specific eval suite, built in an afternoon, is the cheapest way to keep model and prompt changes from becoming a vibes call.
29 Apr 2026 · 3 min
Claude Code hooks that actually save time
Claude Code hooks are easy to over-engineer. The right four save real time and prevent the failure modes you actually hit in week one.
22 Apr 2026 · 3 min
Codex on a real repo
Codex is a repo-aware coding agent. Used carelessly it generates churn the team has to clean up. Used with scope and a real review gate, it ships work.