Guide · October 14, 2026 · 12 min read

MCP server architecture for the enterprise.

The protocol went stateless in the 2026-07-28 revision. That single change decides how many servers you run, where authorization lives, and which of the nine named attack classes you inherit.

The short answer

Enterprise MCP server architecture comes down to three decisions. Keep the server stateless — the 2026-07-28 spec now makes this the default, so any instance can answer any request and an ordinary load balancer is enough. Draw one server per data domain rather than one gateway over everything, so each server holds exactly one scoped credential and its tool list is a readable inventory. Put authorization in the server, never in the model, because six of the nine attack classes in the official security spec are identity problems, not prompting problems.

What MCP server architecture means

MCP server architecture is the set of decisions about what a server is allowed to reach, how many servers you run, and where state lives. It is not the code inside a tool handler. Two teams can write identical handlers and end up with completely different risk profiles depending on how they answered those three questions.

The reason the architecture carries the weight is that the model is not a trust boundary. An MCP server exposes tools a model can call, and the data those tools return lands in the model's context where it will be acted on. So every control that matters has to live on the server side of that line. If the concept is new, start with what is an MCP server, then come back for the design.

The stateless core, and what it cost

The 2026-07-28 revision of the specification is the one that matters for architecture, because it removed the machinery that made MCP servers stateful. Three removals, one addition.

Sessions are gone

SEP-2567 removed sessions and the Mcp-Session-Id header. The practical consequence is a deployment one: there is no sticky routing to arrange and no shared session store to run. A stateless server sits behind an ordinary load balancer, which is what running on normal enterprise infrastructure actually requires. Before this, every horizontally scaled MCP deployment needed an answer to "where does the session live," and every answer was additional infrastructure to secure.

The initialize handshake is gone

SEP-2575 removed the initialize round trip. Protocol version now travels per-request inside _meta as io.modelcontextprotocol/protocolVersion, and server/discover is mandatory for capability discovery. Every request is now self-describing, which is what makes the stateless property hold rather than just being claimed.

SSE resumability is gone, and this one is a trap

This is the removal that breaks working code quietly. Resumability went with sessions, so a dropped stream loses the in-flight request outright. The client MUST re-issue it with a new request ID. The HTTP GET stream is replaced by subscriptions/listen.

Architecturally this means long-running tool calls need a different shape. If a tool takes ninety seconds and the connection is fragile, you cannot lean on the transport to carry you through. The replacement is Multi Round-Trip Requests and InputRequiredResult (SEP-2322) for anything that needs to pause and come back, with long-running task semantics moved out into an extension (SEP-2663). Design for re-issue, and make tool calls idempotent so a re-issue is safe.

CacheableResult replaces the session as the performance lever

Losing sessions means losing the obvious place to keep warm data. SEP-2549 answers it with CacheableResult, carrying ttlMs and cacheScope. Read that second field carefully before you ship: cache scope is an authorization decision wearing a performance costume. A result cached more broadly than the permission that produced it is a data leak with good latency.

One server per data domain

The most consequential architecture decision is how many servers you run and where you cut between them. The default instinct is one server, because one deployment is less work. It is the wrong answer, and the reason is credentials.

Why the boundary belongs at the data domain

A server needs a credential to reach the system behind it. If one server fronts every system, it holds a credential broad enough to reach every system, and no amount of per-tool logic inside it changes what an attacker gets on compromise. Cut at the data domain instead and each server holds exactly one narrow credential. The blast radius of a compromise becomes the domain, not the estate.

Three properties follow, and they are the actual argument:

  • The tool list becomes an audit artifact. "What can our AI reach?" has a finite answer someone can read in one sitting: the servers, and their declared tools. A single gateway with sixty tools does not have that property even though the information is technically present.
  • Scope minimization becomes structural. The security spec asks for minimal scopes. With a server per domain, the minimal scope is the default outcome of the deployment boundary rather than a rule someone has to remember to apply.
  • Independent lifecycle. One domain's server can be scaled, rolled back, or taken offline during an incident without removing the AI's access to everything else. With a gateway, every incident is a total outage.

Where the per-domain pattern costs you

Honest accounting: ten servers is ten deployments, ten sets of logs, and ten things to patch when the spec moves. The pattern only pays if the servers are near-identical in shape — same framework, same filter contract, same transport, differing only in the index or table they query and the credential they hold. If each one is bespoke, you have traded one auditable risk for ten unmaintainable ones. Uniformity is the thing that makes the multiplication affordable, which is why the boundary is worth deciding once, up front, and then not relitigating per domain.

The comparison against the alternative integration style is worked through separately in MCP servers vs custom API integration.

The nine attack classes the design answers

The official MCP security specification names nine attack classes. Read the list by category and the architectural point lands immediately: six of the nine are identity and token problems. They are not model behaviour problems, they are not solved by better prompting, and they existed in OAuth deployments for a decade before MCP. That is good news — the controls are known — but it means the work sits in the authorization design, not in the tool handlers.

The nine attack classes named in the MCP security specification, by category.
Attack classCategoryWhat it is
Confused deputyIdentityThe server uses its own privileged credential on behalf of a caller who does not hold that privilege.
Token passthroughIdentityA token minted for one audience is forwarded to another. RFC 9068 audience validation is the control.
Authorization server mix-upIdentityThe client is steered to the wrong authorization server and hands it a code or token.
State handle hijackingIdentityNew, and a direct consequence of statelessness: once the client carries the state, the handle becomes the target.
OAuth redirect URL validationIdentityLoose redirect_uri matching lets an attacker receive the authorization code.
Localhost redirect impersonationIdentityA local listener claims a loopback redirect that belongs to another client.
Server-side request forgeryNetworkA tool that fetches a caller-supplied URL becomes a probe into your internal network.
stdio in proxy scenariosTransportA stdio server fronted by a proxy inherits the proxy's reachability without inheriting its authentication.
Local server compromiseHostA server running on a developer machine holds real credentials in an environment nobody hardened.

State handle hijacking is the one statelessness created

Eight of the nine predate the stateless revision. State handle hijacking does not, and it is the direct cost of the change: when the server stops holding state, the client has to carry it, and whatever the client carries becomes a target. Treat a state handle as a bearer credential — bind it to the caller, keep its lifetime short, and never let it be the only thing standing between a request and a privileged operation.

The controls the spec actually asks for

The hardening side is specific rather than aspirational. RFC 9207 authorization server issuer identification lands via SEP-2468, with further OAuth hardening in SEP-837 and SEP-2352. Audience validation per RFC 9068 is the control for token passthrough. Mcp-Method and Mcp-Name headers (SEP-2243) make requests legible to the infrastructure in front of the server, so a WAF or gateway can reason about an MCP call without parsing the body. And client ID metadata document trust policies decide which clients you will talk to at all.

The prompt-injection and tool-scope side of the threat model — the part that is about what the model does with what a tool returns — is covered in MCP server security, and the review we run against a deployed server is MCP security.

Versioning against a 12-month window

The protocol publishes its own deprecation policy: twelve months' notice before a feature is removed, with a ninety-day expedited exception reserved for security issues. Both numbers are architecture inputs.

Twelve months means an annual review cadence is sufficient for ordinary change. Ninety days means it is not sufficient for security change, and that is the constraint that bites. If your protocol version is a constant compiled into a client and shipped through a quarterly release train, a ninety-day expedited removal is an incident. Make the protocol version a deployable value, keep the client's version negotiation in configuration, and the expedited case becomes a config change instead of a release.

The 2026-07-28 revision is itself the worked example. Teams that had session handling spread across client code, load balancer config, and a Redis instance did not get to adopt it on a config change.

What this looks like in production

We run this pattern on client work. On Optevo it is ten production MCP servers, one per data domain, deployed over ninety days. The number is not the interesting part — the interesting part is that ten was the count of data domains, not a target. The boundary decision produced the number.

If you are making the same decisions now, the three that are hard to reverse are: where the domain boundary falls, whether the protocol version is deployable, and whether cache scope is reviewed as an authorization decision. Everything else is a refactor. Those three are migrations.

We design and build these servers as MCP server development engagements, and review existing ones through MCP integration consulting.

Frequently asked questions

What is MCP server architecture?

MCP server architecture is how you decide what an MCP server is allowed to reach, how many servers you run, and where state lives. In the enterprise pattern it comes down to three decisions: keep the server stateless so any instance can answer any request, draw one server per data domain rather than one gateway over everything, and make the server, not the model, the thing that enforces authorization. As of the 2026-07-28 revision the protocol itself is stateless by default, so the first decision is now the spec's default rather than a design choice.

Should you run one MCP server or many?

Many, with the boundary at the data domain. One server per domain means each server holds exactly one scoped credential, its tool list is a readable inventory of what the AI can reach, a compromised server exposes one domain instead of all of them, and each can be scaled or taken down independently. A single gateway inverts all four: one credential broad enough for everything, a tool surface nobody can audit in one sitting, and total exposure on one compromise.

Why is the MCP spec stateless now?

The 2026-07-28 revision removed sessions and the Mcp-Session-Id header (SEP-2567) and removed the initialize handshake (SEP-2575), so protocol version is carried per-request in _meta instead. The practical reason is deployment: a stateless server can sit behind an ordinary load balancer with no sticky routing and no shared session store, which is what running it on normal enterprise infrastructure requires. The cost is that SSE resumability went with it, so a dropped stream loses the in-flight request and the client must re-issue it with a new request ID.

What are the main MCP server architecture risks?

The official security specification names nine attack classes: the confused deputy, token passthrough, server-side request forgery, state handle hijacking, local server compromise, OAuth redirect URL validation failures, stdio exposure in proxy scenarios, authorization server mix-up, and localhost redirect impersonation. State handle hijacking is the newest and is a direct consequence of statelessness: once the client carries the state, the handle it carries becomes a target. Most of the remaining eight are identity and token problems, not model problems, which is why they are architecture decisions rather than prompt decisions.

How do you version an enterprise MCP server?

Plan against the protocol's own deprecation window: features get twelve months' notice before removal, with a ninety-day expedited exception reserved for security issues. That means a yearly review cadence is enough for ordinary changes but not for security ones, so the architecture needs a path to ship a breaking protocol change inside ninety days. In practice that means the protocol version is a deployable value, not a constant compiled into the client.

Stay ahead on enterprise AI

Receive our latest insights on knowledge graphs, GraphRAG, and production AI agents—directly in your Google Search, before they go wide.