Skip to content

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.


All paths are repo-relative (resolve under the workspace root).

FileResponsibilityAction
argocd/app-configs/agentgateway/mcp-engram.yamlengram MCP route + JWT policy + PRMRemove clientId line; keep mcp: + resourceMetadata
argocd/cluster-app/templates/agentgateway-controller.yamlArgoCD app for CRDs + controller chartBump 2× targetRevision
argocd/app-configs/agentgateway-controller/values-controller.yamlcontroller image tagBump tag + rewrite comment
argocd/app-configs/agentgateway/parameters.yamldata-plane image tag + AgentgatewayParametersBump tag + rewrite comment
docs/reference/services.mdservices 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.mdprior 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 (the mcp-engram-oauth AgentgatewayPolicy, ~lines 81-89)

  • Step 1: Edit the mcp: block in mcp-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:
- header

with:

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:
- header

Leave 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
Terminal window
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.1 references 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
Terminal window
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 at
v1.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 resolve
hl-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
Terminal window
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 that
DCR is not available (static mcp-public PKCE is the standard). Matches deployed
reality 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 |
## Architecture

Insert 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`).
## Architecture

Do 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
Terminal window
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 the
live 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):

Terminal window
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]
EOF
docker run --rm -v /tmp/agw-dcr-check.yaml:/c.yaml \
ghcr.io/agentgateway/agentgateway:v1.3.1 --validate-only -f /c.yaml

Expected: 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
Terminal window
bd close hl-0sr.26

(hl-0sr.29 — the deferred post-2026.8.0 DCR re-eval — stays deferred; do not close.)


  • openrouter-generic.yaml:6 behavioral comment (hl-rpm9.8).
  • Historical v1.3.0-alpha.1 references 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-y3v8 governance gap (per-key allowedModels not expressible in v1.3.x LocalAPIKey) — unrelated to DCR.