Skip to content

feat(mcp): add direct MCP OAuth dynamic client registration - #1413

Open
jhrozek wants to merge 17 commits into
mainfrom
impl/direct-mcp-dcr
Open

feat(mcp): add direct MCP OAuth dynamic client registration#1413
jhrozek wants to merge 17 commits into
mainfrom
impl/direct-mcp-dcr

Conversation

@jhrozek

@jhrozek jhrozek commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a direct (non-broker) MCP OAuth client mode that uses RFC 7591 Dynamic
Client Registration, so a desktop operator can point mecatl at a protected
Streamable HTTP MCP server with only an endpoint URL — no ToolHive broker,
no manually pasted client ID/secret.

  • New client: {mode: dcr, dcr: {}} form for a direct/global MCP OAuth
    profile, separate from the existing broker/preregistered/CIMD forms.
  • Discovers RFC 9728 protected-resource + authorization-server metadata,
    dynamically registers a public client, then runs the existing
    authorization-code/PKCE loopback login flow.
  • v1 is no-refresh by design: only scopes: [openid] and
    request_refresh_token: false are accepted; an unsolicited refresh token
    fails login before persistence. Resource-bound public-client refresh is
    deferred to Support resource-bound public-client OAuth refresh for direct MCP DCR #1355.
  • Durable client registration and the access grant are separate,
    generation-bound, CAS-protected records in the existing encrypted local
    credential store; explicit --reset-dcr-registration /
    --retry-dcr-registration recovery flags cover corrupt/interrupted state.
  • Preserves all existing OAuth controller hardening: DNS-pinned/no-proxy
    egress, exact-issuer-origin validation, redacted errors, and rejection of
    the SDK's Basic-auth probe for the restored public client (only the
    parameter-form fallback with the exact client_id is admitted).
  • See docs/adr/0325-direct-mcp-dcr.md and
    docs/acceptance/direct-mcp-dcr.md for the full decision record and
    acceptance criteria.

Verification

  • task lint && task test green.
  • Panel review completed on the branch (fixes folded into the final commit).
  • Manual live qualification against connector-gateway.stacklok.dev/gw/mcp
    with real browser consent: registration, login, tool discovery/call, and
    credential reuse across a mecatui restart all verified. Post-expiry
    login-required and re-login/registration-reuse verification is in
    progress and will be confirmed before merge.

Fixes: #1265

🤖 Generated with Claude Code

jhrozek and others added 17 commits September 11, 2026 14:55
Co-Authored-By: mecatl <noreply@stacklok.com>
Co-Authored-By: mecatl <noreply@stacklok.com>
Co-Authored-By: mecatl <noreply@mecatl.dev>
Co-Authored-By: mecatl <noreply@stacklok.com>
Co-Authored-By: mecatl <mecatl@users.noreply.github.com>
Co-Authored-By: mecatl <mecatl@users.noreply.github.com>
Co-Authored-By: mecatl <mecatl@users.noreply.github.com>
Add explicit registration reset/retry login flags, redacted operator remedies, and the no-refresh qualification procedure.

Co-Authored-By: mecatl <noreply@stacklok.com>
Keep the explicit callback lifecycle while satisfying the repository cyclomatic-complexity gate.

Co-Authored-By: mecatl <noreply@stacklok.com>
Keep the plan in progress until its missing named proofs, resource audit, review, and live qualification are complete.

Co-Authored-By: mecatl <noreply@stacklok.com>
Co-Authored-By: mecatl <noreply@mecatl.dev>
Co-Authored-By: mecatl <noreply@stacklok.com>
Co-Authored-By: mecatl <noreply@stacklok.com>
Validate the current generation grant before registration reset and adopt only a strictly matching ready winner after uncertain registration outcomes. Pin the pending-CAS race matrix with deterministic store and HTTP barriers while retaining the authorization hardening from R01.

Co-Authored-By: mecatl <noreply@stacklok.com>
Harden persisted DCR validation and explicit expiry reauthorization. Exercise reset and retry through the public CLI boundary, and restore candidate documentation status pending final qualification.

Co-Authored-By: mecatl <noreply@stacklok.com>
Classify uncertain registration outcomes durably, keep server-advertised registration scopes out of local authority, and make operator recovery remedies match the recorded failure stage.

Co-Authored-By: mecatl <noreply@stacklok.com>
Co-Authored-By: mecatl <noreply@stacklok.com>
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.

Direct Streamable HTTP MCP client with discovery and DCR

1 participant