Many early Model Context Protocol (MCP) servers followed a design that seemed perfectly reasonable: take an existing Application Programming Interface (API), map each endpoint to a tool, expose the resulting toolset to the agent, and let the agent determine what to call.
For a small API with a handful of operations, that can work perfectly well. For anything larger, however, the pattern introduced two problems that initially looked like limitations of the agent rather than consequences of the server design.
What MCP Is and Where It Started
The Model Context Protocol is a standard for connecting AI agents to external tools, data sources, and capabilities. Where an agent previously needed custom integration code for every system it touched, MCP provides a common interface: a server exposes tools the agent can call, and the agent calls them without the client needing to know anything specific about the underlying API. The appeal is real. One protocol, many servers, any compliant client.
In its earliest form, as the Visual Studio Code team's MCP work documents, MCP commonly ran locally using standard input/output (stdio). The host application started the MCP server as a local process, and the two communicated through the process's standard input and output streams: the agent process started the server process, they talked over standard input and output, and the whole thing lived on a single machine. This was a sensible starting point, because local stdio is easy to debug, easy to reason about, and fast to stand up. Most of the first tutorials and examples assumed this pattern, which is why most of the first production MCP servers assumed it too.

The natural thing to do with that architecture was to map your API surface to tools. Every endpoint became a tool definition. The agent now had access to everything. What could go wrong?
The Two Failure Modes That Emerged
The Neon engineering team's analysis of this pattern names both failure modes clearly.
The first is context window bloat: when every endpoint becomes a tool, every tool definition gets loaded into the context window at the start of each session, so an API with two hundred endpoints means two hundred tool definitions sitting in the model's working memory before the user has typed a single word. For smaller APIs this is irrelevant. For anything with genuine breadth, it consumed a meaningful portion of the context budget before any real work began.
The second failure mode is subtler. When many endpoints do related things, with slightly different parameters or slightly different scopes, the agent starts picking the wrong one. Not consistently wrong, which would be easy to catch, but wrong in ways that depend on how the user phrases the request or what else is in the context. The agent is not reading your API documentation the way a developer reads it, building a mental model over time and forgiving ambiguity. It gets a tool description, takes it at face value, and makes a selection. When two descriptions are close enough to each other, the selection process becomes unreliable.
The field's initial response to both problems was a layered tool architecture: instead of hundreds of tools, expose three. A search tool to find relevant endpoints, an inspect tool to read a specific endpoint definition, and an execute tool to run the call. This dramatically reduced the context overhead and concentrated the tool selection problem into a single step with a clear right answer. For a while, this was the recommended pattern.
How the Client Changed What Servers Need to Do
Here is where the history gets interesting, and where configurations that made sense twelve months ago may be doing redundant work today. The layered search-inspect-execute pattern was originally implemented on the server side because clients were simple. Clients loaded whatever tools the server exposed and called them one at a time. The server had to manage discovery and composition because nothing else would.
That is no longer true of the major coding agents. Progressive tool discovery is now a recommended best practice for MCP clients, meaning clients like Codex and Claude Code handle the search-then-inspect logic themselves rather than relying on the server to expose it as tools. Beyond that, many of these clients now implement what is called code mode or programmatic tool calling: instead of calling tools one at a time, the agent writes a script that chains tool calls together, executes the script in a sandbox, and returns only the final result to the model. Between progressive discovery and code-mode composition, the client has absorbed the two problems the layered server pattern was built to solve.
This does not mean reverting to a flat one-to-one endpoint mapping. It means the server's responsibility has shifted. The discovery and composition logic that used to live in the server is now a client concern. What remains a server concern, and what smarter clients make more valuable rather than less, is the ergonomic composite tool: a single callable operation that bundles a workflow that would otherwise require three or four sequential calls.
The Neon example from that same analysis is concrete enough to be useful. Creating a Neon branch is not one API call; it is three. You create the branch, attach compute resources, and retrieve the connection string. If an agent with access to raw endpoints has to figure out that sequence every time, it wastes tokens reconstructing the same chain and occasionally gets it wrong. Bundling those three calls into a single "create with compute" operation is the server doing the work that an SDK helper method does for a human developer: it encodes the right sequence once and makes it available as a single call. For simple APIs, a one-to-one mapping may be entirely appropriate. For APIs where provisioning or workflow complexity is real, composite tools are where the server earns its keep.
The Two Primitives Nobody Talks About
Tool counts have become the default way people evaluate MCP servers, which is understandable and also wrong as a measure of anything important. Kin Lane's analysis at API Evangelist makes a case that the genuinely valuable parts of the protocol are the two primitives that get almost no coverage: prompts and resources.
MCP prompts are not chat prompts in the conversational sense. They are curated, parameterized queries written by someone who knows the system well and made available as a first-class API primitive. The gap they fill is the one that has existed in APIs forever: the difference between "you technically have access to two hundred operations" and "here are the fifteen questions worth asking, phrased the way an expert would phrase them, ready to run." Lane's observation is that this is a documentation and onboarding win that has nothing to do with AI specifically. It is better API design that MCP happened to formalize, and the field has mostly walked past it on the way to arguing about tool counts.
Resources address a different gap. For the entire history of APIs, the documentation, schema reference, and contextual explanation have lived somewhere else: a separate portal, a wiki, a getting-started guide that gradually drifts out of sync with the API it describes. MCP makes accompanying context a first-class member of the interface itself, sitting alongside the capability rather than two clicks and one stale page away. When an agent reaches for a tool, the resource that explains the relevant domain knowledge comes with it. Lane calls this "quietly one of the best ideas in the whole protocol," and it is worth taking seriously, because the co-location of capability and context is exactly what makes the difference between an agent that uses a tool correctly on the first attempt and one that produces plausible-but-wrong output until it stumbles into the right parameter.
Self-Built Versus Vendor-Provided MCP Servers
Most practitioners will encounter MCP through one of two paths: a vendor ships an MCP server with their product and you connect to it, or you build one yourself against an API you control or depend on. The tradeoffs are real and the right answer depends on what you are actually trying to do.
Vendor-provided servers carry the obvious advantage of existing: someone else has already mapped the API surface, written the tool descriptions, and handled the authentication. For straightforward use cases where the vendor's model of what you want to do matches your actual workflow, this is the right choice. The cost is opacity. You do not control the tool descriptions, you cannot add ergonomic composites for your specific workflows, and when the agent makes a bad decision because a tool description is ambiguous, you are waiting for the vendor to care about that in the same version cycle as something else on their roadmap.
Self-built servers give you control over every surface the agent touches. Tool descriptions are the highest-leverage optimization point for agent reliability, which means a server you control is a server you can tune when behavior goes wrong. You can add composite tools for your specific workflows, expose prompts that encode your team's best practices as callable primitives, and co-locate resources with the capabilities that depend on them. The cost is maintenance: you own the updates, the auth, and the gap between your server and whatever the underlying API does next.
A reasonable middle path, illustrated by the Neon architecture, separates tool definitions into a standalone package. That package can serve the MCP server and also be wrapped into adapters for other agent frameworks, which means the same tool definitions travel across integration points without duplication. If you are building against an API with any complexity, this separation pays for itself quickly.
The Transport Shift You Will Need to Handle Eventually
The architecture most practitioners are running today still uses local stdio transport. That is appropriate for development and for single-machine deployments, but it is increasingly not where production MCP is going. The shift to stateless HTTP transport, which the VS Code team identifies as the largest architectural change to the protocol, enables scalable deployment across multiple server instances and opens up options for authentication that stdio never supported.
The operational cost is real, though. Stateless HTTP means you can no longer rely on in-process state to track a user's session across tool calls, so you need shared storage, explicit session management, and an authentication layer that works across instances. None of these are unsolved problems, but none of them come for free from the protocol, and the fact that a demo works over stdio does not mean it is ready to run at scale over HTTP. This is a Part 2 conversation, but it belongs in the picture now because the architecture you choose for transport shapes everything downstream.
What to Ask About Your Current Configuration
Before adjusting anything, the right move is to understand what you actually have. A few questions worth working through before the next part of this series takes up what to change:
How many tools does your server expose, and did that number come from a deliberate decision or from mapping your API surface one endpoint at a time? If it is the latter, the context-window and tool-selection problems are probably present, even if they have not surfaced visibly yet.
Does your server include any composite tools, or does every operation map to a single API call? For each multi-step workflow your agent routinely executes, ask whether the sequence is being reconstructed from scratch every time or encoded once as a callable operation.
Are you running vendor-provided MCP servers where you do not control the tool descriptions? If so, know that when agent behavior goes wrong in those integrations, the optimization surface is not available to you.
Does your server expose prompts and resources, or only tools? If you are evaluating a vendor-provided server, ask the same question of them, because the answer tells you whether the integration was designed for agent usability or just for feature-announcement completeness.
What transport are you using, and does your deployment assumption still match the architecture you have? If you have moved from a single-machine setup to something distributed, and you are still on stdio, the mismatch will surface eventually.
Part 2 takes up what to do with those answers.
Member discussion: