Skip to content

agentgateway is the MCP auth enforcement point + DCR short-circuit (engram stays the Resource Server)

Date: 2026-06-06 Status: Accepted Decision: hl-23m Deciders: sean

Authentik does NOT support OAuth Dynamic Client Registration (RFC 7591) as of 2026-06 (goauthentik/authentik#8751, planned ~2026-08). MCP clients commonly require DCR against the authorization server; LiteLLM filled this gap as a broker, but the broker pattern conflicts with the June 2025 MCP Resource Server model. A decision was needed on where JWT validation lives, how DCR-dependent clients work, and whether to migrate IdP.

agentgateway enforces MCP JWT validation in Strict mode against Authentik (issuer/JWKS/audiences), serves /.well-known/oauth-protected-resource, proxies Authentik AS metadata, and provides a mock RFC 7591 /register endpoint returning a pre-configured mcp-public public PKCE client_id. engram continues to validate the forwarded token as defense-in-depth (no engram code change — only a values-level accepted-audience addition). Stay on Authentik.

  • Authentik’s DCR gap is a known, tracked upstream issue with a projected fix; the mock short-circuit is a minimal, contained workaround that unblocks DCR-dependent MCP clients today (the clientId short-circuit is generic — works for an Authentik issuer with no provider adapter).
  • Keeping engram as the RS minimizes coupling: agentgateway validates+forwards, engram re-validates.
  • A dedicated mcp-public client (separate from the live memory-mcp client) is added additively at P3 — no dual-state conflict, no disruption to the live LiteLLM broker.
  • agentgateway AS-shim + mock DCR (CHOSEN) — serves PRM + proxies AS metadata + mock /register w/ pre-set client_id; Strict JWT validation; engram defense-in-depth. Cost: mock DCR (not real dynamic registration); revisit when Authentik ships DCR.
  • Migrate IdP to one with native DCR (e.g. Keycloak/Zitadel) — rejected for this scope: Authentik is the cluster’s central IdP (all OIDC apps, forward-auth outposts, k8s OIDC RBAC, tf/authentik/*); migration is a separate, much larger project. DCR is too thin a reason alone, and the one concrete need is already solved.
  • No MCP gateway (expose engram directly via Authentik-protected ingress) — rejected: loses centralized MCP visibility/control (a stated goal); DCR gap remains.

Positive: DCR-dependent MCP clients work against Authentik today without Authentik shipping DCR; engram auth code unchanged; no Authentik migration; existing SSO unaffected. Negative: mock /register is not real dynamic registration (static client_id); when Authentik ships DCR the short-circuit config should be revisited. Neutral: the live memory-mcp client + LiteLLM broker coexist until P5 with no conflict.

Addendum (2026-06-06): version requirement discovered at implementation

Section titled “Addendum (2026-06-06): version requirement discovered at implementation”

During execution (hl-0sr drain, decision hl-0sr.22), the clientId mock-DCR field was found to be absent in agentgateway v1.2.1: standalone RawConfig is serde(deny_unknown_fields), so a config carrying mcpAuthentication.clientId hard-fails to load. The field was added to standalone LocalMcpAuthentication only in 1.3.0-alpha (consumed by build_mock_dcr_response); no GA release exposes it.

Resolution (accepted): pin agentgateway to v1.3.0-alpha.1, consciously overriding the cluster latest-GA policy (spec D10) for this component, to keep DCR-client compatibility now rather than wait for a 1.3.0 GA or Authentik DCR (~2026-08). The mock-DCR decision above stands; only the minimum version is corrected (≥1.3.0-alpha). Revisit the pin when 1.3.0 reaches GA.

Addendum (2026-06-28): mock-DCR short-circuit reverted — structurally unusable against Authentik

Section titled “Addendum (2026-06-28): mock-DCR short-circuit reverted — structurally unusable against Authentik”

Status change: the mock-DCR short-circuit (the clientIdbuild_mock_dcr_response path above) is reverted. The cluster standardizes on the static mcp-public PKCE client (“model B” from the original Alternatives). The jwtAuthentication Strict JWT validation + PRM (resourceMetadata) enforcement surface stands unchanged — only the mock-DCR clientId field is removed.

Why (grounded, source-level): a 2026-06-07 read of agentgateway v1.3.0-alpha.1 source (crates/agentgateway/src/mcp/auth.rs) showed the mock-DCR is structurally unusable against Authentik, not merely mis-routed: (1) without mcp.provider the gateway never interposes as the authorization server, so /.well-known/oauth-authorization-server is not served and the clientId /register short-circuit is unreachable; (2) with mcp.provider (enum Auth0 | Keycloak | Okta only — no Authentik adapter) the AS-metadata proxy hard-requires registration_endpoint in the IdP discovery doc and returns HTTP 500 (confirmed for Okta/Keycloak via ProxyError::ProcessingString; Auth0 unconfirmed — moot, since Authentik is not in the enum) when absent, and Authentik’s discovery has none. Net: mock-DCR cannot work against Authentik in this version, with or without provider. Live probes (hl-0sr.26) confirmed 404s on every registration path. (A 2026-06-28 deepwiki query asserted clientId short-circuits client_registration independent of provider; that is accurate at the function level but does not establish route reachability — the source read shows the /register route and /.well-known/oauth-authorization-server are not served without provider, so no request reaches the short-circuit. Function-level provider-independence and route-level reachability are non-contradictory; the latter is what makes mock-DCR unusable here.)

Go-forward stance (gh releases + issues, deepwiki, context7 — 2026-06-28): neither DCR mode is deprecated, but real DCR-proxy is IdP-adapter-gated (McpIDP = Auth0 | Keycloak | Okta; no Authentik adapter, none planned), and the mock-DCR is incomplete (issue #1936 — missing RFC 7591 metadata fields). Authentik DCR is on a real roadmap — goauthentik/authentik#8751 is enhancement/confirmed, milestoned to “Release 2026.8.0: Required” (~Aug 2026).

Version pin correction: the v1.3.0-alpha.1 pin above is obsoletev1.3.0 GA shipped 2026-06-18 and v1.3.1 GA is latest (2026-06-22); clientId is in GA. The cluster returns to latest-GA: pin v1.3.1. The D10 alpha-override is superseded.

Future (contingent, not promised): real DCR-proxy requires (a) Authentik 2026.8.0 native DCR shipping and (b) either an agentgateway Authentik adapter (does not exist, not planned) or Authentik’s DCR + AS-metadata being spec-compliant at the default path with no CORS/metadata quirk requiring an adapter. (b) is the open unknown — verify at the 2026.8.0 ship date. Until then: static mcp-public, no clientId config. Tracked by hl-0sr.29.

Spec of record: docs/engineering/specs/2026-06-28-mcp-dcr-honesty-design.md (bead hl-0sr.26).