MCP server design patterns and anti-patterns A practitioner guide published in October 2026 identifies four design patterns that hold up in production Model Context Protocol (MCP) servers built to the 2026-07-28 specification, led by exposing retrieval as a cheap `search` tool plus a `fetch`-by-ID tool and leaving reasoning to the calling model. The guide, part 32 of the author's MCP series, also recommends explicit handles for cross-call state instead of per-connection state, Multi Round-Trip Requests that settle inputs before returning a task handle, and shipping one capability across layered surfaces from universal tools to MCP Apps. It attributes most production problems to a short list of anti-patterns including one tool per endpoint, per-connection state, unprotected `requestState` and token passthrough, and notes OpenAI's MCP guide asks servers to implement read-only `search` and `fetch` tools to work with ChatGPT's deep research and company knowledge features. MCP server design patterns and anti-patterns The specification tells you what a Model Context Protocol MCP server must do. It says much less about what holds up in practice, so here I’ve collected four recurring patterns that work and the anti-patterns behind most production problems, each with a pointer to the part of the series that explains the fix. This is part 32 of my series on what an MCP server does under the 2026-07-28 specification, after part 31 on which AI hosts support which features https://pournasserian.com/writing/mcp-2026-host-support . One frequently asked architecture question, whether to put an AI agent behind a tool, gets the next part to itself. The facts are as I read them in October 2026. In brief 1. Expose retrieval as two tools, a cheap search and a fetch by ID, and leave the reasoning to the calling model. 2. Keep state across calls in explicit handles, not in the connection: per-connection state breaks behind load balancers, and a handle is checked against the caller on every call. 3. When long work needs a confirmation, settle the inputs first and then return a task, with no side effects before the last input round. 4. Ship one capability on several surfaces, from tools that work everywhere to an MCP App where a host can render one, each degrading to the next. 5. Most production problems come from a short list of anti-patterns, among them one tool per endpoint, per-connection state, unprotected requestState and token passthrough. Four patterns that work Three of these are my advice rather than rules from the specification; the handle pattern follows the specification’s own guidance, as part 5 https://pournasserian.com/writing/mcp-2026-stateless-requests shows. Search plus fetch When your server fronts a body of content, expose retrieval as two tools: a cheap search that returns ranked, citable hits, and a fetch that returns a full item by its ID. The calling model does the reasoning, and your server does what it’s uniquely good at: knowing the index, the schema and the ranking. - search returns structuredContent with IDs, titles, scores, short snippets and source Uniform Resource Identifiers URIs , plus a compact text rendering in content . - fetch returns the full document, or a resource link the host can attach. The pattern also matches what two ChatGPT features, deep research and company knowledge, expect: OpenAI’s MCP guide https://developers.openai.com/api/docs/mcp asks servers that want to work with them to implement two read-only tools, search and fetch . The example instructions in part 4 https://pournasserian.com/writing/mcp-2026-server-instructions tell the model to call search docs first and then fetch doc , which is this pattern in a sentence. Explicit handles for state There are no sessions under the 2026-07-28 specification, so state that spans calls needs a home of its own. Return an opaque handle from a creation tool, accept it on later calls, authorize the caller against it every time, state its lifetime in the description, and return a recoverable tool execution error when it expires. Part 5 explains why and builds one in Python, with an owner and an expiry. Multi round-trip requests, then a task For long-running work that needs a confirmation, resolve the inputs synchronously with Multi Round-Trip Requests MRTR, part 13 https://pournasserian.com/writing/mcp-2026-multi-round-trip-requests , then return a task handle and run the work asynchronously. Cause no side effects before the final input round. Part 26 https://pournasserian.com/writing/mcp-2026-tasks shows how the two phases fit together. Layered surfaces Host support is uneven, as part 31 showed, so ship one capability on several surfaces, each degrading to the next. Here is one workflow, an incident postmortem, delivered five ways: tools that work everywhere, server instructions that point to the prompt and the skill, a prompt for integrated development environment IDE and chat hosts, a skill for hosts with Skills, and an MCP App for hosts with Apps. A host that supports only tools still gets the incident data through get incident and list timeline events . Each layer it supports adds to that. Part 12 https://pournasserian.com/writing/mcp-2026-choosing-a-primitive gives the reasoning behind each choice of primitive. Anti-patterns that cause most production problems I’ve grouped the twelve by where they live. Where the specification itself sets the fix, the group says so; the rest is my advice. In tools and their results Five concern the tools themselves and what they return. Two of the fixes are the specification’s: servers SHOULD return tools in a deterministic order, and under the MCP Apps extension, tools MUST return meaningful content even when a user interface UI is available. | Anti-pattern | Why it hurts | Instead | |---|---|---| | Throwing exceptions on bad input | Becomes a protocol error, and the model can’t self-correct | isError: true with an actionable message part 9 https://pournasserian.com/writing/mcp-2026-tool-errors-and-design | | One tool per Representational State Transfer REST endpoint, 50 or more tools | Context bloat and poor tool selection | Fewer, task-shaped tools with sharp descriptions part 9 https://pournasserian.com/writing/mcp-2026-tool-errors-and-design | | Dumping whole documents into results | Hits host output limits and costs tokens | Summaries plus resource link s part 9 https://pournasserian.com/writing/mcp-2026-tool-errors-and-design | | UI-only answers | Useless in text-only hosts | Meaningful content always part 25 https://pournasserian.com/writing/mcp-2026-apps-building | | Unstable list ordering | Prompt-cache misses, flaky pagination | Deterministic sort part 6 https://pournasserian.com/writing/mcp-2026-caching-and-pagination | One detail for Python: in the official software development kit SDK , mcp 2.3.0, an unexpected exception in an MCPServer tool doesn’t become a protocol error only a deliberate MCPError does . The SDK turns it into an isError result that says only Error executing tool