{
  "slug": "mcp-server-failure-modes",
  "title": "Common MCP Server Failure Modes and How to Fix Them",
  "description": "A runtime playbook for the two MCP server failure modes with no dedicated deep-dive elsewhere: unrecoverable state after a mid-call crash, and malformed or hallucinated tool calls that reach the handler despite upstream validation.",
  "kind": "sub",
  "order": 9,
  "target_query": "common MCP server failure modes and how to fix them",
  "secondary_queries": [
    "MCP tool call idempotency key",
    "MCP server crash recovery",
    "handling hallucinated tool calls in an MCP handler",
    "malformed tool call arguments MCP server"
  ],
  "tags": [
    "mcp",
    "reliability",
    "idempotency",
    "tool-calling",
    "agents",
    "production"
  ],
  "published": "2026-08-21",
  "updated": "2026-08-21",
  "words": 1751,
  "premium": false,
  "license": "https://changegamer.ai/license.xml",
  "canonical": "https://changegamer.ai/articles/mcp-server-failure-modes",
  "markdown": "https://changegamer.ai/articles/mcp-server-failure-modes.md",
  "takeaways": [
    "An MCP tool handler that writes to a database or calls a payment API needs an idempotency key derived from the run ID and step index, not from wall-clock time or a fresh random value, so a retried call after a crash lands as a no-op instead of a duplicate side effect.",
    "A hallucinated tool name or a malformed argument object can still reach an MCP handler even with a well-formed inputSchema declared, because schema declaration constrains what a well-behaved client sends, not what an unreliable model actually emits.",
    "Distinguishing a transient failure (network timeout, rate limit, 5xx) from a terminal one (bad request, business-logic rejection) at the point of failure determines whether an MCP handler should retry with backoff or fail fast and surface a clear error instead.",
    "The Berkeley Function Calling Leaderboard is the standard reference benchmark for tool-call reliability across providers, which means a hallucinated-tool-name or malformed-argument rate greater than zero should be treated as an expected input condition an MCP handler must defend against, not an edge case to leave unhandled.",
    "Rejecting an unknown tool name or a schema-invalid argument object before any handler logic runs turns a hallucinated or malformed call into a clean, typed error response instead of an unhandled exception or, worse, a partially executed side effect."
  ],
  "outline": [
    {
      "depth": 2,
      "text": "What happens when a tool call crashes mid-write?",
      "anchor": "what-happens-when-a-tool-call-crashes-mid-write",
      "url": "https://changegamer.ai/articles/mcp-server-failure-modes#what-happens-when-a-tool-call-crashes-mid-write"
    },
    {
      "depth": 3,
      "text": "Logging the step before acting on it",
      "anchor": "logging-the-step-before-acting-on-it",
      "url": "https://changegamer.ai/articles/mcp-server-failure-modes#logging-the-step-before-acting-on-it"
    },
    {
      "depth": 2,
      "text": "Transient failure or terminal failure — and why the distinction matters",
      "anchor": "transient-failure-or-terminal-failure-and-why-the-distinction-matters",
      "url": "https://changegamer.ai/articles/mcp-server-failure-modes#transient-failure-or-terminal-failure-and-why-the-distinction-matters"
    },
    {
      "depth": 2,
      "text": "Why does a well-formed schema still let bad tool calls through?",
      "anchor": "why-does-a-well-formed-schema-still-let-bad-tool-calls-through",
      "url": "https://changegamer.ai/articles/mcp-server-failure-modes#why-does-a-well-formed-schema-still-let-bad-tool-calls-through"
    },
    {
      "depth": 3,
      "text": "The mitigation table, applied at the handler",
      "anchor": "the-mitigation-table-applied-at-the-handler",
      "url": "https://changegamer.ai/articles/mcp-server-failure-modes#the-mitigation-table-applied-at-the-handler"
    },
    {
      "depth": 3,
      "text": "Why zero-tolerance defense is the right default, not paranoia",
      "anchor": "why-zero-tolerance-defense-is-the-right-default-not-paranoia",
      "url": "https://changegamer.ai/articles/mcp-server-failure-modes#why-zero-tolerance-defense-is-the-right-default-not-paranoia"
    },
    {
      "depth": 2,
      "text": "Where this leaves you",
      "anchor": "where-this-leaves-you",
      "url": "https://changegamer.ai/articles/mcp-server-failure-modes#where-this-leaves-you"
    }
  ],
  "faq": [
    {
      "question": "How should an MCP tool handler recover from a crash mid-call?",
      "answer": "An MCP tool handler should log the call before executing its side effect and use a stable idempotency key derived from the workflow run ID and step index, so that if the process crashes mid-call and the caller retries, the downstream service recognizes the duplicate key and returns the original result instead of repeating the side effect. This is the same idempotency-key pattern durable execution engines use generally, applied at the level of a single tool call rather than a full workflow."
    },
    {
      "question": "What should an MCP server do when it receives a call for a tool name it never declared?",
      "answer": "An MCP server should reject the call immediately with a clear, typed error identifying the unrecognized tool name, before any handler logic runs, rather than attempting to guess the caller's intent or silently ignoring the request. A hallucinated tool name is a known, documented failure mode in tool-calling systems generally, not something specific to MCP, so validating against the server's own declared tool set is the same defense any tool-calling backend needs."
    },
    {
      "question": "Should a malformed tool call always be retried?",
      "answer": "No — only if the failure is transient, not if it is malformed. A malformed or schema-invalid argument object is a client-side (or model-side) error, not a network blip, so retrying the identical malformed call produces the identical failure every time; the correct response is a rejection with a specific validation error the calling model or client can act on, distinct from the retry-with-backoff behavior appropriate for a timeout or a rate limit."
    },
    {
      "question": "Does declaring a strict inputSchema prevent malformed tool calls from reaching my MCP server?",
      "answer": "A strict inputSchema constrains what a well-behaved client validates before sending a call, but it does not prevent a model from emitting a call that skips that validation or a client from forwarding a call it did not itself construct carefully, so the server-side handler still needs to validate arguments against the same schema before executing anything. Treat client-side schema declaration and server-side runtime validation as two independent layers, not a single control."
    }
  ],
  "body": "The pillar's [failure modes section](/articles/mcp-server-in-production) lists eight things that actually break a production MCP server, from rug pulls to spec-transition breakage, each in a sentence or two. Three of those eight already have a dedicated deep-dive elsewhere in this cluster: rug pulls and supply-chain compromise in [tool description injection and tool poisoning](/articles/mcp-tool-description-injection), confused-deputy token passthrough and DNS rebinding in [implementing OAuth 2.1 for an MCP server](/articles/mcp-oauth-implementation), and spec-transition breakage in [MCP server versioning and spec migration](/articles/mcp-server-versioning-and-spec-migration). This article covers the two that have no sibling deep-dive: unrecoverable state on crash, and malformed or hallucinated tool calls that reach the handler. It does not repeat the pillar's one-line summaries of the other five.\n\n## What happens when a tool call crashes mid-write?\n\nA tool call that crashes after it has already started a write — a database insert, a payment charge, a message send — leaves the system in an ambiguous state unless the handler was built to make a retry safe. The caller does not know whether the side effect completed before the crash, only that it did not receive a response, so the caller's only reasonable next move is to retry the same call. Whether that retry is safe depends entirely on whether the handler was written to tolerate it.\n\nThe mechanism that makes a retry safe is an idempotency key: a stable identifier attached to the call that the downstream service uses to recognize \"I have already done this\" and return the original result instead of repeating the side effect. The key detail is what the key is derived from. A key built from wall-clock time or a freshly generated random value is different on every retry attempt — which defeats the purpose, because the downstream service sees each retry as a new, distinct request. A key derived from the run ID and the step index within that run stays identical across retries of the same logical call, which is what durable execution treats as the standard pattern: \"derive a stable idempotency key from the workflow run ID and step index — not from wall-clock time or a random UUID — and pass it to the downstream service so that a duplicate call is a no-op\" ([durable execution for long-running agents](/resources/durable-execution-for-agents)).\n\n```typescript\n// Illustrative — the shape of a stable idempotency key, not tied to a\n// specific MCP SDK. runId and stepIndex must be stable across retries of\n// the same logical call; a fresh value on each attempt defeats the point.\nfunction idempotencyKey(runId: string, stepIndex: number): string {\n  return `${runId}:${stepIndex}`;\n}\n\nasync function chargeCard(runId: string, stepIndex: number, amountCents: number) {\n  const key = idempotencyKey(runId, stepIndex);\n  // Passed to the payment API's own idempotency-key parameter, so a\n  // duplicate call with the same key returns the original charge result\n  // instead of creating a second charge.\n  return paymentClient.charge({ amountCents, idempotencyKey: key });\n}\n```\n\n### Logging the step before acting on it\n\nThe same durable-execution discipline that produces a stable idempotency key also determines whether a crash loses work at all: \"a durable execution engine records every meaningful step of a workflow — LLM call, tool invocation, timer, signal received — to a persistent log (or checkpoint store) before moving on. If the process crashes or is restarted, the engine replays the log to reconstruct in-memory state exactly where execution left off\" ([durable execution for long-running agents](/resources/durable-execution-for-agents)). Applied to a single MCP tool handler rather than a full multi-step workflow, the practical version is narrower but the principle is the same: persist that a call with a given idempotency key was started before attempting the side effect, so that on restart the handler can check whether that key already has a recorded outcome rather than blindly re-executing.\n\nNot every MCP server needs a full durable-execution engine for this — a handler that writes its own idempotency-key table to the same database it is already calling, and checks it before executing, gets most of the benefit without adopting Temporal, Restate, or a similar engine. Reach for a dedicated durable-execution engine specifically when a tool call needs to pause for an external signal — a human approval, a webhook — for longer than a request-response cycle reasonably spans; that is a different problem from making a single crash-prone write retry-safe, and the corpus resource above surveys the engines built for it.\n\n## Transient failure or terminal failure — and why the distinction matters\n\nA crashed or failed tool call should not always be retried, and the decision hinges on whether the failure was transient or terminal. Durable execution engines formalize this distinction explicitly: \"*transient* failures (network timeout, rate limit, 5xx) are retried with backoff; *terminal* failures (4xx bad-request, business logic error) escalate immediately\" ([durable execution for long-running agents](/resources/durable-execution-for-agents)). An MCP handler that retries a terminal failure — a malformed request, a business rule rejection, an authorization denial — will fail identically on every retry, burning latency and, if the retry also re-attempts a side effect without an idempotency key behind it, risking a duplicate. An MCP handler that fails fast on a transient error — a single dropped connection, a momentary rate limit — pushes unnecessary error handling onto the calling agent for a condition a short backoff-and-retry would have resolved on its own.\n\n- **Transient**: network timeout connecting to a downstream API, a 429 rate-limit response, a 5xx from a dependency. Retry with backoff, bounded by a maximum attempt count — unbounded retries mask real bugs behind an eventually-successful call.\n- **Terminal**: a 4xx from a downstream API, a business-logic rejection (insufficient balance, invalid state transition), a validation failure on the handler's own side. Fail immediately and return a specific error the caller can act on; retrying an unchanged terminal failure produces an unchanged terminal failure.\n\n## Why does a well-formed schema still let bad tool calls through?\n\nA declared `inputSchema` constrains what a well-behaved client validates before sending a call — it does not constrain what an unreliable model actually emits. The reliability literature for tool calling generally documents both a hallucinated-tool-name failure and a set of argument-shape failures as distinct, common categories, independent of how carefully a server has declared its schema: \"hallucinated tool name — model calls a tool not in the declared set\", \"missing required arguments — model omits a field the schema marks required\", \"extra / unexpected arguments — model adds fields not in schema\", \"malformed JSON — output is not parseable\", and \"wrong types — string where int expected\" ([reliable tool calling and structured outputs](/resources/reliable-tool-calling)). None of those originate on the server side. They originate in the calling model's own output, before your server ever sees the request — which is exactly why a schema declaration alone cannot prevent them from arriving.\n\nThis is a different problem from the one [testing an MCP server in CI](/articles/testing-mcp-servers-in-ci) solves. That article covers writing a Layer 1 unit test that feeds your own input validator malformed argument objects and asserts it rejects each one — a pre-production check that your validation logic works correctly at all. This section covers what the handler itself does at runtime, in production, when a call that your validator was never exercised against — or a call your validator has a gap for — actually arrives. Testing proves the validator works against cases you thought of; runtime defense is what happens against the case you did not.\n\n### The mitigation table, applied at the handler\n\nThe reliability corpus's mitigation table names concrete fixes for each failure category — check any incoming call name against your declared tool set and refuse whatever isn't on it; use `additionalProperties: false` and a `required` array with schema validation to catch missing or extra arguments pre-execution; wrap JSON parsing in a try/catch and treat a parse failure as a rejection, not a crash; validate types with a schema library before consuming any argument value ([reliable tool calling and structured outputs](/resources/reliable-tool-calling)). Applied specifically to an MCP handler, in order of execution:\n\n```typescript\n// Illustrative handler-side defense — runs before any side effect,\n// regardless of what client-side validation the caller may or may not\n// have performed.\nfunction handleToolCall(req: { name: string; arguments: unknown }) {\n  if (!DECLARED_TOOLS.has(req.name)) {\n    return rejectWith(`unknown tool: ${req.name}`); // hallucinated tool name\n  }\n  const parsed = validateAgainstSchema(req.name, req.arguments); // missing/extra/wrong-type\n  if (!parsed.ok) {\n    return rejectWith(parsed.errors.join('; '));\n  }\n  return executeHandler(req.name, parsed.value); // only now, a side effect\n}\n```\n\nThe ordering matters as much as the checks themselves: tool-name validation, then argument-schema validation, then execution — never the reverse, and never a side effect before both checks pass. A rejection at either of the first two steps costs one round trip; a side effect executed on an unvalidated argument object can cost a duplicate charge, a corrupted write, or a call to a tool the caller never actually intended to invoke.\n\n### Why zero-tolerance defense is the right default, not paranoia\n\nBerkeley's Function Calling Leaderboard (BFCL), the reference benchmark for tool-calling reliability across providers, exists specifically because \"typical breakdowns range from invented tool names and skipped or extraneous arguments to unparsable JSON, mistyped fields, needless or missing invocations, out-of-order parallel calls, and templates that don't match how the model was trained\" ([reliable tool calling and structured outputs](/resources/reliable-tool-calling)). As of August 2026, no provider's constrained-decoding mechanism eliminates every one of these categories for every model and every client integration — strict mode, `tool_choice` forcing, and grammar-based decoding each reduce specific failure categories, but the benchmark's continued existence is itself evidence that the underlying rate is nonzero across the field. An MCP handler sits downstream of whichever model and client happen to be calling it, often without control over either, so treating a hallucinated or malformed call as an expected input condition — not a rare edge case — is the realistic baseline to build against, not defensive overengineering.\n\n## Where this leaves you\n\nGive every side-effecting MCP tool handler a stable idempotency key derived from run ID and step index, distinguish transient failures worth retrying from terminal ones worth failing fast on, and re-check whatever call name and arguments actually arrive against your own declared schema before any side effect runs — regardless of what the client claims to have already checked. For the full eight-item failure-mode list this article extends, see [MCP server in production](/articles/mcp-server-in-production); for how to catch a validation gap before it reaches production, see [how to test an MCP server in CI](/articles/testing-mcp-servers-in-ci); for the durable-execution engines that formalize crash recovery beyond a single handler, see [durable execution for long-running agents](/resources/durable-execution-for-agents).",
  "cluster": {
    "id": "mcp-in-practice",
    "title": "MCP in practice",
    "description": "How to build, ship and run an MCP server in production — transport, auth, tool design, versioning, testing, distribution, observability, cost and failure modes.",
    "status": "complete",
    "pillar": {
      "slug": "mcp-server-in-production",
      "title": "MCP Server in Production: How to Build, Ship and Run One",
      "description": "The operator playbook for taking an MCP server past the quickstart: transport choice, OAuth 2.1 auth, tool design, versioning against a moving spec, testing across clients, distribution, observability, cost and the failure modes that show up once real clients connect.",
      "kind": "pillar",
      "order": 0,
      "html": "https://changegamer.ai/articles/mcp-server-in-production",
      "markdown": "https://changegamer.ai/articles/mcp-server-in-production.md",
      "json": "https://changegamer.ai/api/articles/mcp-server-in-production.json"
    },
    "articles": [
      {
        "slug": "mcp-stdio-vs-streamable-http",
        "title": "stdio vs. Streamable HTTP for MCP Servers: A Decision Framework",
        "description": "Which MCP transport to build against and why: the single-client-vs-shared decision rule, how state works without a session handshake under the 2026-07-28 spec, the auth-model switching cost, and what actually breaks migrating off HTTP+SSE.",
        "kind": "sub",
        "order": 1,
        "html": "https://changegamer.ai/articles/mcp-stdio-vs-streamable-http",
        "markdown": "https://changegamer.ai/articles/mcp-stdio-vs-streamable-http.md",
        "json": "https://changegamer.ai/api/articles/mcp-stdio-vs-streamable-http.json"
      },
      {
        "slug": "mcp-oauth-implementation",
        "title": "How to Implement OAuth 2.1 for an MCP Server",
        "description": "A wire-level implementation walkthrough for OAuth 2.1 on a remote MCP server: what the discovery documents actually contain, CIMD vs. Dynamic Client Registration in your server code, per-SEP detail from the 2026-07-28 hardening set, and token-validation mechanics.",
        "kind": "sub",
        "order": 2,
        "html": "https://changegamer.ai/articles/mcp-oauth-implementation",
        "markdown": "https://changegamer.ai/articles/mcp-oauth-implementation.md",
        "json": "https://changegamer.ai/api/articles/mcp-oauth-implementation.json"
      },
      {
        "slug": "mcp-tool-description-injection",
        "title": "Defending MCP Clients Against Tool Description and Output Injection",
        "description": "Two distinct MCP injection surfaces — a tool description at connect-time and a tool's return value at call-time — and the client-side architectural patterns (Dual LLM, Action-Selector, Context-Minimization) that contain each one.",
        "kind": "sub",
        "order": 3,
        "html": "https://changegamer.ai/articles/mcp-tool-description-injection",
        "markdown": "https://changegamer.ai/articles/mcp-tool-description-injection.md",
        "json": "https://changegamer.ai/api/articles/mcp-tool-description-injection.json"
      },
      {
        "slug": "testing-mcp-servers-in-ci",
        "title": "How to Test an MCP Server in CI",
        "description": "The implementation mechanics below the three-layer test pyramid: what a mocked MCP transport actually replaces, what a Streamable HTTP cassette contains, a concrete CI job/trigger shape, and how to catch spec-version drift before it reaches production.",
        "kind": "sub",
        "order": 4,
        "html": "https://changegamer.ai/articles/testing-mcp-servers-in-ci",
        "markdown": "https://changegamer.ai/articles/testing-mcp-servers-in-ci.md",
        "json": "https://changegamer.ai/api/articles/testing-mcp-servers-in-ci.json"
      },
      {
        "slug": "mcp-server-versioning-and-spec-migration",
        "title": "MCP Server Versioning and Spec Migration: An Operator Playbook",
        "description": "A migration runbook for MCP server operators: feature-detecting via capabilities instead of hard protocolVersion branching, a dual-version fleet rollout with rollback triggers, a compatibility shim for legacy clients still sending initialize, and a deprecation calendar built off the 12-month SEP-2577 floor.",
        "kind": "sub",
        "order": 5,
        "html": "https://changegamer.ai/articles/mcp-server-versioning-and-spec-migration",
        "markdown": "https://changegamer.ai/articles/mcp-server-versioning-and-spec-migration.md",
        "json": "https://changegamer.ai/api/articles/mcp-server-versioning-and-spec-migration.json"
      },
      {
        "slug": "mcp-server-observability-opentelemetry",
        "title": "MCP Server Observability with OpenTelemetry: Spans, Metrics, and Trace Correlation",
        "description": "Instrumenting an MCP server past the pillar's baseline: what to put on a tool-call span beyond gen_ai.tool.name, what replaces the deprecated Logging primitive in practice, per-tool-name latency and error-rate metrics, and how a trace ID actually survives the agent-to-upstream-API hop.",
        "kind": "sub",
        "order": 6,
        "html": "https://changegamer.ai/articles/mcp-server-observability-opentelemetry",
        "markdown": "https://changegamer.ai/articles/mcp-server-observability-opentelemetry.md",
        "json": "https://changegamer.ai/api/articles/mcp-server-observability-opentelemetry.json"
      },
      {
        "slug": "mcp-server-registry-publishing-playbook",
        "title": "How to Publish an MCP Server to the Official Registry",
        "description": "A step-by-step walkthrough of the mcp-publisher CLI and the server.json manifest for publishing an MCP server to registry.modelcontextprotocol.io, how to republish after a version bump, and how the registry relates to aggregators, marketplaces, and direct distribution.",
        "kind": "sub",
        "order": 7,
        "html": "https://changegamer.ai/articles/mcp-server-registry-publishing-playbook",
        "markdown": "https://changegamer.ai/articles/mcp-server-registry-publishing-playbook.md",
        "json": "https://changegamer.ai/api/articles/mcp-server-registry-publishing-playbook.json"
      },
      {
        "slug": "mcp-server-cost-optimization",
        "title": "MCP Server Cost Optimization: Toolset Size, Caching Hints, and Fan-Out",
        "description": "How the token cost of an MCP server's tool list, the 2026-07-28 spec's ttlMs/cacheScope caching hints, fan-out from callers you do not control, and per-tool-name cost visibility each shape what a production MCP server actually costs to run.",
        "kind": "sub",
        "order": 8,
        "html": "https://changegamer.ai/articles/mcp-server-cost-optimization",
        "markdown": "https://changegamer.ai/articles/mcp-server-cost-optimization.md",
        "json": "https://changegamer.ai/api/articles/mcp-server-cost-optimization.json"
      },
      {
        "slug": "mcp-server-failure-modes",
        "title": "Common MCP Server Failure Modes and How to Fix Them",
        "description": "A runtime playbook for the two MCP server failure modes with no dedicated deep-dive elsewhere: unrecoverable state after a mid-call crash, and malformed or hallucinated tool calls that reach the handler despite upstream validation.",
        "kind": "sub",
        "order": 9,
        "html": "https://changegamer.ai/articles/mcp-server-failure-modes",
        "markdown": "https://changegamer.ai/articles/mcp-server-failure-modes.md",
        "json": "https://changegamer.ai/api/articles/mcp-server-failure-modes.json"
      },
      {
        "slug": "mcp-resources-and-prompts-vs-tools",
        "title": "MCP Tools vs Resources vs Prompts: How to Choose the Right Primitive",
        "description": "A decision procedure for MCP's three server-side primitives — who controls each one, a worked example of what it costs to expose a Resource as a Tool by mistake, and how Sampling and Elicitation fit as the client-side counterparts.",
        "kind": "sub",
        "order": 10,
        "html": "https://changegamer.ai/articles/mcp-resources-and-prompts-vs-tools",
        "markdown": "https://changegamer.ai/articles/mcp-resources-and-prompts-vs-tools.md",
        "json": "https://changegamer.ai/api/articles/mcp-resources-and-prompts-vs-tools.json"
      },
      {
        "slug": "mcp-server-production-launch-checklist",
        "title": "The MCP Server Production Launch Checklist",
        "description": "A phase-by-phase go/no-go checklist for launching an MCP server: checkable gate conditions for transport and auth, tool design, cross-client testing, publish readiness, observability, and ongoing operation — with links to the mechanics each gate depends on.",
        "kind": "sub",
        "order": 11,
        "html": "https://changegamer.ai/articles/mcp-server-production-launch-checklist",
        "markdown": "https://changegamer.ai/articles/mcp-server-production-launch-checklist.md",
        "json": "https://changegamer.ai/api/articles/mcp-server-production-launch-checklist.json"
      },
      {
        "slug": "mcp-enterprise-sso-id-jag",
        "title": "Zero-Touch Enterprise Authorization for MCP Servers: ID-JAG and SEP-990",
        "description": "How Enterprise-Managed Authorization (SEP-990) removes the per-server OAuth consent screen for MCP servers: the ID-JAG grant mechanism, its RFC 8693/7523 building blocks, named launch adopters as of August 2026, and how it layers on top of standard OAuth 2.1 rather than replacing it.",
        "kind": "sub",
        "order": 12,
        "html": "https://changegamer.ai/articles/mcp-enterprise-sso-id-jag",
        "markdown": "https://changegamer.ai/articles/mcp-enterprise-sso-id-jag.md",
        "json": "https://changegamer.ai/api/articles/mcp-enterprise-sso-id-jag.json"
      }
    ]
  },
  "navigation": {
    "pillar": {
      "slug": "mcp-server-in-production",
      "title": "MCP Server in Production: How to Build, Ship and Run One",
      "description": "The operator playbook for taking an MCP server past the quickstart: transport choice, OAuth 2.1 auth, tool design, versioning against a moving spec, testing across clients, distribution, observability, cost and the failure modes that show up once real clients connect.",
      "kind": "pillar",
      "order": 0,
      "html": "https://changegamer.ai/articles/mcp-server-in-production",
      "markdown": "https://changegamer.ai/articles/mcp-server-in-production.md",
      "json": "https://changegamer.ai/api/articles/mcp-server-in-production.json"
    },
    "previous": {
      "slug": "mcp-server-cost-optimization",
      "title": "MCP Server Cost Optimization: Toolset Size, Caching Hints, and Fan-Out",
      "description": "How the token cost of an MCP server's tool list, the 2026-07-28 spec's ttlMs/cacheScope caching hints, fan-out from callers you do not control, and per-tool-name cost visibility each shape what a production MCP server actually costs to run.",
      "kind": "sub",
      "order": 8,
      "html": "https://changegamer.ai/articles/mcp-server-cost-optimization",
      "markdown": "https://changegamer.ai/articles/mcp-server-cost-optimization.md",
      "json": "https://changegamer.ai/api/articles/mcp-server-cost-optimization.json"
    },
    "next": {
      "slug": "mcp-resources-and-prompts-vs-tools",
      "title": "MCP Tools vs Resources vs Prompts: How to Choose the Right Primitive",
      "description": "A decision procedure for MCP's three server-side primitives — who controls each one, a worked example of what it costs to expose a Resource as a Tool by mistake, and how Sampling and Elicitation fit as the client-side counterparts.",
      "kind": "sub",
      "order": 10,
      "html": "https://changegamer.ai/articles/mcp-resources-and-prompts-vs-tools",
      "markdown": "https://changegamer.ai/articles/mcp-resources-and-prompts-vs-tools.md",
      "json": "https://changegamer.ai/api/articles/mcp-resources-and-prompts-vs-tools.json"
    }
  },
  "resources": [
    {
      "slug": "durable-execution-for-agents",
      "html": "https://changegamer.ai/resources/durable-execution-for-agents",
      "markdown": "https://changegamer.ai/resources/durable-execution-for-agents.md",
      "json": "https://changegamer.ai/api/resources/durable-execution-for-agents.json"
    },
    {
      "slug": "reliable-tool-calling",
      "html": "https://changegamer.ai/resources/reliable-tool-calling",
      "markdown": "https://changegamer.ai/resources/reliable-tool-calling.md",
      "json": "https://changegamer.ai/api/resources/reliable-tool-calling.json"
    }
  ]
}