PILLAR · ARCHITECT

MCP Architecture for Builders: Design Patterns That Survive Production

Model Context Protocol turned ad-hoc AI tool integration into a standard. Here's how to architect MCP servers that actually scale — five design patterns, seven failure modes, and the 2026 roadmap implications.

· by Pavel Kiyatkin

MCP turned ad-hoc AI tool integration into a standard. The question stopped being “can I connect this tool to that model?” and became “how do I architect MCP servers that hold up under real load?”

Most MCP content right now is “what is MCP” tutorials. That’s not what this is. This is for builders who have already wired up their first MCP server, run into the wall, and need a design system — not another walkthrough.

If you’re shipping AI features behind a UI, integrating LLM workflows into an existing codebase, or running your own AI-augmented operations as a solo founder, MCP is no longer optional infrastructure. It’s the connective tissue. The question is whether you architect it deliberately or pile up servers like browser tabs until your agents drown in 40-tool soup.

This pillar covers the architecture — strategic shift, five components, real-world patterns, five design patterns that work, seven failure modes that kill MCP servers, security baseline, stack choices, what’s coming in the 2026 roadmap, and when MCP is the wrong abstraction. By the end you’ll have a mental model for designing MCP-integrated systems that don’t fall over.

The strategic shift MCP represents

For two years before MCP existed, every AI integration was a snowflake. Want ChatGPT to query your Postgres? Custom function calling. Want Claude to read your Linear issues? Different custom code. Want an LLM in your codebase to commit and push? You wrote a wrapper, and the wrapper was bound to that one model’s tool-use format.

When Anthropic released MCP in November 2024, they framed it as “USB-C for AI applications.” That framing is closer to the truth than the marketing usually gets: MCP is a port that any compliant model can plug into and any compliant tool can expose. The model doesn’t need to know how Postgres works. The Postgres server doesn’t need to know which model is calling it. Both speak JSON-RPC 2.0 over a defined transport, and the host application — Claude Code, Cursor, your custom agent — brokers between them.

The shift isn’t “a better way to call tools.” The shift is “tools and models are now decoupled.” You write your knowledge base MCP server once and it works with Claude, with OpenAI’s Apps SDK clients, with Cursor, with Cline, with whatever editor or agent ships next year. You build your operator stack as a fleet of small MCP servers — each one a capability surface — and you swap models behind them without rewiring anything.

For builders this means three things. First, the architectural unit of an AI feature is no longer “the function call” but “the MCP server.” You design at the surface level, not at the model level. Second, your AI stack becomes composable in a way that ad-hoc API wrappers never were. Third, the design quality of your MCP servers becomes the gating factor for whether your AI system actually works — because LLMs route tool calls through descriptions, and bad descriptions kill performance more than bad models.

That third point is where most builders trip. They treat MCP like a REST API wrapper. It isn’t. MCP is a user interface for agents. The user is an LLM, not a human, but the principles of good UI still apply: clarity, predictability, restraint, well-chosen labels. Bad MCP design isn’t a performance problem; it’s a usability problem for your agent.

The architecture in five components

Every MCP integration has the same five-component anatomy. If you can name each one and describe the contract between them, you understand the protocol.

Host application. This is the thing the human uses — Claude Code, Cursor, ChatGPT desktop, your custom agent runtime. The host owns the model session, the conversation state, and the permission boundary. It decides which MCP servers to connect to, when to invoke their tools, and how their outputs flow back into the model’s context.

Client. Each MCP server connection gets its own client instance inside the host. This is critical for isolation. If you have three MCP servers connected (filesystem, Slack, your custom CRM server), you have three client instances, each maintaining a stateful JSON-RPC channel with one server. Clients are sandboxed from each other — a misbehaving Slack server can’t corrupt the filesystem client’s state.

Server. The capability provider. A server exposes some combination of tools (actions the model can take), resources (data the model can read), and prompts (templated instructions the host can offer to the user). A well-architected server has a single area of concern — “Slack workspace,” “PostgreSQL database,” “GitHub repository” — not “general utility kitchen sink.”

Transport. How the bytes move between client and server. The two options as of mid-2026 are stdio (the server is a subprocess of the host, communicating over its stdin/stdout pipes) and streamable HTTP (the server runs as a remote service, the client makes HTTP requests with streaming responses). The original SSE transport was deprecated in the November 2025 spec revision. Streamable HTTP achieved 95% latency reduction over SSE in MCP v2.1 benchmarks. Use streamable HTTP for remote servers, stdio for local subprocesses.

Capability layer. The contract above the transport. A server declares what it offers (tool list, resource list, prompt list) at handshake time. The client knows what to ask for; the model knows what’s available. The capability layer is also where descriptions live — and we’ll come back to descriptions, because they make or break the whole system.

Diagram-shaped mental model: one host, multiple clients (one per server), each client paired with one server over one transport, and each server publishing a capability list. Everything else is plumbing.

Real world: how I architect MCP servers in my operator stack

I run a multi-brand operation as one person plus AI agents. The connective tissue is a personal cognitive infrastructure with MCP at its core. Not Claude-Code-with-everything — Claude Code is one host, my agents reach into a different host, and they share access to a curated fleet of MCP servers I own.

I’m not going to walk you through the internals; that’s not the point of this pillar. The point is the design decisions I made and why. You can borrow the decisions even without seeing the full stack.

Decision 1: Separate servers per concern, not per tool. I don’t have one big “operations” MCP server. I have a content server (drafts, publishing, repos), a memory server (knowledge graph queries, capture), an infra server (Cloudflare, Hostinger, monitoring), a metrics server (analytics reads). Each one stays under 8 tools. If a server creeps past 10 tools, that’s the signal to split it. Smaller servers mean cleaner descriptions and less context bloat in the model.

Decision 2: Stdio for personal, HTTP for shared. Servers that only my agents use run as local stdio subprocesses. Servers that I want to share across hosts (Claude Code, my custom agent, sometimes Cursor) run as remote HTTP services behind an auth layer. The stdio servers are faster and simpler. The HTTP servers are deployable and reachable from anywhere.

Decision 3: Stateless servers by default. Every server I write is designed so the process can die and respawn without losing anything important. State lives in the underlying systems (Postgres, the filesystem, the API the server is wrapping). The server itself holds only transient session metadata. This becomes critical when the 2026 MCP roadmap’s stateless operation push becomes the dominant pattern — you’re already aligned with it.

Decision 4: Tool descriptions are first-class deliverables. I write tool descriptions the way I’d write API docs for paying customers. Each description answers: what does it do, when should the model reach for it, what does it return, what does it cost (token-wise or otherwise). I revisit descriptions every few months because bad descriptions degrade agent performance more than bad models do. When in doubt, I delete a tool rather than ship a weakly-described one.

Decision 5: Project-scoped servers checked into version control. For anything tied to a specific project, the MCP config lives in a .mcp.json at the project root. Anyone (or any agent) cloning the repo gets the same server set. This isn’t novel — it’s what Claude Code’s project-scoped MCP feature was built for — but a lot of builders skip it and end up with servers configured in random user-level shells that nobody else can reproduce.

If you take one thing from this section: the design unit is the server boundary, not the tool. Pick the right boundary and the rest is mechanical. Pick the wrong boundary and you’ll be untangling 40-tool spaghetti for the next six months.

Five design patterns that actually work

The five patterns below are what survives contact with real workloads. There are more patterns in the wild, but these are the ones I keep returning to and the ones that show up consistently in serious production MCP deployments.

Pattern 1: Single agent, multiple narrow servers

The default for most builders. One AI agent (the host) connects to multiple MCP servers, each with a small focused tool set. The agent decides which server to call based on tool descriptions and the task at hand.

This works when your tools are conceptually distinct (filesystem ≠ database ≠ communication ≠ deployment) and the agent doesn’t need to coordinate between them in complex ways. It scales to perhaps 4-6 servers with 5-10 tools each before tool description bloat starts hurting performance.

Trade-off: simple, predictable, but the agent does all the reasoning. If your task needs strict orchestration, this pattern leaks.

Pattern 2: Project-scoped server fleet

The .mcp.json pattern. Each project (codebase, content site, business unit) declares its own server fleet checked into version control. When you open the project in Claude Code or your agent, it loads that fleet. Switch projects, switch fleets.

This is how you avoid the “why is my AI trying to query the wrong database?” problem when you work across multiple codebases. Each project carries its own AI context.

Trade-off: requires discipline to maintain the .mcp.json files. Pays off enormously when you have 5+ projects.

Pattern 3: Multi-agent with shared servers

When a single agent is too overloaded, split work across specialized agents. Each agent has its own host instance, but they share access to the same fleet of MCP servers. The servers don’t know which agent is calling them; they just respond to JSON-RPC requests.

A research agent and a writing agent might both connect to the same knowledge-base server, but only the writing agent connects to the publishing server. The publishing server’s auth layer enforces that.

Trade-off: more moving parts, but each agent stays focused. Useful when one agent’s context window is being drowned by tools meant for a different role.

Pattern 4: Identity-propagating server

A Hugging Face paper from March 2026 on production MCP identifies identity propagation as one of three missing protocol primitives — the original spec doesn’t have a clean way to pass the human user’s identity through the MCP layer. If you’re building MCP servers that act on behalf of a specific user (creating files in their Drive, posting to their Slack), you need to layer in identity propagation yourself.

The pattern: the host passes a user identity token at session initialization (or per-call via metadata). The server validates the token and uses it when calling downstream APIs. This is what OAuth 2.1 with PKCE buys you — the user’s authority gets propagated to the underlying systems, so the audit log shows the human, not the agent.

Trade-off: more setup, but mandatory if your server touches anything user-specific in a multi-user environment.

Pattern 5: Tool-budget-aware server

Token budgets are real. A server that returns 50KB of JSON per call eats your context window. A server that returns 500 bytes scales. The pattern: design tools to return minimum-useful responses, and add pagination or summarization to the server (not push it onto the agent). The agent should not be doing pagination logic for every tool call.

A list-issues tool that returns all 300 open issues is broken. A list-issues tool that returns the first 20 with a next_cursor and a “call again with cursor X to get more” hint is well-designed. The model can decide whether to keep paginating; you saved 280 issues worth of tokens.

Trade-off: more thinking up front, but every token saved here is a token your agent can spend on actual reasoning.

Seven mistakes that kill your MCP server

These are the failure modes I see most often. Some are technical, some are design — both kinds equally fatal.

1. Stdout pollution

If your server uses stdio transport, stdout is the protocol channel. Every byte written there must be valid JSON-RPC. A stray print() statement, a logger that forgot to redirect, a stray traceback — all of them corrupt the stream and your client disconnects with an obscure parse error.

The fix: route all logs and debug output to stderr. The MCP spec is explicit about this, but the failure is silent — your server “just stops working” with no clear error. If you’re seeing weird disconnects, check what your code writes to stdout.

2. Generic tool names

A tool called get_data is a tool nobody knows when to call. The agent’s tool routing depends on names and descriptions; if everything is generic, the agent picks randomly or asks the human to disambiguate.

The fix: use the pattern {service}_{action}_{resource}. slack_send_message. linear_list_issues. sentry_get_error_details. The name alone should answer the question “what does this do?” before the description is even read.

3. Tool count overload

There’s a famous case from Block: they rebuilt their Linear MCP server three times, going from 30+ tools down to 2. Each rebuild made the agent perform measurably better on their benchmarks. GitHub Copilot did similar work, cutting their tool count from 40 to 13. The pattern is consistent: fewer tools, better agent performance.

Tools eat context window space (the descriptions) and force the model to choose between similar options. Above a certain threshold (somewhere around 10-15 per server), more tools actively degrade performance.

The fix: treat every new tool as a justification problem. Can two tools become one with a richer parameter? Can a tool be replaced by a resource the model reads instead? Aggressive pruning beats permissive expansion.

4. Synchronous I/O in async runtimes

MCP servers usually run inside an async event loop. If your tool implementation does blocking I/O (synchronous database calls, blocking HTTP requests, file reads without aiofiles), the whole event loop stalls. Clients see timeouts; your server appears unresponsive.

The fix: every I/O path async. CPU-intensive work goes to a thread pool. The MCP framework you’re using (Anthropic’s SDK, the Python mcp package, etc.) will have idiomatic patterns for this — follow them.

5. Treating MCP like a REST API wrapper

The biggest conceptual mistake. Builders look at MCP and see “yet another way to expose endpoints.” But MCP’s user is an LLM, not a human, and LLMs need different things from APIs.

REST APIs assume the caller already knows what they want. MCP tools assume the caller is reasoning about whether to call this tool at all, with what arguments, and what the result will mean. That changes how you design names, parameters, error messages, and return formats. A REST endpoint that returns {"error": "404 not found"} is fine. An MCP tool that returns the same thing has just confused the model — what was 404? Should I retry? Should I try a different tool?

The fix: every error message is also a hint to the model. “No issue found with id ‘PROJ-1234’. Try linear_search_issues with a partial title to find similar issues.” That’s MCP design. The model knows what to do next.

6. Description quality treated as an afterthought

The paper “MCP Tool Descriptions Are Smelly!” measured this empirically: poor description quality significantly degrades agent task success rates, increases token overhead per call, and reduces behavioral reliability. Bad descriptions cost real money in real production systems.

The fix: each description answers four questions in order — what does it do, when should the model call it, what does it return, what won’t it do. Write descriptions like you’re writing for paying API customers. Revisit them quarterly as your agent’s behavior reveals weak points.

7. Shell injection via unsanitized inputs

A real and recurring class of vulnerability. CVE-2025-68143, 68144, and 68145 in mcp-server-git are recent examples — MCP servers that construct shell commands from user input without sanitization, allowing arbitrary code execution. The AgentSeal 2025 security survey of 1,808 MCP servers found 43% had shell/command injection vulnerabilities.

The fix: never shell out with string concatenation. Use argument arrays. Validate inputs at the server boundary. Treat the model as a potentially-adversarial caller, because prompt injection attacks can turn the model into one even when the human user has good intentions.

Security: what production-grade MCP looks like

If you’re plugging arbitrary public MCP servers into your stack, you’re playing with fire. The AgentSeal survey of 1,808 public servers in 2025 found 66% had at least one security finding: 43% shell/command injection, 20% tooling infrastructure attacks, 13% authentication bypasses, 10% path traversal. The MCP ecosystem is moving fast and security review hasn’t kept up.

For your own servers, the production-grade baseline:

Authentication via OAuth 2.1 with PKCE for any server that touches user-specific data. API keys are acceptable for service-to-service connections where one side fully owns both. JWT tokens with short TTLs for stateless verification. Device flows for headless environments. The recent SMCP (Secure MCP) paper outlines mutual authentication and policy enforcement patterns worth studying if you’re shipping enterprise MCP.

Input validation at the boundary. Every tool parameter, validated. JSON schema validation in the MCP server, type checks on top, content-level validation (no shell metacharacters in things that become shell arguments, no path traversal in file paths, no SQL injection in query parameters).

Sandboxed execution. If your tool runs code, runs it in a sandbox. Containers, VMs, or at minimum subprocess with restricted permissions. Don’t trust that “my agent would never tell my code-runner to do something dangerous” — prompt injection is a real attack vector.

Audit logging at the server. Every tool invocation logged with caller identity (from your identity propagation layer), arguments, timestamp, outcome. When something goes wrong — and at scale, things always go wrong — you’ll need to know which agent invoked which tool with which arguments under whose identity.

Network restriction for stdio servers. A stdio MCP server shouldn’t be making arbitrary outbound network calls — only to the systems it explicitly integrates with. Use network policies or DNS-level restrictions to enforce this.

For third-party MCP servers: read the code, read the security history, and assume the worst until proven otherwise. The convenience of “just plug in this public server” is rarely worth the supply-chain risk if the server is going to touch anything sensitive.

Choosing your stack

Three host environments dominate as of mid-2026, with different trade-offs.

Claude Code is Anthropic’s own implementation, the most spec-aligned of the major hosts. Project-scoped MCP via .mcp.json is first-class. The four-mechanism extension model (hooks, skills, plugins, MCP) gives you graduated context costs — use hooks for cheap event handlers, escalate to MCP only when you actually need an external service. If you’re already an Anthropic user, this is the path of least resistance.

Cursor has the broadest editor adoption among AI-native developer tools. MCP support has been solid since mid-2025. It’s friendlier to teams that already have a Cursor workflow and want to add MCP rather than rebuild around Claude Code.

OpenAI’s Apps SDK is protocol-compatible with MCP at the wire level — you can write one server and reach both ecosystems. The trade-off is that some of OpenAI’s tooling around the Apps SDK is opinionated in ways MCP-native tools aren’t. For maximum portability, write to the MCP spec; for tighter ChatGPT integration, lean into Apps SDK conventions where they diverge.

Custom hosts (Cline, Continue, your own agent runtime). Use these when you need control over how MCP servers integrate with your specific agent loop. The SDKs (Python, TypeScript, Go, C#, Java) make this less work than you’d expect. Worth the lift if your use case doesn’t fit a generic editor.

For most builders the answer is: pick the editor you’re already in, write MCP servers to the spec, and let portability emerge naturally. Don’t over-engineer for theoretical multi-host scenarios you may never hit.

What’s coming: the 2026 roadmap implications

The MCP 2026 roadmap prioritizes production readiness. Three changes matter for architecture decisions you’re making now.

Stateless operation. Current MCP servers carry session state in-process, which limits horizontal scaling. The new spec is standardizing session creation, resumption, and migration so server restarts and scale-out events become transparent. What this means for you: design your servers stateless today. State in the underlying systems, not in the server process. You’ll be aligned with the direction the protocol is moving.

Standardized metadata via .well-known. Server capabilities will be discoverable without a live connection. Imagine a registry of MCP servers where you can query “which servers expose a tool matching this description” before opening a session. What this means for you: your servers’ descriptions and metadata should be polished enough to survive that level of public scrutiny.

Streamable HTTP becoming the default. With 95% latency reduction over SSE and 100% success rate in stateless session handling per published benchmarks, remote MCP servers are now production-viable in a way they weren’t a year ago. What this means for you: stop thinking of “remote MCP” as the slow-and-stateful cousin of stdio. It’s now a first-class deployment target.

Together, these changes turn MCP from “interesting protocol” into “real production infrastructure.” The architecture decisions you make in 2026 will compound over the next 24-36 months as adoption tracks the roadmap.

When NOT to use MCP

The hardest skill for any builder is knowing when not to use the trendy thing. MCP is genuinely useful, but it’s not the right tool for everything.

Skip MCP when your AI feature talks to one private internal API that nobody else needs. Direct function calling in your model SDK is simpler. MCP earns its weight when there’s reuse — multiple clients, multiple tools, multiple agents — not when it’s a single integration nobody else will touch.

Skip MCP for ultra-low-latency loops. JSON-RPC roundtrips add overhead. If you’re inside a tight inner loop where every millisecond matters (real-time inference, autonomous driving stacks, game engines), MCP isn’t the abstraction you want.

Skip MCP when your “tool” is fundamentally a UI element. A button isn’t a tool. A form isn’t a tool. A workflow visualization isn’t a tool. Don’t shove UI affordances into MCP’s tool model just because everything looks like a nail when you have the MCP hammer.

Skip MCP for stateless function purity that won’t ever interact with the outside world. A math function doesn’t need MCP. Pure code generation doesn’t need MCP. MCP is about connecting models to external systems — when there’s no external system, you don’t need the bridge.

The test: “would another AI client benefit from this same capability?” If yes, build it as MCP. If no, direct integration is fine.

Resources

The cluster articles below go deep on the parts this pillar only touched. Each is a standalone read, but together they form a complete builder’s reference for MCP design.

External authoritative sources worth bookmarking:

I architect my own operator stack around the patterns in this pillar. When I’m consulting on AI implementations, this is the design language I bring. If you want to build the kind of MCP-integrated system that actually holds up — and you want it without the multi-month learning curve of finding the design boundaries the hard way — work through the cluster articles in order, or skip to the course when it ships.

MCP isn’t a protocol you bolt on. It’s a design discipline. The builders who internalize that now will own the AI infrastructure conversation in 2027.

FAQ

What is MCP (Model Context Protocol) in one sentence?

MCP is an open standard from Anthropic (released November 2024) that lets AI assistants connect to external tools, data, and services through a single uniform interface — instead of every model and every tool needing custom integrations.

Who supports MCP in 2026?

Claude (Anthropic), Cursor, Claude Code, Windsurf, Cline, GitHub Copilot (via OpenAI's compatible Apps SDK), Sourcegraph Cody, Continue, and a growing ecosystem of editors and agent frameworks. The protocol is open and SDK-supported in Python, TypeScript, Go, C#, and Java.

MCP vs OpenAI Apps SDK — what's the difference?

OpenAI's Apps SDK (launched 2025) is interoperable with MCP at the protocol level — an MCP server can be reached by OpenAI's clients and vice versa. The practical difference is in transport defaults and tooling around them: MCP has broader editor adoption today, Apps SDK has tighter ChatGPT integration. For most builders, write an MCP server and you reach both.

Is MCP production-ready in 2026?

The protocol is production-ready for many use cases, but uneven. Streamable HTTP transport (introduced November 2025) and the 2026 roadmap's push to stateless operation are still being adopted. A 2025 security survey of 1,808 public MCP servers by AgentSeal found 66% had at least one security finding. Production-grade MCP today requires you to architect carefully: not all servers in the wild are safe to plug in.

When should I NOT use MCP?

When your AI feature talks to a single internal API that nobody else needs to share, direct integration is simpler. When you need ultra-low-latency tool calls inside a tight loop, MCP's JSON-RPC roundtrip adds overhead. When your tool is fundamentally a UI element rather than a data/action surface, MCP is the wrong abstraction. MCP wins when you have multiple AI clients or multiple tool surfaces that benefit from a uniform contract.

Cluster articles

Encyclopedia entries that go deeper on specific pieces of this pillar.

Coming soon in this cluster:

  • What Is Mcp
  • Mcp Server Design Patterns
  • Mcp Vs Openai Apps Sdk
  • Mcp Security Checklist
  • Mcp Client Development Guide
  • Mcp Tool Description Quality
  • Mcp Stdout Pollution Fix
  • Mcp Stateless Architecture
  • Mcp Project Scoped Servers
  • Mcp Oauth Pkce Implementation
  • Mcp Streamable Http Transport
  • Mcp For Solo Operators
  • Mcp Agent Memory Patterns
  • Mcp Failure Modes Debugging
  • Mcp Public Servers Worth Using