I ended up writing an MCP server — one that gives coding agents indexed code navigation instead of grep — and building it clarified what MCP actually is, past the hype. It is not an AI breakthrough; it’s a protocol standard, and it solves a problem every integration engineer will recognize instantly: the M×N glue explosion. Announced by Anthropic in late 2024 and broadly adopted through 2025, MCP is best understood by systems people as “an interface standard for capabilities,” and it earns the analogy it’s usually given: USB-C for AI tools.
The Problem It Solves Is Old
You have M AI applications (Claude Desktop, Cursor, your custom agent) and N tools/data sources (GitHub, a database, a filesystem, an internal API). Without a standard, wiring them together is M×N bespoke integrations — every app reimplements every tool connection, in its own format, and a new tool must be re-integrated everywhere. This is the exact shape of problems that standards have always dissolved: ODBC for databases, LSP for editor/language-server pairs (the closest analogy — LSP turned M editors × N languages into M+N), POSIX for OS calls. MCP turns M×N into M+N: each app implements an MCP client once, each tool exposes an MCP server once, and any client talks to any server.
flowchart LR
subgraph Clients
A[Claude Desktop]
B[Cursor]
C[custom agent]
end
subgraph Servers
D[filesystem]
E[GitHub]
F[gtags / code nav]
end
A & B & C <--> H((MCP)) <--> D & E & FThe Design Is Boring, Which Is the Point
MCP is a client-server protocol over JSON-RPC 2.0 — deliberately unexciting, standing on proven ground. The host application runs clients; each client connects to a server that exposes capabilities. Transports are the familiar two: stdio (the server is a local subprocess — how my code-nav server runs, zero network surface) and HTTP with Server-Sent Events for streaming (remote/hosted servers). Nothing here is novel, and that’s the correct instinct for a standard: novelty is a liability when you want universal adoption.
Servers offer three kinds of things, and the distinction is cleaner than it first looks:
- Tools — model-callable functions with JSON-Schema’d arguments
(
search_code,run_query). These are the actions; they map exactly onto the “capability table” of the agent loop. The model discovers available tools at connect time and decides when to call them. - Resources — readable data the app can pull into context (a file, a record, a query result), addressed by URI. Application-controlled context, not model-invoked actions.
- Prompts — reusable templates a server offers to the user/app.
The important architectural property, and the reason it’s genuinely a protocol and not just a plugin format: discovery is dynamic. A client connects, asks “what do you offer?”, and gets a live schema — so tools can appear, disappear, and update without the client knowing anything in advance. That’s what makes it composable the way USB or LSP are: you plug in a new server and existing clients can use it immediately.
What It Means, and What to Watch
For anyone building agents, MCP changes the unit of work: instead of hardcoding tool integrations into one app, you write a server once and every MCP-speaking client gains the capability. My code-navigation server works in Claude Code, Cursor, and anything else that speaks the protocol, with no per-client code — that reuse is the whole value proposition, and it’s the same win LSP delivered to language tooling.
The systems engineer’s caution is the same one every integration standard carries, only sharper because a model is the caller: each MCP server is code executing with real permissions, invoked with arguments an LLM generated from untrusted context. Prompt injection in a document the model read can become a tool call you didn’t intend — so servers must treat arguments as hostile (validate, scope, least- privilege), the transport and auth story for remote servers matters (this tightened notably through 2025 as adoption grew), and “give the agent this MCP server” is a permission-granting decision, not a convenience toggle. Standardizing the port doesn’t remove the trust boundary; it makes it uniform, which is progress precisely because a uniform boundary is one you can actually reason about and secure — the same reason we prefer one well-understood syscall interface to a hundred bespoke ones.
Takeaways
- MCP solves the M×N integration explosion the way ODBC/LSP/POSIX did: one client per app, one server per tool, any-to-any — M+N.
- It’s a deliberately boring JSON-RPC client-server protocol over stdio or HTTP+SSE; boring is correct for a standard.
- Servers expose tools (model-callable actions = the agent’s capability table), resources (app-pulled context by URI), and prompts — with dynamic discovery at connect time, which is what makes it composable.
- Write a server once, gain the capability in every MCP client — the reuse is the point (I run one code-nav server across multiple agents).
- Each server is privileged code called with LLM-generated arguments from untrusted context: validate and scope everything — MCP standardizes the trust boundary, it doesn’t remove it.