DEV Community

MCP Design Patterns: 6 Architectures for Your AI Tools

What Is an MCP Server?

The Model Context Protocol is an open protocol for connecting AI applications to external context and capabilities. An MCP server can expose three main kinds of primitives:

  • Tools: callable actions, usually with parameters and structured results.
  • Resources: readable context such as files, documents, database records, or generated views.
  • Prompts: reusable prompt templates or interaction patterns.

In practice, most people start with tools because they are the most visible part of MCP. But a good MCP server is not just a bag of functions. It is a boundary between an AI client and a system that has data, behavior, permissions, and risk. The important question is not only: What can the agent call? It is also: What should the client expose, in what shape, with what permissions, and at what level of abstraction?

Pattern 1: Direct API Wrapper

This is the simplest and most common pattern. One MCP tool maps closely to one existing API endpoint. The server is mostly a thin adapter between the MCP client and an existing service.

AI Client | MCP Tool: get_user(id) | REST API: GET /users/{id}

When it fits: The API is stable, well documented, and already close to what the model needs. You want quick integration without adding much domain logic to the MCP server.

When it does not fit: The API exposes low-level data that the model still has to join, filter, interpret, or clean up. Then the complexity moves into the prompt and the model has to act like an API integration layer. That is fragile.

Typical examples:

  • GitHub issue lookup
  • Jira ticket retrieval
  • internal REST services
  • simple CRM queries

Main risk: Tool bloat. If every endpoint becomes a tool, the model has too many similar options and too much raw API detail to reason about.

Design rule: Use direct wrappers for small, obvious, low-risk API operations. Move to task-level tools when the agent has to combine or interpret several raw endpoints.

Pattern 2: Composite Service

A composite MCP server hides multiple backend calls behind one task-level tool. The agent asks for the result it actually needs, and the server performs the aggregation.

AI Client | MCP Tool: get_order_summary(order_id)
  | +-- REST API: GET /orders/{id}
  | +-- REST API: GET /customers/{customer_id}
  | +-- REST API: GET /products/{product_id}

When it fits: The agent repeatedly needs the same combination of data for one task. Without this pattern, it would make several tool calls and assemble the result itself.

When it does not fit: The required combination changes constantly. If every task needs a different shape, a fixed composite tool can become too rigid.

Typical example: A customer service agent that needs order data, customer profile, delivery status, and product information together.

Main risk: The composite tool can become a hidden mini-application. If it starts making too many assumptions, the agent loses flexibility.

Design rule: Return task-ready context, not a full backend dump. The output should be smaller, clearer, and safer than the raw data sources.

Pattern 3: Resource-Oriented MCP

Not every capability should be a tool. Sometimes the best MCP server exposes structured resources that the client can read and inject as context.

AI Client
  | MCP Resource: file://project/README.md
  | MCP Resource: db://customer/123/profile
  | MCP Resource: config://service/payment
  | Local or remote data source

When it fits: The agent needs context more than action. The data is read-only or should be treated as reference material.

When it does not fit: The model needs to execute a parameterized operation, mutate state, trigger a workflow, or perform a search that has meaningful side effects or cost.

Typical examples:

  • code repositories
  • documentation collections
  • local knowledge bases
  • generated system state snapshots
  • configuration views

Main risk: Overexposure. Raw resource access can accidentally reveal too much. A filesystem server, for example, should not expose the entire machine by default.

Design rule: Expose curated resources with clear roots, metadata, and permission boundaries. Prefer readable views over unrestricted raw access.

Pattern 4: Agent-Backed Tool

In this pattern, the MCP tool does not call a normal API. It delegates to another AI agent, model, or specialized reasoning component.

Main AI Client | MCP Tool: analyze_code(snippet) | Specialized Analysis Agent

When it fits: A subtask benefits from a different model, narrower context, specialized tools, or a controlled reasoning workflow.

When it does not fit: The task is simple enough for the main model. Additional agent hops add latency, cost, and debugging complexity.

Typical examples:

  • code security review
  • policy compliance analysis
  • domain-specific document classification
  • test generation with a specialized context

Main risk: Loss of traceability. Once one agent calls another, failures become harder to explain. The main model sees a result, but not necessarily the reasoning quality behind it.

Design rule: Use agent-backed tools when the subagent produces a bounded, verifiable result. Return evidence, confidence, and limitations where possible.

Pattern 5: Event-Driven Control Surface

Some work should not happen inside a synchronous MCP tool call. The operation may take minutes, involve queues, or run in a background service. In this pattern, the MCP server exposes a control surface over asynchronous infrastructure.

AI Client
  | MCP Tool: start_report_generation(params)
  | Event Queue / Job Scheduler
  | Report Service
  | MCP Tool: get_report_status(job_id)
  | MCP Resource: report://jobs/{job_id}/result

When it fits: The operation is too slow or too expensive for a normal request-response call. The agent should start the job, receive a job ID, and check status later.

When it does not fit: The operation is fast and deterministic. Adding a queue for a 200 ms call is unnecessary overhead.

Typical examples:

  • report generation
  • long-running data processing
  • batch imports
  • document conversion
  • asynchronous approval workflows

Main risk: Ambiguous state. If the agent cannot tell whether a job is queued, running, failed, completed, or expired, the workflow becomes unreliable.

Design rule: Make job state explicit. Provide status, progress, failure reason, result location, cancellation, and retry semantics.

Pattern 6: Gateway or Federated MCP

In larger systems, one MCP server may act as a gateway in front of several domain-specific servers or services. This is not a special MCP primitive. It is an architectural pattern. Many clients can connect to multiple MCP servers directly. A gateway is useful when you need shared concerns in one place.

AI Client
  | MCP Gateway: Auth, Routing, Logging, Policy
  | +-- Inventory MCP Server
  | +-- Order MCP Server
  | +-- Customer MCP Server

When it fits: The system has many domains, teams, or permission boundaries. You need central authentication, routing, audit logging, tool filtering, or rate limiting.

When it does not fit: The system is small. A gateway then becomes an unnecessary layer between the client and a few simple tools.

Typical examples:

  • enterprise AI platforms
  • multi-team internal tool ecosystems
  • regulated environments
  • shared company-wide assistant infrastructure

Main risk: The gateway becomes a bottleneck or a second platform. If every domain change requires gateway changes, team independence disappears.

Design rule: Use a gateway for cross-cutting policy, not for domain logic. Domain ownership should stay with the domain servers.

A Note on Local Access

Local resource access is often treated as its own category because it feels different from API integration. A local MCP server may read files, inspect repositories, query a local database, or expose an Obsidian vault. Architecturally, local access usually belongs to one of two patterns:

  • Resource-Oriented MCP for read-only local context.
  • Direct or Composite Tools for controlled local actions such as search, indexing, transformation, or file generation.

The key issue is permission scope. Local access can be extremely powerful. A good local MCP server should restrict roots, filter results, avoid leaking secrets, and make dangerous actions explicit.

The Decision Logic

These questions help choose the right pattern:

Question Best fit
Do I have a simple existing API operation to expose? Direct API Wrapper
Does the model need one task-level result from several sources? Composite Service
Is the capability mostly read-only context? Resource-Oriented MCP
Does the task need another model or specialized reasoning context? Agent-Backed Tool
Does the operation run asynchronously or take too long for one call? Event-Driven Control Surface
Do many teams or domains need one shared policy boundary? Gateway or Federated MCP

The patterns are not mutually exclusive. A production system often combines them:

Gateway MCP
  | +-- Composite tools for customer support
  | +-- Resource-oriented server for documentation
  | +-- Event-driven tools for report generation
  | +-- Agent-backed tools for specialized analysis

The more important decision is where complexity should live:

  • in the MCP server
  • in the client
  • in the model prompt
  • in backend services
  • in a gateway layer

As a rule, complexity that is deterministic, security-sensitive, or repetitive should live outside the prompt.

Security Questions Every Pattern Needs

Before exposing a capability through MCP, ask:

  • Is it read-only or can it change state?
  • Does it require user confirmation?
  • What is the smallest permission scope that works?
  • Can the tool leak secrets through raw output?
  • Is the result structured enough for the model to use safely?
  • Is the action logged with user, time, input, and result?
  • Can the operation be replayed safely?
  • What happens if the model calls the tool with malformed or hostile input?

MCP makes integration easier. It does not make trust boundaries disappear.

Conclusion

Building an MCP server is easy. Building the right MCP server requires a conscious decision about shape, abstraction level, and risk. Start with the simplest pattern that satisfies the requirement:

  • direct wrappers for simple API operations
  • composite tools for repeated multi-source tasks
  • resources for readable context
  • agent-backed tools for bounded specialist work
  • event-driven control surfaces for long-running jobs
  • gateways only when cross-domain policy really matters

The best MCP server does not expose everything the backend can do. It exposes the smallest stable capability that helps the model complete the task without giving it unnecessary power or unnecessary raw data. That is the real architecture decision.

References

Comments

No comments yet. Start the discussion.