The MCP Abstraction Tax
By Justin Poehnelt Published 6 min read
My last post argued that CLIs need to be redesigned for AI agents. That post was about how to build. This one is about what happens at the boundaries. I focus on the fidelity you lose every time you add a layer between an agent and an API.
A conversation about building an MCP server for a complex enterprise CRM clarified the tradeoff for me: every protocol layer between an agent and an API is a tax on fidelity. The tax is sometimes worth paying. But you should understand what you’re giving up at each layer, because the costs compound, especially with complex enterprise APIs. Jeremiah Lowin’s Code Mode makes the case that most MCP servers treat agents like humans rather than using their ability to write code. I want to focus on a related but distinct problem: what happens to fidelity when the API underneath is already hostile.
The abstraction stack
Consider the layers between an agent’s intent and a CRM opportunity record:
Agent Intent: "Update the probability on the ACME corp deal"
│
▼
┌─────────────┐
│ MCP Tool │ ← abstraction tax
│ Definition │
└──────┬──────┘
│
┌──────▼──────┐
│ REST API │ ← abstraction tax
│ (CRM) │
└──────┬──────┘
│
┌──────▼──────┐
│ Data │ ← the actual thing
│ (Storage) │
└─────────────┘ Each layer is an abstraction. Each abstraction loses something. The fidelity loss starts before MCP even enters the picture. The REST API is itself an imperfect projection of the underlying data model. A CRM’s internal object representation is richer than what the standard REST API exposes. MCP adds another layer on top of that.
The question at each layer is whether what you gain in discoverability, safety, and standardization is worth what you lose.
But for complex enterprise APIs, the math changes.
The two-path problem
When you build an MCP server for an enterprise API like a mature CRM, you face a choice:
Path 1: Constrained tools. You expose a handful of high-level operations such as create_account, update_opportunity, and add_contact. These are easy for models to call, fit comfortably in a context window, and provide a clean developer experience. But they’re lossy. The CRM’s bulkUpdate API accepts dozens of request types with deeply nested relationships and custom fields. You can’t express “update the stage on 50 opportunities, recalculate their custom revenue formulas, and reassign the related tasks to the new account owner” through update_opportunity.
Path 2: Full surface. You expose every API method as a tool with its full request schema. This preserves fidelity but explodes the context window. A full-featured enterprise CLI covers dozens of services with hundreds of commands mapping directly to the underlying APIs. Loading all of those tool definitions into an MCP context at once would consume a meaningful fraction of an agent’s reasoning capacity. Most of them would be irrelevant to any given task.
Neither path is great. The first is too limited. The second is too expensive. And every team building an MCP server for a large API surface hits this same wall.
Why the APIs are hostile
The underlying API adds to the problem. Enterprise CRM APIs were designed for human developers who would read docs, understand the complex data model, and carefully construct requests. They have sharp edges, including opaque relationship identifiers, polymorphic custom fields, deeply nested JSON structures, and missing capabilities for operations that feel basic. I covered the input hardening side of this in my previous post. The point here is that these APIs are not friendly to AI agents, and forcing agents through a simplified MCP abstraction on top of an already-unfriendly API compounds the fidelity loss.
Skills manage context, not just commands
The Skills approach lets the agent load instructions as it needs them.
A CLI with 700+ commands doesn’t present all 700 in the system prompt. The agent starts with --help, discovers the service, runs crm schema opportunities.bulkUpdate, and gets exactly the schema it needs at runtime. It pays the context cost only when the schema is relevant.
Skills extend this further with markdown files containing task-specific documentation, prompt instructions, and CLI usage patterns. Each SKILL.md file is a self-contained unit of agent knowledge:
skills/
├── crm-opportunities/SKILL.md # Core opportunity operations
├── crm-opportunities-advanced/SKILL.md # Custom fields, bulk updates The agent loads crm-opportunities when it needs to manage opportunities. It loads crm-opportunities-advanced only when the task requires bulk updates. The context cost scales with the task, not with the API surface.
MCP doesn’t have this mechanism natively. Every tool definition is loaded upfront. Lowin calls this the “dictionary problem”, where all tool definitions travel with every message. Some clients support enabling and disabling tools, and some are exploring tool search, but these are client-side features, not protocol guarantees. If you’re building an MCP server, you can’t assume the client will be smart about context management.
The layering insight
Another approach is for the MCP server to expose a meta-tool, such as discover_tools or enable_service, that lets the agent dynamically expand its available tool set as the conversation evolves. The agent starts with a minimal surface and pulls in capabilities as needed.
Agent: "I need to work with CRM opportunities"
→ calls discover_tools(service: "opportunities")
→ server registers opportunity tools
→ agent now has opportunity capabilities This isn’t standardized in MCP today, but the ecosystem is converging on it. FastMCP 3.1 recently shipped a two-stage discovery pattern using Search and GetSchemas meta-tools to solve this exact problem. It trades one upfront context cost (all tools loaded at startup) for a small per-request cost (the discover call) plus targeted context (only the tools that matter).
This server-side workaround highlights a growing tension. As MCP clients get smarter about native tool search and selective loading, baking stateful discovery logic into the server may eventually conflict with the client. It’s a delicate balance between helping the agent now and fighting the client later.
The fidelity spectrum
Each approach trades fidelity for accessibility differently:
- MCP (constrained tools): high accessibility, lower fidelity. The agent discovers capabilities through structured definitions. The cost: you can only express what the tool author anticipated.
- MCP (full surface): high fidelity in theory, but the context cost makes it impractical. The agent has access to everything but can reason about almost none of it.
- CLI + Skills: high fidelity, moderate accessibility. The agent navigates
--helpand loads context on demand. The cost: it requires a CLI that was designed for this pattern. - Raw API with client libraries: maximum fidelity, lowest guardrails. The agent writes code directly against the API.
Choose based on what each approach loses and whether that loss matters for your use case.
What this means in practice
A few observations from sitting with this:
The MCP layer is only as good as the API underneath. If the API is hostile to AI agents because of positional indexes, opaque identifiers, or missing capabilities, no amount of MCP abstraction fixes that. The abstraction tax compounds: an unfriendly API wrapped in a lossy protocol is doubly frustrating.
MCP interfaces can evolve faster than APIs. They don’t carry the same stability guarantees. You can ship, learn what agents actually struggle with, and iterate. The fidelity loss is tolerable if the iteration speed is high.
Testing with agents reveals different failure modes than testing with humans. Define a user journey, hand it to an agent with your MCP server enabled, and watch where it breaks. The friction points are often surprising. Agents struggle with things humans find trivial, and breeze through things humans find tedious.
Context management is a shared responsibility. MCP clients are getting smarter through tool search, selective loading, and dynamic registration. Building an overly constrained server to solve a context problem that the client might already handle can leave users frustrated. But assuming the client will be smart about it is also risky.
Frequently Asked Questions
- What is the abstraction tax?
Every layer between the user's intent and the API, including the app, protocol, and tool definition, loses fidelity. MCP adds a layer. That layer costs you expressiveness, and the cost compounds with complex APIs.
- Where does fidelity loss happen with MCP?
Tool signatures either become unwieldy (exposing the full payload) or lossy (hiding it behind simplified abstractions). Neither option preserves the full expressiveness of the underlying API.
- How do skills approach the same problem differently?
Skills are loaded on demand. The agent discovers what it needs at runtime instead of paying the token cost for every tool definition upfront. This shifts the tradeoff from upfront fidelity loss to incremental context cost.
- Is one approach better than the other?
They optimize for different things. MCP optimizes for discoverability and standardization. CLIs with skills optimize for fidelity and flexibility. The interesting question is what each one costs you.