How to Build a Production-Ready MCP Server
A production MCP server needs five things a demo does not: tool descriptions precise enough for a model to select correctly, errors that explain how to recover, authentication scoped per caller rather than a shared key, idempotent write operations, and a small context footprint. The protocol is the easy part. Tool design is the work.
Design the tools before you write the server
The protocol layer is largely solved by the SDKs. What determines whether your server works in practice is the contract you expose, and that is a design exercise you should do before any code.
Start from the tasks an agent will attempt, not from your API surface. A one to one mapping of REST endpoints to tools is the most common mistake and produces servers with thirty tools where four would do. Agents are not clients writing integration code, they are operators trying to accomplish something, and they compose poorly across many small primitives when each one requires knowledge they do not have.
Name tools by the operation, not by the resource. Describe them with enough precision that selection is unambiguous: what the tool does, what it returns, what it does not do, and when to use it instead of a similar tool. If two of your tools could plausibly answer the same request, the model will pick inconsistently, and that inconsistency is your fault rather than the model's.
Keep arguments few and shallow. Deeply nested objects with optional fields get filled in wrongly. If a parameter requires knowing an internal identifier, either accept a human readable alternative or provide a lookup tool that returns it.
The context budget nobody accounts for
Every tool schema you expose is sent with every request for the entire session, whether or not it is used. A server exposing twenty tools with verbose descriptions can consume a noticeable share of the window before the user says anything, and it degrades selection accuracy across every other tool the client has connected. Expose the smallest set that covers the work.
Errors are part of the interface
In ordinary API design an error is a status code and a log line. For an MCP server, the error text goes directly into a model's context and is the sole basis on which it decides what to do next. That makes error design a feature.
A production error states three things: what failed, why, and what a valid next step would be. "Invalid argument" leaves the agent guessing. "start_date must be ISO 8601, received 03/04/2026, use 2026-03-04" gets a correct retry on the next turn.
Distinguish the categories clearly. A permission failure should be unambiguous, because an agent that reads it as a transient error will retry pointlessly. A rate limit should say when to try again. A not found should say what was searched so the agent can widen its query rather than repeating it.
And never return a success with an empty payload when the operation did not do what was asked. An agent takes that as done and moves on.
Auth, safety, and writes
Authentication per caller. A shared service key means every agent has every permission your server has, and nothing in the audit trail distinguishes them. Scope credentials to the caller and carry the identity through to your backend so that the permissions your organization already defined still apply.
Least privilege by tool. Read and write should be separable, so a client can connect the read tools without also gaining the ability to mutate. Many deployments only ever need the read half.
Idempotency on writes. Agents retry: on timeout, on ambiguous errors, on a user asking again. Accept an idempotency key and deduplicate, or you will create duplicate records and, in some domains, duplicate charges. This is the single most common production failure in agent facing APIs.
Confirmation for the irreversible. Expose destructive operations as two steps, a preview that describes the effect and an execute that takes the preview's token. That structure gives the client a natural place to insert human approval.
Treat inputs as untrusted. Arguments arrive from a model that may have read attacker controlled text. Validate, bound, and never interpolate directly into queries or shell commands.
Operate it like a service
Log every tool call with its arguments, outcome, duration, and the caller identity. When an agent behaves strangely, this log is the only place the answer lives, and reconstructing it after the fact is impossible.
Set timeouts deliberately. An agent waiting on a slow tool burns the user's patience and, in some clients, retries in ways that multiply load.
Version the contract. Renaming a tool or changing an argument silently breaks every agent that learned the old shape from a system prompt or a skill. Additive change is safe, renaming is not.
Test with a real client, not with unit tests alone. Most defects in MCP servers are not crashes, they are tools the model selects wrongly or arguments it fills in badly, and those only appear when a model is doing the calling.
When not to build a server at all
If what you are exposing is mostly documents, an MCP server is the wrong shape. A tool is a verb and knowledge is a noun, and models under-call optional lookup tools because nothing in the conversation reminds them the material exists. Index the content instead. RDK turns vaults, docs, and code into encrypted private chunks that agents search before querying a model, cutting token spend 80 to 90 percent because the answer is retrieved rather than regenerated. Private retrieval covers 40 to 65 percent of queries, the public network 15 to 20 percent, and the model handles the last 5 to 10 percent. Build a server for access to systems, and index for knowledge about them.
Frequently asked questions
- What makes an MCP server production ready?
- Tool contracts precise enough that a model selects correctly, errors that explain how to recover, per caller authentication rather than a shared key, idempotent writes, deliberate timeouts, and call logging with caller identity. The protocol implementation is mostly handled by SDKs. The design work is the tool surface.
- How many tools should an MCP server expose?
- As few as cover the work. Every schema is resent on every request for the whole session, so a large surface consumes context and makes selection harder across every tool the client has connected. Map tools to the tasks agents attempt rather than one to one onto your existing API endpoints.
- Why do agents call the wrong tool on my server?
- Usually because two descriptions are close enough that either could plausibly apply. The description is the model's only documentation, so it must state what the tool does, what it returns, what it does not do, and when to prefer it over a similar tool. Ambiguity in the contract shows up as inconsistency in behavior.
- Do MCP servers need idempotency keys?
- Any server with write operations does. Agents retry on timeouts, on ambiguous errors, and whenever a user repeats a request, and a retried write without deduplication creates duplicate records or duplicate charges. Accepting an idempotency key is a small change that prevents the most common production failure in agent facing APIs.