Est.

How MCP Servers Work Internally

Columnist · · 14 min read
Cover illustration for “How MCP Servers Work Internally”
MCP 101 (mcp vs api, mcp servers, spec updates, mcp oauth) · July 29, 2026 · 14 min read · 3,258 words

The autumn of 2024 was a busy season for AI integration tooling. Teams were duct-taping together bespoke connectors between their AI applications and their data sources, and the combinatorial misery of that work was becoming impossible to ignore. Every new tool meant a new auth scheme, a new data format, a new error-handling convention. Multiply that across a growing roster of AI hosts and you had what people were quietly calling the N×M problem: N applications times M tools equals an explosion of point-to-point bridges, each requiring its own custom plumbing.

Anthropic's engineers David Soria Parra and Justin Spahr-Summers had a specific answer. One server per tool, one client per host, and every combination works automatically without custom connectors. They called it the Model Context Protocol, and they shipped it in November 2024 alongside reference servers for GitHub, Slack, Google Drive, Postgres, and Puppeteer. Concrete from day one. The architecture was not speculative; it was solving an enumerable problem.

The critical thing to understand before anything else: MCP is the protocol specification. An MCP server is a process that implements the server side of that spec. The relationship is identical to HTTP and Apache. You don't run HTTP; you run a server that speaks it. Keeping that distinction sharp will make everything else in this piece click into place.

How fast MCP has been adopted, and what that signals about the protocol's staying power

Start with the trajectory, not the endpoint, because the shape of the curve is what tells you something real.

At launch in November 2024, the MCP SDK was pulling roughly two million downloads a month. By April 2025, when OpenAI announced it was adopting the protocol, that number had climbed to 22 million. Microsoft joined in July 2025, and monthly downloads hit 45 million. AWS came aboard in November 2025 and the count reached 68 million. By March 2026, the figure was sitting at 97 million.

React, which most engineers treat as a canonical example of a fast-moving open-source adoption story, took approximately three years to approach 100 million monthly downloads. MCP did it in sixteen months.

The public registry now lists more than 13,000 servers. OpenAI, Google, and Microsoft all ship first-party MCP clients. In December 2025, Anthropic donated the protocol to the Agentic AI Foundation under the Linux Foundation, co-founded with Block and OpenAI, and supported by Google and Microsoft. That governance transfer is architecturally meaningful. It signals that the spec is no longer a vendor protocol; it is an industry standard managed by a neutral body. Anthropic still contributes, but the spec no longer belongs to Anthropic.

Why does any of this matter for a piece about server internals? Because 13,000 servers and 97 million SDK downloads means the design decisions baked into MCP's internal architecture have real operational consequences for a very large number of engineering teams. Understanding the internals is not an academic exercise at this scale. It is a prerequisite for building things that hold up.

Diagram: MCP Adoption vs. React: 16 Months to 97 Million Downloads. Visualizes: Show the download trajectory of the MCP SDK against the React benchmark, using five labeled milestones: November 2024 launch (~2M/month), April 2025 OpenAI adoption…

The three-role architecture: host, client, and server, and how they divide responsibility

There are three participants in any MCP interaction, and each has a non-negotiable role.

The host is the AI application the end user actually interacts with. Claude Desktop is a host. VS Code with Copilot is a host. Cursor is a host. The host is what sits in front of the human.

The client lives inside the host and manages the connection to a specific MCP server. Each client connects to exactly one server. This is not a limitation; it is a deliberate design choice. The 1:1 client-to-server relationship keeps the protocol clean and makes fault isolation tractable.

The server is the process that implements the server side of the spec and exposes capabilities. Each server encapsulates a single domain responsibility. Your file system server doesn't know about your database, and your database server doesn't know about your GitHub integration. Modularity is structural here, enforced by the architecture, not left to the discretion of individual developers.

The separation of host, client, and server is the mechanism by which the N×M problem collapses. Capability discovery and invocation happen through the protocol. Custom integration code is no longer required for each new combination. A new server that correctly implements the spec is immediately usable by any compliant host, without modification on either side. But what if a server only partially implements the spec? Does it still interoperate, or does the whole chain break? That edge case is worth keeping in mind as you build.

Hold on the primitives for a moment. Those come next. This section is about roles and boundaries, and the boundaries are what make the rest possible.

The two-layer internal structure of a server: data layer and transport layer

Most descriptions of MCP conflate two things that are distinct, and the conflation causes confusion when you start debugging or optimizing. Inside every MCP server there are two layers. The data layer is the inner layer: what is being communicated. The transport layer is the outer layer: how it physically moves. Keep those separate conceptually and the server's internals become much more legible.

The data layer

The data layer runs on JSON-RPC 2.0. Clients and servers exchange requests and responses; notifications are used when no response is required. The canonical source of truth for all protocol definitions is the TypeScript schema file, schema.ts. JSON Schema documentation and everything else derives from it. If you want to know exactly what the protocol permits, that file is the answer.

The data layer is where lifecycle management lives, and it is where the core primitives are defined. The transport layer doesn't know what a tool is. The data layer does.

The transport layer

The transport layer is negotiated based on deployment context, and the two current options represent a real architectural fork.

stdio is the local transport. The server is launched as a child process. Requests arrive on stdin, responses leave on stdout, log lines go to stderr. There is zero network setup. It is single-tenant by nature. This is the right choice for developer tooling, local agents, and any scenario where the server runs on the same machine as the host.

Streamable HTTP is the remote transport. A single HTTP endpoint handles bidirectional streaming and is designed for serverless and load-balanced deployments. Authentication runs over OAuth 2.1 with PKCE. This is the right choice for production, multi-tenant, horizontally scaled deployments.

It is also worth considering what the numbers actually tell you here: on a representative 2026 stack, stdio transport adds roughly 8 to 12 milliseconds of overhead per call. Streamable HTTP on a VPS runs 40 to 70 milliseconds, but almost all of that latency is network round-trip, not protocol cost. The protocol itself is not the bottleneck in the remote case. The performance gap is a correct signal for choosing between deployment modes, not evidence of a flaw.

The older HTTP+SSE transport from the original November 2024 spec was deprecated on March 26, 2025. If you're reading documentation that mentions it as current, the documentation is out of date.

Venn diagram: MCP Transport Layers: stdio vs. Streamable HTTP. Compares stdio Transport and Streamable HTTP; overlap: Shared Foundation.

The three primitives a server exposes, and what distinguishes them from each other

Table: The Three MCP Primitives Compared. Compares Control Model, Nature, Invocation, Examples, and 1 more by Tools, Resources and Prompts.

The sharpest way to distinguish the three primitives is by their control model. Who decides when each one is used?

Tools are model-controlled. The AI decides when to invoke them based on context. The user does not push a button; the model determines that a tool call is warranted and makes it.

Resources are application-controlled. The application makes them available for the AI to reference. They are not autonomously invoked; they are surfaced and then consulted.

Prompts are user-controlled. They are workflow packages that structure how the model is invoked, initiated by the user rather than autonomously triggered.

Control model first. Everything else follows from that.

Tools

Tools are executable functions: file operations, API calls, database queries. Each is defined with a JSON Schema describing its inputs. Since the June 18, 2025 spec update, tools can also declare structured output and return resource links, which makes chained workflows considerably more tractable.

Tools are what most MCP demos show, and they are also where most of the attack surface lives. Keep that in the back of your mind; we'll get to it.

Resources

Resources are read-only data sources. File contents, database schemas, API responses. Each is identified by a unique URI. They are not invoked autonomously; the application surfaces them and the model references them.

The distinction between resources and tools has a practical implication for access control. Resources are pull: the model reads from them when pointed at them. Tools are push: the model initiates an action. That asymmetry matters when you are designing permission boundaries.

Prompts

Prompts are reusable templates: system prompts, few-shot examples, workflow starters. Most SDKs implement them as simple message lists. The gap between what prompts could theoretically be, genuine workflow packages with data flow between steps, and what most implementations actually do, which is serve as message templates, is worth naming plainly. The abstraction exists. The ecosystem has not fully built into it yet.

All three primitive types support a consistent pattern: discovery via list endpoints, retrieval via get endpoints, and where applicable, execution. That consistency is not accidental; it makes building generic clients tractable.

A final note here: servers can also use capabilities the client exposes back to them. Sampling lets the server ask the model to generate text. Elicitation, added in the June 2025 spec, lets the server request user input. Roots let the server learn which directories it is permitted to operate on. The protocol is bidirectional in ways that are easy to miss if you only think about the client calling the server.

How a session is established, operated, and closed across three lifecycle phases

A session has three phases: Initialization, Operation, and Shutdown. These are a temporal sequence, not interchangeable stages. What happens in each phase is constrained by what happened in the one before it.

Initialization

The client and server begin by agreeing on the highest mutually supported protocol version. Then both sides advertise their optional features: sampling, prompts, tools, logging. The client sends a notifications/initialized signal after receiving the server's initialize response.

That signal matters more than it might appear. Per the MCP specification, servers must not send requests before receiving it. Clients must not send requests other than pings before receiving the initialize response. The handshake is not ceremonial; it is a hard constraint on what is legally permissible in the session. What gets negotiated in initialization governs what is valid for the entire session's duration. Parties must not invoke features they didn't agree upon.

Operation

Once initialization is complete, bidirectional message flow begins. The client may call tools/list; the server may initiate sampling or elicitation if those capabilities were negotiated. Version and capability negotiation do not repeat. Every subsequent JSON-RPC call is compact and faster for the absence of that overhead.

Persistent session handles for roots, tools, and resources allow incremental notifications. The server can stream only what changes rather than retransmitting full state. This is an important efficiency property for long-running agentic workflows.

Shutdown

There are no specific protocol messages required to close a session. The client or server closes the underlying transport, and the session ends. The simplicity is intentional. Graceful termination does not need ceremony, and adding it would only introduce failure modes.

The lifecycle design is what makes MCP stateful, and that statefulness is why the next architectural shift represents a meaningful departure.

The protocol's move from stateful sessions toward stateless horizontal scaling

Here is the current operational reality: MCP is a stateful protocol. Servers maintain session state. That works extremely well for local deployments and single-instance servers. It becomes a ceiling when you try to deploy behind a load balancer, because the load balancer has no guarantee that any given request will reach the server instance that holds the relevant session state.

The July 28, 2026 release candidate addresses this directly. Six Specification Enhancement Proposals work in concert to move statefulness out of the protocol layer. The new spec standardizes session creation, resumption, and migration, so that server restarts and horizontal scale-out events become transparent to connected clients.

The operational implication is significant. A stateful server that cannot scale horizontally is a hard ceiling on enterprise deployment. Removing that constraint changes what MCP can realistically do at scale.

Two caveats are worth stating plainly. First, as of the time this piece was written, that transition is a release candidate, not a shipped spec. The operational reality for most deployed MCP infrastructure is still stateful. Second, the move toward statelessness changes the security surface in ways worth flagging. Session resumption and migration introduce new questions about identity continuity: if a session can migrate, what guarantees that the entity resuming it is the same entity that initiated it? That question points forward to the authentication section.

How MCP handles authentication and authorization, and how the model has matured

The pivotal change in the June 18, 2025 spec revision was architectural, not incremental. MCP servers are now defined as OAuth Resource Servers, not Authorization Servers. The distinction is consequential. Servers consume access tokens issued by existing identity providers, Auth0, Okta, whatever an enterprise already runs, rather than issuing their own. MCP plugged itself into established enterprise identity infrastructure instead of trying to replace it. That is the correct call. Novel security models are a liability; alignment with established patterns is an asset.

November 2025 additions to the spec built on that foundation: OAuth 2.1 with PKCE, Protected Resource Metadata discovery per RFC 9728, and OpenID Connect support for authorization server resolution. The protocol now has a coherent, standards-aligned identity story.

The other significant design choice is incremental scope negotiation. Permissions are granted only when a workflow actually requires them, not in a single broad approval step at install time. This is zero trust applied to agent authorization, and it makes role-based access control for agents meaningful in a way that bulk upfront permissions never could. Access decisions are made intentionally, at the moment they are needed.

The maturation of the auth model is real progress. One might argue, though, that spec correctness and deployment security are two entirely different problems — and the gap between them is where the vulnerabilities in the next section actually live. The spec can be correct and the deployment can still be insecure.

The attack surface that opens when MCP servers are deployed without proper controls

Researchers disclosed more than 30 MCP-related CVEs in the first four months of 2026, including a CVSS 9.6 remote code execution vulnerability in mcp-remote. A 2025 audit by Invariant Labs found that 43% of early MCP servers contained command injection vulnerabilities. The server runs with the user's permissions, so a compromised tool does not just access the server; it accesses everything the user can access.

These are not exotic research scenarios. They are practical deployment risks.

Tool poisoning

Tool poisoning is the attack vector that most directly exploits MCP's internal architecture. Malicious instructions are embedded in tool metadata, specifically in descriptions and parameter definitions, rather than in user inputs. The attack surface is the client-server trust model itself. Clients receive tool definitions from the server, and most pass them to the model without any sanitization.

CVE-2025-54136 and CVE-2025-54135 (MCPoison and CurXecute, respectively) demonstrated this concretely: an attacker who controls a server can write directives into descriptors that the agent then hands to its model, with the agent's full ambient authority. Empirical testing found that five out of seven evaluated clients do not implement static validation of server-provided metadata. The gap is in clients as much as in servers.

Silent redefinition

MCP tools can mutate their own definitions after installation. A tool approved as benign on day one can quietly reroute API keys by day seven. There is no built-in mechanism in the base spec to alert a user or an administrator that a tool's definition has changed. This is sometimes called a rug pull, and it is a governance problem as much as a security problem. You cannot audit what you are not tracking.

Multi-agent contagion

In chained agentic workflows, one agent's output becomes another agent's input. Prompt injections can propagate across MCP processes, enabling data exfiltration or control-flow hijacking without any single point of obvious failure. No individual server looks obviously compromised. The attack distributes itself across the chain.

The structural point beneath all of this: an ungoverned MCP server is an identity the organization cannot account for. An identity no one is tracking is the one that gets exploited. The protocol's security model is sound at the spec level. The operational risk lives in deployment decisions, specifically in the absence of the governance infrastructure described next.

What governance infrastructure looks like in practice for teams running MCP at scale

The teams managing MCP deployments effectively tend to share a common operational posture. It is not complicated in principle, though it requires discipline to sustain.

The foundation is a server registry. Every MCP server in the environment, whether built internally or sourced from the public registry, should be enumerated. Name, version, declared capabilities, owning team, last-reviewed date. If you cannot enumerate your servers, you cannot govern them. This is the inventory problem, and it precedes everything else.

Registries alone are insufficient without a gateway layer. An MCP gateway sits between hosts and servers and enforces policy centrally: which tools a given agent is permitted to call, which resources it may read, which scopes were actually granted versus which were requested. Gateways are also where you catch the silent redefinition problem. If a tool's schema changes, the gateway is the choke point where that change can be detected, logged, and held for review before it reaches a production agent.

Tool definitions, including names, descriptions, and parameter schemas, should be treated as artifacts subject to version control and change review. If the definition can change the behavior of an AI agent in production, it deserves the same scrutiny as code. The teams that have had tool poisoning problems are nearly uniform in having treated tool metadata as configuration rather than code.

For multi-agent deployments specifically, the audit trail requirements are qualitatively different from single-agent scenarios. When a prompt injection propagates across three agents, you need to be able to reconstruct the full call chain. That means structured logging at the gateway layer, not just at the application layer, with enough context to trace a single artifact from ingestion through every MCP process it touched.

Incremental scope negotiation, which the spec now supports, gives teams the mechanism to implement least-privilege access at the workflow level rather than the installation level. Use it. The permission model is only as tight as you configure it to be. Broad scopes granted at install time are a residue of the old pre-June-2025 auth model; there is no longer a technical justification for them.

Finally: treat the public registry as a dependency ecosystem, with the same skepticism you would apply to any open-source dependency. Thirteen thousand servers is a large surface, and the quality and security posture across them is not uniform. A registry entry is not an endorsement. Audit before you adopt, pin versions, and have a process for responding when a CVE drops against a server you are running.

The governance work is not glamorous. It is also not optional at scale. The protocol's adoption trajectory means that MCP infrastructure is now, for many organizations, as operationally critical as their database layer. The internal architecture makes that infrastructure powerful. The governance layer is what makes it trustworthy.

Sources

  1. modelcontextprotocol.io

More in MCP 101 (mcp vs api, mcp servers, spec updates, mcp oauth)