{
  "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,
  "target_query": "how to implement OAuth 2.1 for an MCP server",
  "secondary_queries": [
    "oauth-protected-resource metadata fields",
    "CIMD vs Dynamic Client Registration for MCP",
    "validating MCP OAuth token audience and issuer"
  ],
  "tags": [
    "mcp",
    "agents",
    "protocols",
    "oauth",
    "security",
    "production"
  ],
  "published": "2026-08-07",
  "updated": "2026-08-07",
  "words": 1548,
  "premium": false,
  "license": "https://changegamer.ai/license.xml",
  "canonical": "https://changegamer.ai/articles/mcp-oauth-implementation",
  "markdown": "https://changegamer.ai/articles/mcp-oauth-implementation.md",
  "takeaways": [
    "The discovery chain is two JSON documents a client fetches before it ever authenticates: `/.well-known/oauth-protected-resource` (RFC 9728), which lists the authorization servers your server trusts, and `/.well-known/oauth-authorization-server` (RFC 8414) on that AS, which returns `authorization_endpoint`, `token_endpoint` and `registration_endpoint` — get either response wrong and no client can complete the flow.",
    "A Client ID Metadata Document (CIMD) replaces server-side client registration with a fetch: the `client_id` your server receives is itself an HTTPS URL, and your authorization server resolves it by fetching that URL for a JSON document describing the client, instead of looking up a row a Dynamic Client Registration call previously wrote to a database.",
    "Of the six 2026-07-28 authorization-hardening SEPs, three change what a server must actively validate or emit: SEP-2468 requires checking the `iss` claim against RFC 9207, SEP-837 adds an `application_type` field your registration handler has to read, and SEP-2350 requires accepting incremental scope requests during step-up re-authorization instead of forcing a full re-grant.",
    "Token validation on every request is three checks, not one: audience (does the `aud` claim match this server's URL), issuer (does `iss` match the authorization server your Protected Resource Metadata actually names), and signature/validity (via the AS's published keys or an introspection call) — a token that passes only the first check is still forgeable or replayable.",
    "A rejected request should look like a signpost, not a dead end: an HTTP 401 whose `WWW-Authenticate` header points back at your Protected Resource Metadata document, so a compliant client can restart discovery instead of failing silently."
  ],
  "outline": [
    {
      "depth": 2,
      "text": "What the discovery documents actually contain",
      "anchor": "what-the-discovery-documents-actually-contain",
      "url": "https://changegamer.ai/articles/mcp-oauth-implementation#what-the-discovery-documents-actually-contain"
    },
    {
      "depth": 2,
      "text": "CIMD vs. DCR: what actually changes in your server's code",
      "anchor": "cimd-vs-dcr-what-actually-changes-in-your-server-s-code",
      "url": "https://changegamer.ai/articles/mcp-oauth-implementation#cimd-vs-dcr-what-actually-changes-in-your-server-s-code"
    },
    {
      "depth": 2,
      "text": "Three of the six 2026-07-28 hardening SEPs, in implementation detail",
      "anchor": "three-of-the-six-2026-07-28-hardening-seps-in-implementation-detail",
      "url": "https://changegamer.ai/articles/mcp-oauth-implementation#three-of-the-six-2026-07-28-hardening-seps-in-implementation-detail"
    },
    {
      "depth": 2,
      "text": "Token validation: what your handler actually checks, in order",
      "anchor": "token-validation-what-your-handler-actually-checks-in-order",
      "url": "https://changegamer.ai/articles/mcp-oauth-implementation#token-validation-what-your-handler-actually-checks-in-order"
    },
    {
      "depth": 2,
      "text": "An honest example, extended",
      "anchor": "an-honest-example-extended",
      "url": "https://changegamer.ai/articles/mcp-oauth-implementation#an-honest-example-extended"
    },
    {
      "depth": 2,
      "text": "Where this leaves you",
      "anchor": "where-this-leaves-you",
      "url": "https://changegamer.ai/articles/mcp-oauth-implementation#where-this-leaves-you"
    }
  ],
  "faq": [
    {
      "question": "What exactly does a client read from oauth-protected-resource and oauth-authorization-server?",
      "answer": "The Protected Resource Metadata document at `/.well-known/oauth-protected-resource` on your MCP server's base URL exists to answer one question for the client: which authorization server(s) do you trust for this resource. The client then takes that authorization server's URL and fetches `/.well-known/oauth-authorization-server` on it — the Authorization Server Metadata defined by RFC 8414 — to get back the three endpoints it needs to actually run the flow: `authorization_endpoint` (where to send the user to log in and consent), `token_endpoint` (where to exchange a code for a token), and `registration_endpoint` (where to register a client, if Dynamic Client Registration is in play at all). Both documents are static JSON your server or its authorization server serves at a fixed, well-known path — no request parameters, no session state."
    },
    {
      "question": "Do I need to write a client registration endpoint if I use CIMD instead of DCR?",
      "answer": "No — that is the entire appeal of CIMD from a server-operator's perspective. Dynamic Client Registration (RFC 7591) requires your authorization server to expose a `registration_endpoint` that accepts a POST, validates the payload, persists a new client record, and returns a `client_id` your server now has to store and manage indefinitely. A Client ID Metadata Document sidesteps all of that: the client already has an HTTPS URL it controls, that URL serves a static JSON document describing the client, and your authorization server treats the URL itself as the `client_id` — resolving it with an HTTP fetch at authorization time instead of a database lookup. You still need to fetch and validate that document, but there is no registration handler, no client-record table, and no registration endpoint to secure."
    },
    {
      "question": "What does token audience and issuer validation actually check, mechanically?",
      "answer": "Audience validation confirms the `aud` claim on the presented token names your specific MCP server URL — set via the `resource` parameter (RFC 8707) at authorization time — so a token minted for a different server cannot be replayed against yours. Issuer validation, tightened under SEP-2468 in the 2026-07-28 spec revision, confirms the `iss` claim matches the authorization server your own Protected Resource Metadata document actually names, per RFC 9207, closing a bug class where a token gets redeemed against the wrong server entirely. Neither check tells you the token is genuine and unexpired on its own — that third check is a signature verification against the authorization server's published keys, or a live introspection call to the AS, depending on which token format your AS issues."
    }
  ],
  "body": "The auth section of [MCP server in production](/articles/mcp-server-in-production) covers what a compliant OAuth 2.1 flow requires: PKCE, RFC 8707 audience binding, the confused-deputy prohibition. It is a checklist, not a wire trace — it tells you the five steps exist without showing what actually crosses the network at each one, or what changes in your server's own code between the two client-registration paths. This article is that wire trace, plus what the six 2026-07-28 hardening SEPs concretely make you implement.\n\nEverything below assumes a remote Streamable HTTP server; a stdio server has no OAuth surface at all, and that decision is covered in [stdio vs. Streamable HTTP](/articles/mcp-stdio-vs-streamable-http).\n\n## What the discovery documents actually contain\n\nA client does not guess your authorization endpoints — it fetches two static JSON documents, in order, before it can authenticate at all.\n\n**`/.well-known/oauth-protected-resource`**, served from your MCP server's own base URL, is the Protected Resource Metadata defined by RFC 9728. Its job is narrow: tell the client which authorization server(s) your server trusts. A client reads it once at the start of the flow to know where to go next — nothing in it is a credential; it is pure discovery.\n\n**`/.well-known/oauth-authorization-server`**, served from the authorization server's own base URL (not yours), is the Authorization Server Metadata defined by RFC 8414. This is the document a client actually parses to build the flow: it returns the `authorization_endpoint` a client redirects a user to for login and consent, the `token_endpoint` it POSTs to for the code exchange, and the `registration_endpoint` it uses if Dynamic Client Registration is in play. If either document is missing, malformed, or wrong, no client can complete the flow regardless of how correctly it implements everything downstream — the most common early-implementation failure is getting PKCE and audience binding right while serving a broken or absent metadata document that never lets a client reach that code at all.\n\nOnce discovery resolves, the authorization and token requests each carry two things worth naming because they are easy to omit silently: the `resource` parameter from RFC 8707, set to your MCP server's own URL, which is what lets the authorization server bind the issued token's audience to your server specifically; and the PKCE pair — a `code_verifier` the client generates and keeps, and a `code_challenge` derived from it (S256 only, per the pillar's security guidance) that travels in the authorization request. Your server never sees either PKCE value directly — that exchange happens between the client and the authorization server — but the token your server later validates is the downstream product of both being present and correct.\n\n## CIMD vs. DCR: what actually changes in your server's code\n\nThe pillar names the priority order between these two client-registration paths; what it does not show is what each one actually requires you to build, and that is where the real implementation cost differs.\n\n**Dynamic Client Registration (RFC 7591)** requires your authorization server to run a registration endpoint: a POST handler that accepts a JSON payload describing the client (redirect URIs, a display name, a client type), validates it, mints a new `client_id` (and, for confidential clients, a secret), persists a client record somewhere durable, and returns the credentials. From then on your AS owns a client-record table it has to manage — updating entries when a redirect URI changes, pruning stale registrations, and treating the endpoint itself as attack surface, since it is an unauthenticated POST that creates state.\n\n**A Client ID Metadata Document (CIMD)** removes that table entirely. The `client_id` a CIMD-using client presents is itself an HTTPS URL — something the client's own operator controls and serves — pointing at a JSON document describing the client the same way a DCR payload would (redirect URIs, a display name). Your authorization server's job changes from \"look up a row this `client_id` should match\" to \"fetch this URL and parse what comes back\": an HTTP GET at authorization time, rather than a database read against a row a registration call wrote earlier. No registration endpoint to write or secure and no stale-registration cleanup — but a new obligation to fetch that document reliably (sane timeout, TLS verification) every time it is needed, since there is no local \"this client is known good\" cache the way a database row provides.\n\nIf you are implementing the authorization-server side yourself rather than delegating to a provider such as Auth0 or Keycloak: DCR means writing and hardening a registration handler; CIMD means writing a document fetcher and validator, treating the fetched JSON with the same untrusted-input discipline as any external content. Both are legitimate simultaneously — CIMD as the default, DCR retained for clients that have not adopted it — the priority order the pillar describes.\n\n## Three of the six 2026-07-28 hardening SEPs, in implementation detail\n\nThe pillar lists all six 2026-07-28 authorization SEPs in one paragraph. Three of them require you to actually write new validation or registration-handling code, not just be aware the SEP exists ([MCP goes stateless](/resources/mcp-2026-spec-revision)):\n\n- **SEP-2468 — `iss` validation per RFC 9207.** Your token-validation code needs an explicit check, separate from audience validation, that the `iss` claim names the authorization server your Protected Resource Metadata lists as trusted. Without it, a token issued by a *different* AS your server never declared trust in — but that still passes signature verification — could be redeemed against you. This closes a wrong-server token-redemption bug class that audience binding alone does not.\n- **SEP-837 — `application_type` on Dynamic Client Registration.** A DCR-capable registration endpoint now needs to read an `application_type` field from the payload and branch on it, rather than defaulting every client to \"web.\" The failure this fixes: servers assuming \"web\" for every client were rejecting `localhost` redirect URIs from desktop and CLI clients, for whom `localhost` is the normal pattern, not a misconfiguration.\n- **SEP-2350 — incremental step-up scopes.** If your server supports scoped permissions, the re-authorization path needs to accept a request for additional scopes on top of what a client already holds, instead of forcing a full re-grant from zero — a distinct, supported code path, not a config flag.\n\nThe other three — SEP-2351 (discovery-suffix clarification), SEP-2352 (credential reissuance on AS migration), SEP-2207 (refresh tokens from OIDC-style servers) — are narrower and situational, and don't reshape every server's validation code the way the three above do.\n\n## Token validation: what your handler actually checks, in order\n\nEvery authenticated request needs the same sequence of checks, and skipping or reordering them is where implementations quietly become insecure rather than obviously broken:\n\n1. **Audience.** Does `aud` match this server's own URL — the `resource` parameter (RFC 8707) set at authorization time? A token that passes every other check but names a different audience must still be rejected; this is the check that stops a confused-deputy replay.\n2. **Issuer.** Does `iss` match the authorization server your Protected Resource Metadata names as trusted, per RFC 9207 and SEP-2468? A token can have the right audience and still fail here if issued by an AS you never declared trust in.\n3. **Signature and validity.** Is the token genuine and unexpired — a local signature check against the AS's published signing keys, or a live introspection call to the AS, depending on the token format it issues? The corpus this article draws from specifies the audience- and issuer-binding requirements but not one mandated token format, so confirm which mechanism your AS supports before building against it.\n\nA request failing any of these three gets an HTTP 401, and a compliant response does more than reject it: the `WWW-Authenticate` header should point back at your Protected Resource Metadata document, so the client can restart discovery from a known-good location. Confirm exact header syntax against RFC 9728 directly before shipping it — the shape is a signpost back to `/.well-known/oauth-protected-resource`, not a bare rejection.\n\n## An honest example, extended\n\nChangeGamer's own `/mcp` endpoint is unauthenticated as of August 2026 — no OAuth flow, no RFC 9728 metadata — because it is public and read-only, with paid content gated at the application layer instead. What that gate actually covers — the current premium resource list and its pricing — is published separately at [access and pricing](/resources/access-and-pricing), not embedded in the MCP tool schema. Adding OAuth would concretely mean: standing up the two discovery documents above (a minimal Protected Resource Metadata pointing at one trusted AS), choosing CIMD over a registration endpoint (ChangeGamer only needs to vet its own clients, not arbitrary ones), and replacing the current `api_key` argument check with the three-step token validation above — a materially larger surface than today's single string comparison. That gap is why the pillar treats unauthenticated-but-key-gated as legitimate for a narrow, read-only case, not a shortcut every server should take.\n\n## Where this leaves you\n\nThe discovery documents, CIMD's document-fetch model, the three SEPs that add real validation code, and the three-check token-validation sequence above are the parts of OAuth 2.1 for MCP that only show up once you are implementing it, not just deciding to require it. For the decision-level version — whether you need OAuth at all, the confused-deputy rule, the CIMD/DCR priority order — see the auth section of [MCP server in production](/articles/mcp-server-in-production); for the broader security posture beyond auth specifically, see the [agentic security checklist](/resources/agentic-security-checklist).",
  "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-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"
    },
    "next": {
      "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"
    }
  },
  "resources": [
    {
      "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": "agentic-security-checklist",
      "html": "https://changegamer.ai/resources/agentic-security-checklist",
      "markdown": "https://changegamer.ai/resources/agentic-security-checklist.md",
      "json": "https://changegamer.ai/api/resources/agentic-security-checklist.json"
    },
    {
      "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"
    }
  ]
}