mcp7 min read

Designing MCP Servers for Real Tools

Patterns for MCP server boundaries, auth, idempotent tools, clear schemas, and error contracts—plus anti-patterns to avoid.

A well-designed MCP server feels boring: small surface area, predictable errors, and tools that do one job safely. A poorly designed server turns every agent session into incident response. This post covers boundary design, auth, idempotency, schemas, and the anti-patterns I see when teams rush “MCP wrappers” around legacy APIs.

Why server design beats prompt engineering

When tools are vague, teams compensate with longer system prompts. That does not scale: prompts drift, models change, and injection gets easier. Crisp tools and structured errors move failure left—to validation and API tests you already run in CI.

Treat each tool description as part of your public contract. Review it in PRs the same way you review user-facing error strings. If two teams ship servers with overlapping tool names, hosts cannot disambiguate reliably—governance is part of design, not an afterthought once agents are in production.

Start with boundary design

An MCP server should wrap a coherent domain, not your entire backend.

Good boundaries

  • One server per trust domain (e.g. “customer support tickets” vs “billing mutations”).
  • Tools that map to user-meaningful actions, not raw database rows.
  • Resources for read-only context that agents need repeatedly (profile summary, project metadata). The protocol’s resources model is meant for exactly this: stable URIs or templates the host can fetch without triggering side effects.

Weak boundaries

  • A single “god server” with dozens of tools and overlapping names.
  • Tools that mirror internal admin APIs users were never meant to trigger from chat.
  • Hidden side effects (sending email, charging cards) bundled into innocent-sounding tool names.

If you are aligning product strategy first, read What is MCP for vocabulary, then Building AI-powered software products in 2026 for where servers sit in the stack.

Auth, scoping, and tenancy

MCP servers must authenticate the end user (or service identity), not only the host application.

Practices that work

  • Reuse your existing OAuth or session model; pass scoped tokens into the server process.
  • Encode tenancy in auth claims; reject cross-tenant tool calls server-side even if the model asks nicely.
  • Separate read and write scopes so hosts can offer “suggest only” modes without new server code.

Practices that fail

  • A shared API key embedded in the host that grants org-wide admin.
  • Trusting client-supplied userId fields in tool arguments without verification.
  • Long-lived tokens with no rotation tied to MCP sessions.

Document scopes in product copy so users know what an agent can access—security UX is part of server design. Production threat models belong in MCP security & permissions.

Idempotency and safe writes

Agents retry. Users click “run again.” Models duplicate tool calls. Write tools must be safe under repetition.

  • Prefer idempotent keys for create/update operations where your domain allows it.
  • Expose dry-run or preview tools for high-impact actions when possible.
  • Return stable identifiers in success payloads so the host can dedupe UI notifications.

For destructive operations, require a second step: confirmation token, elevated scope, or human approval in the host UI—not a longer system prompt begging the model to be careful.

Schema clarity and error contracts

Models choose tools from names, descriptions, and JSON Schema–style inputs. The MCP specification defines how tools are advertised and invoked, how resources expose readable context, and what metadata hosts need for discovery—align your server implementation with those docs rather than inventing parallel shapes. Input constraints should follow familiar JSON Schema patterns so validators and SDKs can reuse tooling you already trust.

Treat tool and resource metadata as UX copy reviewed by engineering and product. When a field accepts an enum or a date range, say so in the description; models do not read your OpenAPI PDF.

Schema tips

  • Use descriptive tool names (search_open_tickets not query_v2).
  • Document units, enums, and max lengths in field descriptions.
  • Avoid “bag of optional fields” schemas that invite hallucinated parameters.

Error contracts

Return structured errors the host can map to UI: code, message, retryable, optional details safe to show users. Do not dump stack traces into tool results. When a dependency fails, say which layer failed and whether the user can retry.

Align with how you document HTTP APIs today; MCP does not remove the need for consistent error semantics. For client-side loops that consume these errors, see Connecting AI agents with MCP.

Observability from day one

Log tool invocations with correlation IDs shared across the host and server. Metrics worth tracking:

  • Latency per tool
  • Error rate by code
  • Rate of validation failures (often signals schema or prompt issues)

Tracing helps when an agent chains multiple tools; you need to see the graph, not isolated log lines.

Anti-patterns

| Anti-pattern | Why it hurts | |--------------|--------------| | Mega-tools with mode flags | Models pick wrong modes; split into explicit tools | | Leaking PII in resources | Compliance risk; redact and minimize | | Silent partial success | Users trust wrong outcomes; return explicit status | | Prompt-only guardrails | Bypassed by injection; enforce on server | | Unversioned breaking schema changes | Breaks hosts in the wild; version tools or servers |

Testing servers before agents touch production

  • Contract tests for each tool’s input validation and auth matrix.
  • Golden-path scenarios that mirror real user jobs (not toy math tools).
  • Failure injection for timeouts and 429s from upstream APIs.

Pair server tests with evals in the host so you catch wrong tool selection as well as wrong tool implementation.

Pagination, limits, and large results

Tools that return unbounded lists will overwhelm model context and slow hosts. Design explicit limits:

  • Default page sizes with continuation tokens in tool results.
  • Summarization tools for “overview” vs detail tools for “fetch one record.”
  • Warnings in schema descriptions when results may be truncated.

Resources for large files should support range reads or precomputed summaries stored in your domain—not dumping megabytes into every turn.

Naming, discovery, and documentation

Hosts list tools for users and models. Inconsistent naming across servers (createTicket vs tickets_create) confuses selection. Adopt a convention per org:

  • domain_action snake_case or consistent camelCase—pick one.
  • Prefix server name in telemetry even if not in tool name, so operators know which deployment failed.

Publish internal docs mirroring public API references: examples per tool, required scopes, and common error codes. Link out to Connecting AI agents with MCP for how hosts present errors in the loop.

Handoffs between platform and feature teams

Platform teams often own the MCP host SDK, auth plumbing, and shared telemetry. Feature teams own domain servers. Write an internal “server author guide” that covers:

  • Required metadata fields and review checklist before merge.
  • How to request new OAuth scopes without widening org-wide defaults.
  • SLAs for upstream APIs your tools call.

Clear handoffs prevent every product squad from inventing incompatible error shapes—pain that shows up later in Connecting AI agents with MCP when the host cannot map failures to UI.

Local development and staging

Developers need fast feedback loops:

  • Run servers locally with fixture data; avoid shared staging tenants for destructive tests.
  • Seed eval transcripts that call your tools with realistic args.
  • Mirror production auth flows in staging so “works on my machine” does not mean “bypassed OAuth.”

Record short screen captures or transcripts of happy-path tool runs for onboarding—new engineers grasp schemas faster from examples than from prose alone.

Rate limits and fairness across tenants

Agents can issue bursts of tool calls that look like abuse to upstream APIs. Apply per-user and per-tenant rate limits inside the server, not only at the host edge. Return retryable errors with backoff hints when limits trip so the host can show “try again in a moment” instead of a generic failure. Fairness policies belong in server design because the model will not self-throttle when a user asks for a bulk export.

Closing

Designing MCP servers is API design under agent pressure: smaller surfaces, stricter auth, explicit errors, and write paths that survive retries. Get boundaries right, then wire agents with the patterns in Connecting AI agents with MCP. Before production write tools ship, complete a security pass using MCP security & permissions and keep the hub map in Building AI-powered software products in 2026 handy for stack-wide tradeoffs.

Let's talk