MCP DCR Honesty — Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Drop the inert mock-DCR clientId from the engram MCP policy, bump agentgateway v1.3.0-alpha.1 → v1.3.1 GA, and correct the docs to match deployed reality.
Architecture: Pure GitOps config + docs change. agentgateway stays the MCP JWT enforcement point + serves the RFC 9728 Protected Resource Metadata (PRM); only the fake mock-DCR clientId field is removed. The version pin returns to the cluster latest-GA policy now that clientId (and the rest of the 1.3.0 line) is in GA. No client-facing change — Claude Code already uses the static mcp-public PKCE client.
Tech Stack: Kubernetes (kustomize), ArgoCD (GitOps), agentgateway CRDs agentgateway.dev/v1alpha1 (v1.3.1 GA), Gateway API v1, Authentik OIDC, jj VCS.
Spec: docs/engineering/specs/2026-06-28-mcp-dcr-honesty-design.md (design-reviewer READY round 2)
Bead: hl-0sr.26 (child of epic hl-0sr)
ADR: hl-23m 2026-06-28 addendum (already written, lands in the docs PR)
TDD note: This is GitOps config + documentation — there are no units to test. Per the writing-plans TDD exception, verification is structural + empirical (kustomize dry-run, --validate-only on the GA binary, post-sync engram round-trip). These appear as the “verify” steps in each task and as Task 5.
File Structure
Section titled “File Structure”All paths are repo-relative (resolve under the workspace root).
| File | Responsibility | Action |
|---|---|---|
argocd/app-configs/agentgateway/mcp-engram.yaml | engram MCP route + JWT policy + PRM | Remove clientId line; keep mcp: + resourceMetadata |
argocd/cluster-app/templates/agentgateway-controller.yaml | ArgoCD app for CRDs + controller chart | Bump 2× targetRevision |
argocd/app-configs/agentgateway-controller/values-controller.yaml | controller image tag | Bump tag + rewrite comment |
argocd/app-configs/agentgateway/parameters.yaml | data-plane image tag + AgentgatewayParameters | Bump tag + rewrite comment |
docs/reference/services.md | services catalog (agentgateway + controller rows, client config) | Bump 2 chart-version rows; add DCR note |
docs/engineering/specs/2026-06-06-llm-gw-mcp-gw-migration-design.md | prior migration spec (D3/D10/D13) | Insert dated correction note |
Not touched (historical records): docs/engineering/specs/2026-06-20-…, docs/engineering/plans/2026-06-20-…, 2026-06-15-…, 2026-06-22-…, and the openrouter-generic.yaml:6 behavioral comment (hl-rpm9.8) — these reference v1.3.0-alpha.1 as a record of their own state and are corrected by the live spec + ADR addendum, not edited in place.
Task 1: Remove the mock-DCR clientId from the engram MCP policy
Section titled “Task 1: Remove the mock-DCR clientId from the engram MCP policy”Files:
-
Modify:
argocd/app-configs/agentgateway/mcp-engram.yaml(themcp-engram-oauthAgentgatewayPolicy, ~lines 81-89) -
Step 1: Edit the
mcp:block inmcp-engram-oauth
Replace this block (the mcp: stanza of the mcp-engram-oauth policy):
mcp: # provider: omitted — Authentik is not Auth0/Keycloak/Okta; generic issuer/jwks used clientId: "mcp-public" # mock-DCR short-circuit (Authentik has no RFC 7591 DCR) resourceMetadata: resource: "https://mcp-gw.fzymgc.house/mcp/engram" # YAML sequence (not a quoted string) so this serializes as a JSON # array in the RFC 9728 protected-resource-metadata document. bearerMethodsSupported: - headerwith:
mcp: # provider: omitted — Authentik is not Auth0/Keycloak/Okta; generic issuer/jwks used. # No clientId/mock-DCR (hl-0sr.26): structurally unusable against Authentik — without # a provider the /register route + /.well-known/oauth-authorization-server are not # served, and Authentik has no registration_endpoint for the provider path either. # Static mcp-public PKCE client (pre-provisioned) is the cluster standard; agentgateway # stays the JWT enforcement point + serves the PRM (resourceMetadata) below. resourceMetadata: resource: "https://mcp-gw.fzymgc.house/mcp/engram" # YAML sequence (not a quoted string) so this serializes as a JSON # array in the RFC 9728 protected-resource-metadata document. bearerMethodsSupported: - headerLeave the rest of mcp-engram.yaml unchanged (the AgentgatewayBackend, HTTPRoute, the jwtAuthentication Strict provider block, and the mcp-engram-auth-passthrough policy are all unaffected).
- Step 2: Verify the manifest still parses
Run: kubectl --context fzymgc-house apply --dry-run=client -k argocd/app-configs/agentgateway
Expected: namespace/agentgateway configured (dry run) (or similar) with no YAML/validation errors.
- Step 3: Commit
jj describe -m 'feat(agentgateway): drop inert mock-DCR clientId from mcp-engram-oauth [hl-0sr.26]
The clientId mock-DCR short-circuit was structurally unusable against Authentik(no provider adapter + no registration_endpoint). Keep Strict JWT validation +the PRM (resourceMetadata); static mcp-public PKCE client is the cluster standard.No client-facing change.
Co-Authored-By: Claude <noreply@anthropic.com>'Task 2: Bump agentgateway v1.3.0-alpha.1 → v1.3.1 GA (manifests)
Section titled “Task 2: Bump agentgateway v1.3.0-alpha.1 → v1.3.1 GA (manifests)”Files:
- Modify:
argocd/cluster-app/templates/agentgateway-controller.yaml(lines 22, 27) - Modify:
argocd/app-configs/agentgateway-controller/values-controller.yaml(line 3) - Modify:
argocd/app-configs/agentgateway/parameters.yaml(lines 14-17) - Step 1: Bump the two chart
targetRevisions
In argocd/cluster-app/templates/agentgateway-controller.yaml, change both occurrences (lines 22 and 27):
targetRevision: "1.3.0-alpha.1"to:
targetRevision: "1.3.1"(Both the agentgateway-crds source at line 22 and the agentgateway chart source at line 27.)
- Step 2: Bump the controller image tag + rewrite its comment
In argocd/app-configs/agentgateway-controller/values-controller.yaml, replace line 3:
tag: "v1.3.0-alpha.1" # v-prefixed image tag; alpha required for mcp.clientId CRD field (decision A / ADR hl-23m)with:
tag: "v1.3.1" # v-prefixed image tag; latest GA (mcp.clientId is GA since v1.3.0; the field was dropped from mcp-engram-oauth in hl-0sr.26, so this pin no longer overrides latest-GA — see ADR hl-23m 2026-06-28 addendum)- Step 3: Bump the data-plane image tag + rewrite its comment
In argocd/app-configs/agentgateway/parameters.yaml, replace the comment + tag block (lines 14-17):
# v-prefixed image tag. 1.3.0-alpha required: the mcp.clientId CRD field (engram # OAuth mock-DCR) exists only in >=1.3.0-alpha — decision A / ADR hl-23m. v1.2.1 CRDs # reject AgentgatewayPolicy/mcp-engram-oauth (field not declared in schema). tag: "v1.3.0-alpha.1"with:
# v-prefixed image tag, latest GA. mcp.clientId (mock-DCR) shipped in GA at v1.3.0 # (2026-06-18); v1.3.1 is current. The clientId field was DROPPED from # mcp-engram-oauth (hl-0sr.26 — structurally unusable against Authentik), so this pin # no longer overrides latest-GA. See ADR hl-23m (2026-06-28 addendum). tag: "v1.3.1"- Step 4: Confirm no other active-config
1.3.0-alpha.1references remain
Run: rg -n '1\.3\.0-alpha\.1|v1\.3\.0-alpha\.1' argocd/
Expected: only argocd/app-configs/agentgateway/openrouter-generic.yaml:6 (the hl-rpm9.8 behavioral comment — intentionally left). No targetRevision or tag lines.
- Step 5: Commit
jj describe -m 'feat(agentgateway): bump v1.3.0-alpha.1 -> v1.3.1 GA [hl-0sr.26]
Alpha-pin override (ADR hl-23m / spec D10) dissolved: clientId shipped in GA atv1.3.0 (2026-06-18), v1.3.1 is latest. Returns to the cluster latest-GA policy.Rewrites the two stale "alpha required for clientId" comments. May resolvehl-0sr.24 (alpha configMapper bug) — re-verify post-sync.
Co-Authored-By: Claude <noreply@anthropic.com>'Task 3: Correct docs/reference/services.md (version bump + DCR note)
Section titled “Task 3: Correct docs/reference/services.md (version bump + DCR note)”Files:
-
Modify:
docs/reference/services.md(lines 277, 317, + new note near the MCP-servers line) -
Step 1: Bump the agentgateway app Charts row (line 277)
Replace:
| Charts | `agentgateway-crds` + `agentgateway` `1.3.0-alpha.1` (images `cr.agentgateway.dev/{controller,agentgateway}:v1.3.0-alpha.1`) |with:
| Charts | `agentgateway-crds` + `agentgateway` `1.3.1` (images `cr.agentgateway.dev/{controller,agentgateway}:v1.3.1`) |- Step 2: Bump the Agentgateway Controller Charts row (line 317)
Replace:
| Charts | `agentgateway-crds` + `agentgateway` controller `1.3.0-alpha.1` |with:
| Charts | `agentgateway-crds` + `agentgateway` controller `1.3.1` |- Step 3: Add a DCR note after the MCP-servers line
Find the line (in the agentgateway section):
**MCP servers:** `engram` (OAuth/Authentik), `exa`, `firecrawl`, `context7`, `fal`, `deepwiki` (the SaaS five gated by virtual key, with per-upstream `Authorization` keys injected from Vault; deepwiki needs no upstream key).Insert immediately after it:
**DCR (Dynamic Client Registration):** not available. MCP clients are pre-provisioned with the static `mcp-public` PKCE client (Authentik public app, any loopback `callbackPort`). agentgateway does **not** serve RFC 7591 DCR — the mock-DCR `clientId` short-circuit was structurally unusable against Authentik (no `provider` adapter — `McpIDP` is `Auth0|Keycloak|Okta` only — and Authentik exposes no `registration_endpoint`). Real DCR-proxy is contingent on Authentik `2026.8.0` native DCR + an adapter or spec-compliant metadata (`hl-0sr.29`). See ADR `hl-23m` (2026-06-28 addendum).- Step 4: Verify the two version references are gone
Run: rg -n '1\.3\.0-alpha\.1' docs/reference/services.md
Expected: no matches.
- Step 5: Commit
jj describe -m 'docs(agentgateway): bump services.md chart pin to 1.3.1 + DCR note [hl-0sr.26]
Bumps the agentgateway + controller Charts rows to 1.3.1 GA and documents thatDCR is not available (static mcp-public PKCE is the standard). Matches deployedreality after the mock-DCR revert.
Co-Authored-By: Claude <noreply@anthropic.com>'Task 4: Add the correction note to the 2026-06-06 migration spec
Section titled “Task 4: Add the correction note to the 2026-06-06 migration spec”Files:
-
Modify:
docs/engineering/specs/2026-06-06-llm-gw-mcp-gw-migration-design.md(insert after the D12 row, before## Architecture) -
Step 1: Insert the correction blockquote
Find the D12 row (the last row of the decisions table, immediately before ## Architecture):
| D12 | **Transitional `litellm.fzymgc.house` alias → `llm-gw`** through cutover, removed at decommission | De-risks any consumer not enumerated here at near-zero cost |
## ArchitectureInsert a blank line + the correction note between the D12 row and ## Architecture, so it reads:
| D12 | **Transitional `litellm.fzymgc.house` alias → `llm-gw`** through cutover, removed at decommission | De-risks any consumer not enumerated here at near-zero cost |
> **Correction (2026-06-28):** D3 / D10 / D13 are **superseded**. The mock-DCR `clientId` short-circuit was found structurally unusable against Authentik at execution time (no `provider` adapter — `McpIDP` is `Auth0|Keycloak|Okta` only — and Authentik exposes no `registration_endpoint`); the cluster standardizes on the static `mcp-public` PKCE client ("model B"). The `v1.3.0-alpha.1` pin (D10) is obsolete — `v1.3.1` GA is current (`clientId` shipped in GA at v1.3.0, 2026-06-18). The `jwtAuthentication` Strict JWT validation + PRM (`resourceMetadata`) enforcement surface stands unchanged. See `docs/engineering/specs/2026-06-28-mcp-dcr-honesty-design.md` and the ADR `hl-23m` 2026-06-28 addendum. Real DCR-proxy remains contingent on Authentik `2026.8.0` (`hl-0sr.29`).
## ArchitectureDo not edit the D3/D10/D13 rows themselves or the other v1.3.0-alpha.1 references in this spec (Architecture line 119, line 193, line 249) — they are the historical record; the blockquote above is the live correction.
- Step 2: Verify the note is present and the historical rows are intact
Run: rg -n 'Correction \(2026-06-28\)' docs/engineering/specs/2026-06-06-llm-gw-mcp-gw-migration-design.md
Expected: one match.
Run: rg -n '1\.3\.0-alpha\.1' docs/engineering/specs/2026-06-06-llm-gw-mcp-gw-migration-design.md
Expected: the original 4 matches (lines ~91, 119, 193, 249) still present — the historical rows are untouched.
- Step 3: Commit
jj describe -m 'docs(hl-0sr.26): correction note on 2026-06-06 migration spec (D3/D10/D13 superseded)
Points readers of the merged migration spec to the 2026-06-28 DCR-honesty spec +ADR hl-23m addendum. Historical decision rows left intact; the blockquote is thelive correction.
Co-Authored-By: Claude <noreply@anthropic.com>'Task 5: Verification (pre-merge + post-merge)
Section titled “Task 5: Verification (pre-merge + post-merge)”Files: none (verification only)
- Step 1: Pre-merge — confirm the diff scope
Run: jj diff --git --stat
Expected: exactly these 6 files (the 7th — ADR hl-23m — already landed in the docs PR):
argocd/app-configs/agentgateway/mcp-engram.yaml, argocd/cluster-app/templates/agentgateway-controller.yaml, argocd/app-configs/agentgateway-controller/values-controller.yaml, argocd/app-configs/agentgateway/parameters.yaml, docs/reference/services.md, docs/engineering/specs/2026-06-06-llm-gw-mcp-gw-migration-design.md. No stray files.
- Step 2: Pre-merge — full agentgateway kustomize dry-run
Run: kubectl --context fzymgc-house apply --dry-run=client -k argocd/app-configs/agentgateway
Expected: all resources configured (dry run); no schema/validation errors. Confirms the clientId removal + mcp: with only resourceMetadata is accepted by the v1.3.1 CRD schema (SSA client-side dry-run uses the live CRD).
- Step 3: Pre-merge — validate a synthesized config on the v1.3.1 GA binary
Build a minimal config.yaml exercising the mcp: block shape (PRM only, no clientId, no provider) and validate on the GA image (uses the --validate-only form grounded in hl-0sr.1 — the flag is --validate-only, not --validate):
cat > /tmp/agw-dcr-check.yaml <<'EOF'llm: policies: apiKey: mode: Strict keys: [{ key: "k" }]mcp: targets: - name: engram mcp: # standalone mcp target variant: {host,port,path} (no protocol — hl-0sr.1) host: memory-mcp.agent-memory.svc.cluster.local port: 8080 path: /mcp policies: mcpAuthentication: mode: strict issuer: https://auth.fzymgc.house/application/o/mcp-public/ audiences: [mcp-public] jwks: url: https://auth.fzymgc.house/application/o/mcp-public/jwks/ resourceMetadata: resource: https://mcp-gw.fzymgc.house/mcp/engram bearerMethodsSupported: [header]EOFdocker run --rm -v /tmp/agw-dcr-check.yaml:/c.yaml \ ghcr.io/agentgateway/agentgateway:v1.3.1 --validate-only -f /c.yamlExpected: exit 0 (the binary returns Ok(()); rely on the exit code, not a specific stdout string). This is a bonus standalone-schema check (the deployed config is CRD-mode; the authoritative check is the CRD dry-run in Step 2). If the standalone mcp: target variant shape has drifted since hl-0sr.1, adjust per that bead’s grounding — the load-bearing assertion here is only that a mcpAuthentication block with resourceMetadata and no clientId validates on the GA binary. (If a digest pin is required, substitute ghcr.io/agentgateway/agentgateway:v1.3.1@sha256:<digest> — confirm via docker buildx imagetools inspect.)
- Step 4: Merge the docs PR (spec + plan + ADR addendum) + this execution PR
Per the writing-plans auto-fire chain, the spec/plan/ADR-addendum docs PR lands on main first; this execution PR lands alongside or after. After both merge, ArgoCD auto-syncs the agentgateway apps (selfHeal: true).
- Step 5: Post-merge — confirm the policy reconciled without
clientId
Run (after ArgoCD sync completes):
kubectl --context fzymgc-house get agentgatewaypolicy mcp-engram-oauth -n agentgateway -o jsonpath='{.spec.traffic.jwtAuthentication.mcp}'
Expected: a JSON object with resourceMetadata and no clientId key. (SSA may show client_id: null if the field is omitempty — either is fine; the key must not carry "mcp-public".)
- Step 6: Post-merge — engram MCP round-trip (unchanged static-client flow)
Re-run the hl-0sr.17 client flow: from a Claude Code session configured with mcpServers.engram = { url: "https://mcp-gw.fzymgc.house/mcp/engram", oauth: { clientId: "mcp-public", callbackPort: 8090 } }, list engram tools.
Expected: OAuth/PKCE completes against Authentik mcp-public; the tool list returns (200). Confirms the clientId removal did not regress the working static-client path.
- Step 7: Post-merge — re-check
hl-0sr.24(alpha configMapper bug)
Open the agentgateway admin UI (https://agentgateway.fzymgc.house) → dashboard data views.
Expected: if the v1.3.1 GA configMapper fix resolved the standalone-config dashboard-empty bug, the views populate → bd close hl-0sr.24 --reason="resolved by v1.3.1 GA configMapper fix (hl-0sr.26 bump)". If still empty, leave hl-0sr.24 open with a bd note recording the v1.3.1 re-check result.
- Step 8: Close the bead
bd close hl-0sr.26(hl-0sr.29 — the deferred post-2026.8.0 DCR re-eval — stays deferred; do not close.)
Out of scope
Section titled “Out of scope”openrouter-generic.yaml:6behavioral comment (hl-rpm9.8).- Historical
v1.3.0-alpha.1references in the 2026-06-20 / 2026-06-15 / 2026-06-22 specs + plans (they are records of those artifacts’ own state). - Real DCR-proxy implementation — contingent on Authentik
2026.8.0(hl-0sr.29). - The
hl-y3v8governance gap (per-keyallowedModelsnot expressible in v1.3.xLocalAPIKey) — unrelated to DCR.