Skip to main content

MCP Server Engineering

Every tool you give an agent costs tokens before it asks a single question — so how do you build a server that gives the right capability at the right cost?

This is the builder's view of MCP. If you want to decide which MCP servers to adopt, that is a value-selection job — see the MCP tool radar. This page is how to engineer a server that any client can reuse.

Model Context Protocol standardises how AI models reach external capabilities — databases, APIs, file systems, other tools. Before MCP, every application invented its own integration layer. MCP is the USB-C standard for agent-tool connections: build the server once, use it with any MCP-compatible client.

Architecture

Three roles, one protocol, nested:

Host (Claude Code, Cursor, Claude Desktop)
└── Client (one per server connection)
└── Server (exposes tools/resources/prompts)
└── External system (DB, API, filesystem)
  • Host — contains the LLM and manages all client connections (Claude Code, Cursor, Claude Desktop).
  • Client — the protocol adapter, one per server, handling transport. Built into the host.
  • Server — what you build: it exposes capabilities to the client (Supabase MCP, GitHub MCP, your own).

Connection flow: the host creates a client per configured server → the client connects over its transport → client and server negotiate capabilities in a handshake → the model receives all tool schemas and calls them as it reasons → results flow back through the client into model context.

The Three Primitives

Every server exposes some combination of three capability types. Choosing the right one is the core design decision:

  • Tools — functions the model calls (search, query, write, execute). The schema sits in context always; the result arrives only when called. This is the main capability.
  • Resources — file-like data the model can read (documents, DB records, configs). Loaded on request; can be large.
  • Prompts — reusable prompt templates with typed arguments. Minimal schema cost; injected on demand.

Tools are the workhorse. Reach for resources when the workflow is read-heavy, and prompts when it is templated.

Token Economics — the design constraint

Loading tools is not free. Research shows MCP tool definitions inflate input tokens by 3× to 236× depending on the toolset [source: arXiv 2508.12566]. Every schema loaded before the first message is tokens unavailable for reasoning. This is the constraint that shapes every server you build:

Session budget = context_window × 0.6 (reserve 40% for reasoning)
MCP overhead = Σ(tool_schema_tokens) + Σ(tool_result_tokens)
Target = schema overhead < 15% of session budget

Design for loading strategy from the start:

  • Static (always load) — all schemas in context from turn one. Fine for toolsets of ≤5 tools used every session.
  • Dynamic (load on demand) — only the schemas currently needed. Cuts overhead by ~96% on large toolsets [source: Speakeasy].
  • Curated profiles — the right tools per role, nothing extra. The recommended approach.

The practical rule you design toward: if a tool isn't in the caller's always-load set, don't make them pay for its schema. Keep tools few, schemas tight, and results field-maskable.

Transports

  • stdio — the server runs as a subprocess; the client talks over stdin/stdout. Zero-latency, no networking. Best for local servers (filesystem, CLI tools).
  • HTTP + SSE — the server runs as a remote HTTP service; the client connects via SSE. Best for cloud-hosted, shared instances — one server for the whole team.

Why MCP Beats Bespoke Function Calling

Traditional function calling made every application define its own tools — no reuse, no standard security, no dynamic discovery. MCP changes each axis:

  • Integration — build once against the protocol instead of per-application custom code.
  • Discovery — dynamic capability negotiation instead of a static startup list.
  • Security — server-enforced access controls instead of per-integration ad-hoc rules.
  • Composability — a shared server ecosystem (2,000+ servers) instead of each agent rebuilding the stack.
  • Surface — tools plus resources plus prompts, not tools alone.

The compounding effect: a well-designed server built once works in Claude Code, Cursor, Claude Desktop, and any future client without modification.

How to Apply

  1. List the capability you're exposing and decide its primitive — tool, resource, or prompt.
  2. Write the tightest schema that still lets the model call it correctly; every token in the schema is paid on every session.
  3. Choose a transport: stdio for local, HTTP+SSE for shared/remote.
  4. Decide loading strategy — static only if ≤5 always-used tools; otherwise dynamic or a curated profile.
  5. Field-mask results so a call returns only what was asked for.
  6. Publish so any client can negotiate it.

Proof of done: the server's schema overhead is under ~15% of the session budget, an unfamiliar client can discover and call it from the handshake alone, and no result floods the context window.

Failure Modes

  • Schema bloat. Too many tools or verbose schemas eat the reasoning budget before the agent starts.
  • Static-loading a large toolset. Every session pays for tools it never calls.
  • Unmaskable results. A single query returns a wall of data that blows the window.
  • Stateful assumptions over stdio. Treating a subprocess transport like a persistent session.
  • Tool ambiguity. Two tools the model can't distinguish → wrong-tool calls at scale.

Changes my mind: if context windows grew cheap and effectively unbounded, token economics would stop governing server design and the discipline here would relax toward "expose everything."

Context

  • instance-of Intelligent Hyperlinks — MCP is the third pipe: a standard that lets an agent discover and call a capability
  • pairs-with Agent-First CLI Design — a hardened CLI exposes itself through exactly this protocol
  • pairs-with AI Harness — the harness carries only the tools it needs; this page keeps each tool cheap enough to carry
  • depends-on Agent Protocols — where MCP sits in the broader protocol stack
  • applies-to MCP Tool Radar — the selection view that decides which servers earn their token cost
  • up Agent Tooling — the engineering hub

Questions

Which server design decision — schema clarity, stateless versus stateful context, or the authentication model — has the most impact on agent reliability at scale?

  • At what tool count does a server become too complex for an agent to select the right tool without extra routing logic?
  • If dynamic loading cuts token overhead by 96% but adds 2–3× more tool calls, when is static loading still worth it?
  • Which of the three primitives is most underused — and what workflow does that gap represent?