Skip to content

Design: MCP DCR honesty — drop the mock-DCR short-circuit, pin agentgateway GA

  • Bead: hl-0sr.26 (child of epic hl-0sr)
  • Date: 2026-06-28
  • Status: Draft (pending design-reviewer gate)
  • Author: Sean (with Claude)
  • Corrects: docs/engineering/specs/2026-06-06-llm-gw-mcp-gw-migration-design.md (D3/D10/D13) and ADR hl-23m

The mcp-engram-oauth AgentgatewayPolicy (argocd/app-configs/agentgateway/mcp-engram.yaml) sets jwtAuthentication.mcp.clientId: "mcp-public" with a comment reading “mock-DCR short-circuit (Authentik has no RFC 7591 DCR)”. The intent (spec D3/D13, ADR hl-23m) was that agentgateway serve a mock RFC 7591 /register returning the pre-configured mcp-public client_id, so DCR-requiring MCP clients work despite Authentik lacking DCR.

Deployed reality: the mock-DCR is unreachable — POST /register and GET /.well-known/oauth-authorization-server/... both 404 (found verifying hl-0sr.17). The clientId field is, in effect, inert dead config. Current clients (Claude Code) are unaffected because they use the static mcp-public PKCE client directly (verified end-to-end in hl-0sr.17); they never exercise the mock-DCR path.

The spec and ADR therefore describe a capability the cluster does not have and that the deployed config implies but does not deliver. This design stops the pretense.

The mock-DCR is not “a missing HTTPRoute match away from working” — a 2026-06-07 source-level read of agentgateway v1.3.0-alpha.1 (crates/agentgateway/src/mcp/auth.rs) showed it is structurally unusable against Authentik:

  1. Without mcp.provider the gateway never interposes as the authorization server: the PRM’s authorization_servers points at the raw Authentik issuer and /.well-known/oauth-authorization-server is not served, so the clientId /register short-circuit is unreachable regardless of route matches.
  2. With mcp.provider (enum Auth0 | Keycloak | Okta only — no generic, no Authentik adapter) the AS-metadata proxy hard-requires registration_endpoint in the IdP discovery document and returns HTTP 500 (confirmed for Okta/Keycloak via ProxyError::ProcessingString; Auth0 unconfirmed — moot, since Authentik is not in the enum at all) when absent. Authentik’s discovery has none.

Net: mock-DCR cannot work against Authentik in this version, with or without provider.

A 2026-06-28 deepwiki query asserted clientId short-circuits client_registration independent of provider; that assertion is accurate at the function level (clientIdbuild_mock_dcr_response regardless of provider) but does not establish route reachability. The source read above shows the mock-DCR route (/register) and /.well-known/oauth-authorization-server are not served without provider, so no request ever reaches the short-circuit — and the bead’s live 404 probes confirm the unreachability. Function-level provider-independence and route-level reachability are non-contradictory; the latter is what makes mock-DCR unusable against Authentik here. See engram memory 9b080d3a for the trace.

Go-forward DCR stance (grounded 2026-06-28: gh releases + issues, deepwiki, context7)

Section titled “Go-forward DCR stance (grounded 2026-06-28: gh releases + issues, deepwiki, context7)”
  • Neither DCR mode is deprecated. Mock-DCR (clientIdbuild_mock_dcr_response) is “stable and supported”; real DCR-proxy (provider) is the dynamic-registration path.
  • Mock-DCR is incomplete: agentgateway issue #1936 (OPEN) — “MCP clientId mock DCR response is missing RFC 7591 metadata fields” — strict DCR clients may reject the response even if reachable.
  • Real DCR-proxy is IdP-adapter-gated: McpIDP = Auth0 | Keycloak | Okta only. No Authentik adapter exists and none is planned. Generic-issuer DCR-proxy (no provider) is unreliable (provider-specific CORS + AS-metadata rewriting); “might work if the IdP exposes a spec-compliant registration_endpoint at the default path” but with no guarantee. context7 frames non-listed IdPs as “added with minimal code changes” = write an adapter.
  • Authentik DCR is on a real roadmap: goauthentik/authentik#8751 is OPEN, labeled enhancement + enhancement/confirmed (“will be implemented”), milestoned to “Release 2026.8.0: Required” (~Aug 2026, ~5 weeks from 2026-06-28). Not “no roadmap” — a committed deliverable. (The epic’s earlier “planned ~2026-08” note understated this as a vague hope.)
  • Relevant fixed bug: agentgateway #1205 (CLOSED) — “RFC 8414 URL construction incorrect for path-based issuers.” Authentik uses path-based issuers (/application/o/<slug>/), so this fix matters for any future Authentik DCR-proxy.

Approach B — get honest. Drop the mock-DCR; standardize on the static mcp-public PKCE client; correct the spec/ADR/ops docs to match deployed reality; dissolve the obsolete alpha pin by bumping to GA.

Delete clientId: "mcp-public" (and its “mock-DCR short-circuit” comment) from the mcp-engram-oauth policy. Keep jwtAuthentication.mode: Strict + the Authentik issuer/audiences/jwks provider + resourceMetadata (the PRM) — those are the real, working enforcement + discovery pieces. The PRM continues to advertise Authentik directly as the authorization server, which is correct for the static-client model.

No client-facing change; no cutover; no outage. Claude Code already uses static mcp-public and is unaffected.

D2 — Bump agentgateway v1.3.0-alpha.1v1.3.1 GA

Section titled “D2 — Bump agentgateway v1.3.0-alpha.1 → v1.3.1 GA”

The alpha-pin override (ADR hl-23m addendum / spec D10: “no GA release exposes clientId”) is dissolved: v1.3.0 GA shipped 2026-06-18 and v1.3.1 GA is latest (2026-06-22); clientId (added in 1.3.0-alpha) is in GA. Return to the cluster’s latest-GA policy (argocd/CLAUDE.md). Four coupled pin sites:

FileField1.3.0-alpha.1
argocd/cluster-app/templates/agentgateway-controller.yaml:22chart agentgateway-crds targetRevision1.3.1
argocd/cluster-app/templates/agentgateway-controller.yaml:27chart agentgateway targetRevision1.3.1
argocd/app-configs/agentgateway-controller/values-controller.yaml:3controller image tagv1.3.1
argocd/app-configs/agentgateway/parameters.yaml:17data-plane image tagv1.3.1

The two image-tag comments currently cite “alpha required for mcp.clientId CRD field (decision A / ADR hl-23m)” — rewrite them to reflect GA + the D1 removal (the field is no longer used; the pin is latest-GA, no override). The openrouter-generic.yaml:6 comment (“as of agentgateway v1.3.0-alpha.1 Detect does not apply pathPrefix”) is a behavioral observation owned by hl-rpm9.8 — left untouched here.

Side benefit: the bump may resolve hl-0sr.24 (alpha configMapper bug on standalone configs blocks the UI dashboard). Re-verify hl-0sr.24 after the bump; close if resolved.

D3 — Doc corrections (the “get honest” paperwork)

Section titled “D3 — Doc corrections (the “get honest” paperwork)”
  • Spec 2026-06-06-llm-gw-mcp-gw-migration-design.md: add a dated correction note at D3/D10/D13 pointing to this spec and the ADR addendum — agentgateway is the JWT enforcement point + serves the PRM; DCR is not supported against Authentik (mock-DCR structurally unusable: no provider adapter + no registration_endpoint; real DCR-proxy is provider-gated with no Authentik adapter). Static mcp-public pre-provisioning is the cluster standard. D10 alpha-override superseded by the GA pin.
  • ADR hl-23m: append a dated Addendum recording the reversal — the mock-DCR short-circuit was found structurally unusable against Authentik at execution time (source-level, 2026-06-07); the design reverts to static-client “model B”; real DCR-proxy remains contingent (see Future). Preserves the audit trail (original decision and empirical reversal), matching the existing v1.2.1→alpha addendum pattern.
  • Ops/client doc (docs/reference/services.md client-config section, per hl-bb8): state plainly — MCP clients must be pre-configured with mcp-public; DCR is unavailable until Authentik 2026.8.0 ships and agentgateway gains Authentik adapter support (or Authentik’s DCR metadata proves spec-compliant without an adapter). Also bump the stale chart-version reference at docs/reference/services.md:277 (1.3.0-alpha.11.3.1) so the docs match the D2 pin — this file is already touched by this bullet, so it is a free fix, but call it out so the plan doesn’t miss it.

Future (contingent — recorded, not promised)

Section titled “Future (contingent — recorded, not promised)”

Real DCR-proxy requires all of:

  • (a) Authentik 2026.8.0 native DCR shipping (milestoned “Required”, ~Aug 2026), and
  • (b) either an agentgateway Authentik provider 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 is the cluster standard and no clientId config is carried. A deferred bead (hl-0sr.29) is filed to re-evaluate DCR post-2026.8.0 so this is not lost.

  • argocd/app-configs/agentgateway/mcp-engram.yaml — remove clientId + comment (D1).
  • argocd/cluster-app/templates/agentgateway-controller.yaml — two targetRevision (D2).
  • argocd/app-configs/agentgateway-controller/values-controller.yaml — image tag + comment (D2).
  • argocd/app-configs/agentgateway/parameters.yaml — image tag + comment (D2).
  • docs/engineering/specs/2026-06-06-llm-gw-mcp-gw-migration-design.md — correction note at D3/D10/D13 (D3).
  • docs/adr/hl-23m-agentgateway-is-mcp-auth-enforcement-point-dcr-short-circuit.md — Addendum (D3).
  • docs/reference/services.md — client-config DCR note (D3).
  1. jj diff --git shows only the files above; clientId removed, four pins at 1.3.1, comments rewritten.
  2. kubectl --context fzymgc-house apply --dry-run=client -k argocd/app-configs/agentgateway succeeds (manifests still valid after clientId removal).
  3. docker run --rm -v <final-config.yaml>:/c.yaml ghcr.io/agentgateway/agentgateway:v1.3.1 --validate-only -f /c.yaml exits 0 (config valid on the GA binary; uses the --validate-only form per hl-0sr.1).
  4. Post-merge ArgoCD sync: mcp-engram-oauth policy reconciles with no clientId; engram MCP at https://mcp-gw.fzymgc.house/mcp/engram still 401-without-token / 200-with-token (static mcp-public flow unchanged — re-run the hl-0sr.17 client round-trip).
  5. UI dashboard (hl-0sr.24): re-check whether the v1.3.1 GA configMapper bug is resolved; close hl-0sr.24 if so.
  • GA clientId removal is safe — the field was inert (unreachable). The Strict JWT validation + PRM are independent of clientId and remain the enforcement + discovery surface.
  • GA bump carries the usual chart/CRD reconciliation risk — the controller app uses ServerSideApply + RespectIgnoreDifferences for the large CRDs, and sync-wave: -1 orders CRDs before the gateway app. Watch the ArgoCD sync for CRD-drift on the AgentgatewayPolicy CRD; the ignoreDifferences for last-applied-configuration already covers the known large-CRD annotation overflow.
  • The mock-DCR removal forecloses DCR-requiring clients until the Future conditions land. Accepted: no such client exists today, and the static-client path is the documented standard. Tracked by hl-0sr.29.