Skip to content

feat(mcp): RFC 7591 Dynamic Client Registration for the consent proxy - #2710

Merged
jung-thomas merged 1 commit into
DEVfrom
worktree-mcp-consent-dcr
Oct 11, 2026
Merged

jung-thomas merged 1 commit into
DEVfrom
worktree-mcp-consent-dcr

Conversation

@jung-thomas

Copy link
Copy Markdown
Contributor

What

Adds a facade Dynamic Client Registration (RFC 7591) endpoint to the MCP consent proxy, so native-HTTP OAuth clients (Claude Code/Desktop, Joule Work Desktop) connect with zero config and no client_id.

Why

Native-HTTP OAuth MCP clients bootstrap via DCR — they POST to a registration_endpoint to obtain a client_id. The consent proxy had none (registration_endpoint: null, POST /mcp-oauth/register → 404), so the "native HTTP, no bridge" path the API-docs page advertises actually failed. The only working path was the mcp-remote bridge with an explicit, environment-specific client_id (DEV 0b1e8b56…, PROD 5a7cb5fd…) — the exact fragility behind the recent multi-day PROD aud-mismatch debugging.

How (facade, not pass-through)

/mcp-oauth/register returns this environment's existing tutorials-identity public PKCE client_id, read from the bound VCAP_SERVICES.identity[].credentials.clientid. That's the same clientid tutorials-srv-mcp validates token aud against — so native-HTTP clients get the correct per-env id automatically, eliminating the wrong-env client_id failure class by construction.

  • No IAS client created; no client_secret / registration_access_token minted (public client).
  • Client redirect_uris echoed for the client↔proxy leg only (validated at /authorize); the proxy↔IAS leg always uses our fixed callback — registration input can't influence it.
  • No identity binding → 500 (never guesses).
  • Gated by the existing MCP_CONSENT_ENABLED flag.

Changes

  • approuter/lib/mcp-consent.js: REGISTER_PATH, resolveIasClientId(), handleRegister(), dispatch + exports
  • approuter/lib/well-known-oauth.js: advertise registration_endpoint under the consent flip
  • docs: native-HTTP/DCR path now works (no client_id); reversed the stale "XSUAA does not support DCR" notes in the quickstart + api-docs page; mcp-remote + per-env client_id kept as fallback
  • tests: +5 DCR + 2 discovery, 60 green

Verification

Unit green. Post-DEV-deploy: curl .../.well-known/oauth-authorization-server | jq .registration_endpoint → …/mcp-oauth/register; POST .../mcp-oauth/register → 201 with DEV's 0b1e8b56…, no secret. End-to-end: a native-HTTP OAuth MCP client (no --static-oauth-client-info) connects to /mcp-auth/api — self-registers, consents, signs in, connects. Then PROD after promotion. (The mcp-remote + explicit-client_id path still works — back-compat.)

Native-HTTP OAuth MCP clients (Claude Code/Desktop, Joule Work Desktop) bootstrap
via DCR — they POST to a registration_endpoint to get a client_id. The consent
proxy had none (discovery registration_endpoint=null, POST /mcp-oauth/register
404), so the advertised "native HTTP, no bridge" path failed; the only working
path was the mcp-remote bridge with an explicit, env-specific client_id (DEV
0b1e8b56…, PROD 5a7cb5fd…) — the fragility behind the multi-day PROD aud-mismatch
saga.

Add a facade DCR endpoint. /mcp-oauth/register returns THIS environment's existing
tutorials-identity public PKCE client_id, read from the bound
VCAP_SERVICES.identity[].credentials.clientid (resolveIasClientId). That is the
same clientid tutorials-srv-mcp validates token aud against, so native-HTTP clients
get the correct per-env id automatically — eliminating the wrong-env client_id
failure class by construction. No IAS client is created; no secret or
registration_access_token is minted (public client). The client's redirect_uris are
echoed for the client↔proxy leg only (validated at /authorize); the proxy↔IAS leg
always uses our fixed callback. If no identity binding is present, /register returns
500 (never guesses). Gated by the existing MCP_CONSENT_ENABLED flag.

- approuter/lib/mcp-consent.js: REGISTER_PATH, resolveIasClientId(), handleRegister(),
  dispatch + exports
- approuter/lib/well-known-oauth.js: advertise registration_endpoint under the flip
- docs/end-users/mcp-quickstart.md + hugo/content/api-docs/_index.md: native-HTTP/DCR
  path now works (no client_id); reverse the stale "XSUAA does not support DCR" notes;
  mcp-remote + per-env client_id kept as the fallback
- tests: +5 DCR (mcp-consent) +2 discovery (well-known); 60 green
@jung-thomas
jung-thomas marked this pull request as ready for review October 11, 2026 15:55
@jung-thomas
jung-thomas merged commit 5bb5749 into DEV Oct 11, 2026
4 checks passed
@jung-thomas
jung-thomas deleted the worktree-mcp-consent-dcr branch October 11, 2026 15:55
jung-thomas added a commit that referenced this pull request Oct 11, 2026
release: MCP DCR + consent-proxy clientid fixes → PROD (#2709 #2710 #2711)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant