{
  "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,
  "target_query": "stdio vs Streamable HTTP for MCP servers",
  "secondary_queries": [
    "MCP session handle without Mcp-Session-Id",
    "migrating MCP server from HTTP+SSE to Streamable HTTP",
    "does stdio MCP server need OAuth"
  ],
  "tags": [
    "mcp",
    "agents",
    "protocols",
    "transport",
    "oauth",
    "production"
  ],
  "published": "2026-08-06",
  "updated": "2026-08-06",
  "words": 1628,
  "premium": false,
  "license": "https://changegamer.ai/license.xml",
  "canonical": "https://changegamer.ai/articles/mcp-stdio-vs-streamable-http",
  "markdown": "https://changegamer.ai/articles/mcp-stdio-vs-streamable-http.md",
  "takeaways": [
    "Pick transport by counting clients and machines, not by feature preference: stdio if the server and its one client always run on the same machine, Streamable HTTP the moment a second user, a second client, or a remote deployment enters the picture.",
    "As of the 2026-07-28 spec revision, Streamable HTTP dropped the `initialize`/`initialized` handshake and the `Mcp-Session-Id` header entirely — any request can land on any server instance, and a server that needs cross-call state (a basket, a wizard step) has to mint its own opaque handle and have the model pass it back as an ordinary tool argument on the next call.",
    "Moving a server from stdio to Streamable HTTP is not a drop-in swap of the transport binding — it is also an auth-model change, from \"no OAuth surface, credentials via environment variables\" to \"OAuth 2.1 required if the server authenticates at all,\" and it is legitimate to land on the unauthenticated end of that range for a public, read-only server.",
    "Migrating an existing server off the deprecated HTTP+SSE transport means re-deriving your auth model, not just re-pointing a client library — HTTP+SSE and Streamable HTTP have different auth surfaces, and any code that assumed a stable session ID will misbehave under the stateless 2026-07-28 model unless you replace that assumption with an explicit handle.",
    "WebMCP is not a third MCP transport and does not belong in this decision — it is a same-tab, no-network-hop browser API for a page to expose tools to an in-browser agent, explicitly distinct from MCP's client-server model."
  ],
  "outline": [
    {
      "depth": 2,
      "text": "The decision rule",
      "anchor": "the-decision-rule",
      "url": "https://changegamer.ai/articles/mcp-stdio-vs-streamable-http#the-decision-rule"
    },
    {
      "depth": 2,
      "text": "What Streamable HTTP actually costs you beyond the transport",
      "anchor": "what-streamable-http-actually-costs-you-beyond-the-transport",
      "url": "https://changegamer.ai/articles/mcp-stdio-vs-streamable-http#what-streamable-http-actually-costs-you-beyond-the-transport"
    },
    {
      "depth": 2,
      "text": "Session-handle mechanics under the 2026-07-28 revision",
      "anchor": "session-handle-mechanics-under-the-2026-07-28-revision",
      "url": "https://changegamer.ai/articles/mcp-stdio-vs-streamable-http#session-handle-mechanics-under-the-2026-07-28-revision"
    },
    {
      "depth": 2,
      "text": "The auth switching cost",
      "anchor": "the-auth-switching-cost",
      "url": "https://changegamer.ai/articles/mcp-stdio-vs-streamable-http#the-auth-switching-cost"
    },
    {
      "depth": 2,
      "text": "Migrating off HTTP+SSE",
      "anchor": "migrating-off-http-sse",
      "url": "https://changegamer.ai/articles/mcp-stdio-vs-streamable-http#migrating-off-http-sse"
    },
    {
      "depth": 2,
      "text": "Not to be confused with: WebMCP",
      "anchor": "not-to-be-confused-with-webmcp",
      "url": "https://changegamer.ai/articles/mcp-stdio-vs-streamable-http#not-to-be-confused-with-webmcp"
    },
    {
      "depth": 2,
      "text": "Where this leaves you",
      "anchor": "where-this-leaves-you",
      "url": "https://changegamer.ai/articles/mcp-stdio-vs-streamable-http#where-this-leaves-you"
    }
  ],
  "faq": [
    {
      "question": "How do I decide between stdio and Streamable HTTP for a new MCP server?",
      "answer": "Count clients and machines, not features. If the server will only ever be spawned as a child process by one client on the same machine — a local dev tool, a personal automation — use stdio: zero network exposure, credentials injected via environment variables, no OAuth surface at all. If more than one user, more than one client, or a remote deployment is even plausible, build on Streamable HTTP from the start; retrofitting a network transport onto a server designed around a local child process is a bigger rewrite than starting there."
    },
    {
      "question": "How does an MCP server keep state without Mcp-Session-Id?",
      "answer": "It mints its own handle. As of the 2026-07-28 spec revision (SEP-2575, SEP-2567), MCP removed the `initialize`/`initialized` handshake and the `Mcp-Session-Id` header — there is no protocol-level session for the server to rely on, and no sticky routing guarantee that puts repeat requests on the same instance. A server that needs cross-call state — a shopping basket, a multi-step wizard — creates its own opaque identifier (a `basket_id`, a job token) on the first call and returns it in the response; the model is expected to pass that identifier back as an ordinary tool argument on subsequent calls, the same way it would pass any other parameter."
    },
    {
      "question": "What actually breaks in my auth code when I move a server from stdio to Streamable HTTP?",
      "answer": "Not a missing OAuth flow so much as a credential model that quietly stops being valid. stdio credentials — API keys injected via environment variables — work because the host trusts the process it just spawned; that trust doesn't survive once the caller is an arbitrary remote client. Moving to Streamable HTTP doesn't automatically obligate OAuth (a public, read-only server can stay unauthenticated, the way ChangeGamer's own `/mcp` endpoint does), but if the server authenticates anyone, the environment-variable pattern has to be replaced wholesale with the full OAuth 2.1 flow — there is no lighter-weight remote option in the spec."
    },
    {
      "question": "What breaks when migrating an MCP server from HTTP+SSE to Streamable HTTP?",
      "answer": "Two things, neither of which is a simple find-and-replace. First, the transport binding itself changes — HTTP+SSE and Streamable HTTP are different wire behaviors in your SDK, so you are swapping the transport layer, not tweaking a config flag. Second, and easy to miss, the auth surface changes with it, so any auth code written against the old transport needs to be re-derived rather than carried over unmodified. If your HTTP+SSE-era code additionally assumed a stable session ID for cross-call state, that assumption breaks outright under the 2026-07-28 spec's stateless model and has to be replaced with an explicit handle passed back as a tool argument."
    }
  ],
  "body": "The MCP transport comparison in [MCP server in production](/articles/mcp-server-in-production) tells you what the two transports are. This article is the decision you actually have to make: which one to build, what changes underneath you when you pick Streamable HTTP, and what breaks if you are migrating an existing server rather than starting fresh.\n\n## The decision rule\n\nCount clients and machines, not features. If your server will only ever be spawned as a child process by exactly one client on the same machine — a local dev tool, a personal automation, an integration nobody but you will connect to — **stdio** is correct, and adding anything else is unnecessary surface. The moment a second user, a second client, or a remote deployment becomes plausible, **Streamable HTTP** is correct: retrofitting a network transport onto a server built around a local child process is a bigger rewrite than starting there.\n\nThis is not a preference call. stdio and Streamable HTTP differ in network exposure, auth model, and — as of the 2026-07-28 spec revision — state handling, and each difference cascades into how you write the server, not just how you deploy it ([building an MCP server](/resources/building-mcp-servers)).\n\n| If… | Use | Why the alternative is wrong |\n|---|---|---|\n| One client, one machine, no plan to share it | stdio | Streamable HTTP adds a network surface, an Origin-validation obligation, and a real service to operate, for zero benefit if nobody remote will ever connect |\n| Multiple users or clients need to reach it | Streamable HTTP | stdio has no network path at all — it cannot serve a second machine by design |\n| It has to run somewhere other than the caller's machine | Streamable HTTP | stdio requires the host to spawn the process locally; there is no remote-spawn variant |\n| You are not yet sure | Streamable HTTP | The migration from stdio to a network transport is the expensive direction; the reverse almost never has to happen |\n\n## What Streamable HTTP actually costs you beyond the transport\n\nChoosing Streamable HTTP is not just picking a different SDK binding. It brings two obligations a stdio server never faces, and a third that is new as of 2026-07-28.\n\n**A real network service to operate.** stdio ships as a local process or package with no server to run — the host spawns it and owns its lifecycle. Streamable HTTP is a service you deploy, keep online, put behind TLS, and monitor. The one infrastructure fact grounded in the current spec: statelessness \"simplifies horizontal scaling\" for Streamable HTTP servers — because any request can land on any instance, no sticky routing or shared session store is required in front of a scaled deployment.\n\n**A security checklist that didn't exist a moment ago.** Streamable HTTP adds obligations stdio never faces — Origin-header validation against DNS-rebinding attacks chief among them, detailed in [MCP server in production](/articles/mcp-server-in-production). The decision-relevant point isn't the checklist itself, it's that stdio isn't a shorter version of it: there's no network hop for any of it to attach to, which is exactly why bolting Streamable HTTP onto a server architected around stdio later is a real rewrite, not a config change.\n\n**A stateless core, as of the 2026-07-28 revision.** Most write-ups still describe the older session model — worth getting right before you design your first stateful tool.\n\n## Session-handle mechanics under the 2026-07-28 revision\n\nBefore 2026-07-28, a Streamable HTTP session opened with an `initialize`/`initialized` handshake and could carry an optional `Mcp-Session-Id` header for stateful sessions. **SEP-2575** removes the handshake entirely; **SEP-2567** removes the `Mcp-Session-Id` header along with the protocol-level session it carried ([MCP goes stateless](/resources/mcp-2026-spec-revision)). There is no negotiation step before normal requests, and no session identifier to recognize \"this is the same caller as the last call.\"\n\nThe practical implication for a stateful tool: **any request can now land on any server instance**, with no sticky routing and no shared session store guaranteed by the protocol. If your tool needs to remember something across calls — a shopping basket a user is building, a wizard partway through — the protocol will not do that for you. Instead: the server mints its own opaque handle on the first call — a `basket_id`, a job token — and returns it in the tool result. The model treats that handle like any other value and passes it back as an ordinary argument on the next call that needs the same state.\n\nThis changes where state lives, not whether it can exist. A stateful tool under the 2026-07-28 model looks like:\n\n```\ncreate_basket() -> { basket_id: \"b_8f2a\", items: [] }\nadd_item(basket_id: \"b_8f2a\", sku: \"widget-1\") -> { basket_id: \"b_8f2a\", items: [...] }\n```\n\nrather than relying on a session header to implicitly scope `add_item` to the right basket. The server owns the storage keyed by that handle — a database row, a cache entry with a TTL — the same way it owns any other application state; MCP's transport no longer does that bookkeeping for you.\n\nTwo smaller changes ship in the same revision, and both only matter once you're actually on a network transport: per-request routing headers a gateway can act on without parsing the body, and explicit cache-lifetime hints on list/resource results — mechanics covered in [MCP server in production](/articles/mcp-server-in-production). The reason they belong in this decision at all: neither has a stdio equivalent, because stdio has no gateway sitting in front of it and no multi-instance cache to invalidate.\n\n## The auth switching cost\n\nThis is the part of the stdio-to-Streamable-HTTP move that gets treated as an afterthought and shouldn't be — the two transports have completely different auth models, not just different wire formats ([MCP server authentication](/resources/mcp-server-authentication)).\n\nA **stdio** server has no OAuth surface at all — the spec explicitly says stdio implementations should not follow the HTTP-based OAuth authorization flow, and credentials for whatever upstream API your server calls are injected via environment variables or the host process. That pattern is exactly what stops working the day you switch transports: an environment-variable credential assumes a locally-spawned process the host already trusts, and that assumption is gone the instant the caller is a remote client on the network instead.\n\nA **Streamable HTTP** server that authenticates callers must implement the full OAuth 2.1 flow instead: mandatory PKCE (S256 only), RFC 8707 audience binding against confused-deputy replay, and a hard rule against forwarding a caller's Bearer token to any upstream API — your server gets its own credentials for that.\n\nThe precision point: **moving to Streamable HTTP doesn't automatically mean adding OAuth.** A remote, unauthenticated, read-only server is legitimate — ChangeGamer's own `/mcp` endpoint is exactly that, gating only paid resources behind an application-layer `api_key` argument; which resources that gate covers, and what they cost, is published at [access and pricing](/resources/access-and-pricing) rather than derived from the transport choice. Streamable HTTP makes authentication *possible*, and for anything that writes state or acts on a user's behalf, *necessary* — a switch that doesn't exist on the stdio side at all. Budget for it as a design decision, not a checkbox flipped because the transport changed.\n\n## Migrating off HTTP+SSE\n\nIf you are operating a server built before the 2025-06-18 spec revision made Streamable HTTP the standard remote transport, you are likely still running the older HTTP+SSE transport, and migrating is not a config flag. Two things change together, and both need deliberate work:\n\n- **The transport binding itself.** Streamable HTTP and HTTP+SSE are different wire behaviors in your SDK — a single POST endpoint returning either `application/json` or a `text/event-stream` stream, versus the older SSE-based exchange. That is a real code change in how your server sends and receives messages, not a parameter you toggle.\n- **The auth model underneath it.** Because HTTP+SSE and Streamable HTTP have different auth surfaces, auth code written against the old transport should be re-derived against the current OAuth 2.1 requirements rather than carried over unmodified — do not assume whatever worked under HTTP+SSE still applies.\n\nIf your HTTP+SSE-era server also assumed a stable session identifier for cross-call state, that assumption breaks outright under the 2026-07-28 stateless model, in a way that looks like a bug in your own code rather than a spec change — the fix is the handle pattern above, an explicit identifier passed back as a tool argument. There is no documented dual-transport transition period or specific migration tool; treat it as three steps — swap the transport binding, re-derive the auth model, replace session-ID-shaped state with a handle — then re-test against a real client rather than trusting the old test suite.\n\n## Not to be confused with: WebMCP\n\nIf you are searching around this decision, you will run into WebMCP — it is not a third MCP transport and does not belong in this comparison. WebMCP is a same-tab, no-network-hop browser API that lets a web page expose tools directly to an agent in that same tab, explicitly distinct from MCP's client-server model over stdio or Streamable HTTP ([WebMCP](/resources/webmcp)). It solves a different problem — in-page tool exposure — than the one this article is about.\n\n## Where this leaves you\n\nDefault to stdio for anything genuinely local and single-client, and to Streamable HTTP for everything else — that one question resolves the transport decision correctly in nearly every case. What it does not resolve automatically is auth (gated by whether the server authenticates callers at all, not by which transport it uses) or state (now an explicit design choice under the 2026-07-28 spec, not something the protocol hands you for free). Get those two right alongside the transport decision, and the rest of what a production MCP server needs — tool design, versioning, testing, distribution — is covered in [MCP server in production](/articles/mcp-server-in-production).",
  "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": null,
    "next": {
      "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"
    }
  },
  "resources": [
    {
      "slug": "building-mcp-servers",
      "html": "https://changegamer.ai/resources/building-mcp-servers",
      "markdown": "https://changegamer.ai/resources/building-mcp-servers.md",
      "json": "https://changegamer.ai/api/resources/building-mcp-servers.json"
    },
    {
      "slug": "mcp-server-authentication",
      "html": "https://changegamer.ai/resources/mcp-server-authentication",
      "markdown": "https://changegamer.ai/resources/mcp-server-authentication.md",
      "json": "https://changegamer.ai/api/resources/mcp-server-authentication.json"
    },
    {
      "slug": "mcp-2026-spec-revision",
      "html": "https://changegamer.ai/resources/mcp-2026-spec-revision",
      "markdown": "https://changegamer.ai/resources/mcp-2026-spec-revision.md",
      "json": "https://changegamer.ai/api/resources/mcp-2026-spec-revision.json"
    },
    {
      "slug": "webmcp",
      "html": "https://changegamer.ai/resources/webmcp",
      "markdown": "https://changegamer.ai/resources/webmcp.md",
      "json": "https://changegamer.ai/api/resources/webmcp.json"
    }
  ]
}