Conversation
This commit completes the MCP Gateway DCR implementation providing fully automated OAuth flows for MCP servers with enhanced security and UX. ## Key Features Added ### OAuth Discovery & DCR - RFC 9728 + RFC 8414 compliant OAuth discovery with fallback mechanisms - RFC 7591 Dynamic Client Registration using public clients (no secrets) - Direct authorization server discovery for non-compliant servers - Enhanced error handling with detailed DCR failure diagnostics ### PKCE Security Implementation - OAuth 2.1 S256 PKCE implementation replacing client secret security - 128-character code verifiers with SHA256 challenges - Secure parameter storage with automatic cleanup - 10-minute expiry for PKCE parameters ### Provider Registration & Persistence - Automatic provider registration after DCR completion - Enhanced DCR credentials storage with OAuth endpoints - Two-tier architecture: DCR registry + OAuth provider runtime - Provider persistence across Docker Desktop restarts ### API Enhancements - Added RegisterDCRProvider method for explicit provider registration - Enhanced DCR types to include authorization/token endpoints - Improved PKCE parameter handling with server name association - Fixed redirect URI consistency to use https://mcp.docker.com/oauth/callback ### User Experience - Zero manual configuration - servers appear automatically in UI - Consistent redirect URI across all OAuth flows - Enhanced debugging with detailed error messages - Immediate provider availability after DCR completion ## Technical Implementation ### MCP Gateway Components - discovery.go: Enhanced with direct auth server discovery fallback - dcr.go: Complete public client implementation with endpoint storage - pkce.go: S256 PKCE generation and authorization URL building - storage.go: Integrated provider registration with DCR storage - auth.go: Docker Desktop API client enhancements ### Security Model - Public clients eliminate client secret storage/leakage risks - PKCE provides equivalent security to confidential clients - OAuth 2.1 compliant implementation throughout - Resource parameter binding prevents token misuse ### Catalog Updates - Fixed Hugging Face upstream URL for proper discovery - Updated remote server configurations for OAuth compatibility ## MCP Specification Compliance ✅ RFC 9728 - OAuth Protected Resource Metadata ✅ RFC 8414 - Authorization Server Metadata ✅ RFC 7591 - Dynamic Client Registration ✅ RFC 8707 - Resource Indicators ✅ RFC 7636 - PKCE for OAuth ✅ OAuth 2.1 - Public client requirements All components tested with real OAuth servers and verified working. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
The OAuth list command was showing duplicate entries for DCR providers (huggingface-remote and notion-remote appeared twice) because the code was adding catalog OAuth servers without checking if they already existed as OAuth apps in Docker Desktop. With DCR implementation, catalog servers automatically become Docker Desktop OAuth apps, so the deduplication logic prevents showing the same provider twice. ## Changes - Add deduplication map to track existing OAuth apps by name - Skip catalog OAuth servers if they already exist in Docker Desktop apps - Preserve authorization status from Docker Desktop (primary source) ## Result - huggingface-remote: appears once, shows "authorized" ✅ - notion-remote: appears once, shows "authorized" ✅ - All other servers: appear once with correct status ✅ 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
The deduplication logic addresses a subtle integration issue between DCR and catalog systems that caused duplicate entries. Adding comprehensive comments to explain: 1. Why deduplication is needed (DCR created data source overlap) 2. Historical context (pre-DCR vs post-DCR architecture) 3. Which data source takes priority (Docker Desktop over catalog) 4. Backward compatibility preservation for non-DCR servers This prevents future developers from accidentally removing the logic and reintroducing the duplicate entry bug. ## Comments Added - Context about DCR integration creating overlap between data sources - Explanation of prioritization strategy (Docker Desktop = authoritative) - Backward compatibility notes for non-DCR OAuth servers - Clear rationale for seemingly complex logic in simple list operation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
The revoke command was broken for DCR providers (notion-remote, huggingface-remote) showing a recursive message instead of actually revoking access. This was due to outdated logic from pre-DCR era. ## Problem - `docker mcp oauth revoke notion-remote` showed: "To revoke access, use: docker mcp oauth revoke notion-remote" - No actual revocation occurred ## Root Cause The revoke logic assumed remote servers used separate OAuth providers: - OLD: notion-remote (server) uses "notion" (provider) - NEW: notion-remote IS the OAuth provider (via DCR) ## Solution Updated `revokeRemoteMCPServer()` to: 1. **Check DCR providers first**: Look for server as actual OAuth provider 2. **Revoke directly**: Use Docker Desktop API to delete OAuth app 3. **Fallback**: Preserve old logic for backward compatibility ## Testing ✅ `docker mcp oauth revoke notion-remote` → "OAuth access revoked" ✅ `docker mcp oauth revoke huggingface-remote` → "OAuth access revoked" ✅ Status verified: both now show "not authorized" Fixes the recursive message issue and enables proper OAuth management for DCR-registered providers. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove user-configured catalogs enhancement from configuration.go - Clarify DCR-specific GetWithOptions calls in server/enable.go with comments - Remove remote-mcp-catalog.yaml test file (486 lines) This cleanup focuses the implementation on pure DCR functionality: - OAuth discovery, DCR registration, and PKCE flows - Server lifecycle integration (enable/disable with OAuth cleanup) - Docker Desktop integration for credential storage The DCR implementation now contains only essential changes aligned with the MCP Authorization specification and dynamic client registration goals. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…uth DCR functionality - Resolved conflicts in feature.go: kept oauth-interceptor and mcp-oauth-dcr features - Resolved conflicts in types.go: added Name field while keeping Type field for OAuth detection - Resolved conflicts in configuration.go: merged MCPRegistryServers with McpOAuthDcrEnabled - Resolved conflicts in run.go: merged constructor parameters for both upstream and OAuth features - Resolved conflicts in enable.go: kept OAuth DCR cleanup logic while accepting upstream changes All OAuth DCR functionality preserved including: - Dynamic Client Registration for remote servers - Token refresh and event watching - OAuth provider lifecycle management during server enable/disable
kgprs
added a commit
that referenced
this pull request
Sep 18, 2025
This commit implements PR #129 changes with adaptations for the latest main branch: * Add mcp-oauth-dcr feature flag support to commands and gateway configuration * Implement OAuth 2.0 Dynamic Client Registration (RFC 7591) for public clients * Add OAuth 2.0 Authorization Server Discovery (RFC 8414) and Protected Resource Metadata (RFC 9728) * Support token event handling for OAuth client invalidation on token refresh * Add secure OAuth credential helper using docker-credential-desktop * Update MCP remote client to automatically add OAuth Bearer tokens * Add DCR client management methods to desktop auth client * Update server enable/disable commands to support DCR feature flag * Add comprehensive WWW-Authenticate header parsing (RFC 6750) * Add InvalidateOAuthClients method to gateway client pool * Include OAuth configuration in catalog server types Key features: - Automatic OAuth server discovery from MCP server 401 responses - Public client registration using PKCE for enhanced security - Secure token storage via system credential store - Automatic token refresh handling with client pool invalidation - Full compliance with OAuth 2.0/2.1 and MCP Authorization specifications All tests pass and build succeeds. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
kgprs
added a commit
that referenced
this pull request
Sep 18, 2025
This commit implements PR #129 changes with adaptations for the latest main branch: * Add mcp-oauth-dcr feature flag support to commands and gateway configuration * Implement OAuth 2.0 Dynamic Client Registration (RFC 7591) for public clients * Add OAuth 2.0 Authorization Server Discovery (RFC 8414) and Protected Resource Metadata (RFC 9728) * Support token event handling for OAuth client invalidation on token refresh * Add secure OAuth credential helper using docker-credential-desktop * Update MCP remote client to automatically add OAuth Bearer tokens * Add DCR client management methods to desktop auth client * Update server enable/disable commands to support DCR feature flag * Add comprehensive WWW-Authenticate header parsing (RFC 6750) * Add InvalidateOAuthClients method to gateway client pool * Include OAuth configuration in catalog server types Key features: - Automatic OAuth server discovery from MCP server 401 responses - Public client registration using PKCE for enhanced security - Secure token storage via system credential store - Automatic token refresh handling with client pool invalidation - Full compliance with OAuth 2.0/2.1 and MCP Authorization specifications All tests pass and build succeeds. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
kgprs
added a commit
that referenced
this pull request
Sep 18, 2025
This commit adds the critical DCR integration functionality that was missing from the initial implementation, bringing it to full parity with PR #129: DCR Integration in Server Commands: • registerProviderForLazySetup() - Registers OAuth providers during server enable • cleanupOAuthForRemoteServer() - Cleans up OAuth data during server disable • OAuth server detection - Checks server.IsRemoteOAuthServer() for DCR eligibility • User guidance - Provides helpful messages about OAuth setup and requirements Key Features Added: • Automatic DCR provider registration when enabling OAuth-enabled remote servers • Complete OAuth cleanup when disabling servers (tokens + DCR client data) • Smart conditional logic based on mcpOAuthDcrEnabled feature flag • User-friendly messaging for OAuth setup guidance and status • Idempotent operations that handle missing OAuth data gracefully Server Enable Flow: 1. Enable server in registry.yaml 2. Check if server requires OAuth (type=remote + oauth config) 3. If DCR enabled: Register provider for lazy setup + show auth guidance 4. If DCR disabled: Show feature enablement guidance Server Disable Flow: 1. Check if server has OAuth configuration 2. If DCR enabled: Clean up OAuth tokens and DCR client data 3. Remove server from registry.yaml This completes the missing 101 lines of DCR integration from PR #129. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
kgprs
added a commit
that referenced
this pull request
Sep 18, 2025
- Expand DCRResponse to include all RFC 7591 fields from original PR #129 - Add ClientIDIssuedAt, ClientSecretExpiresAt, RedirectURIs, and metadata fields - Restore complete DCR response handling for full OAuth 2.0 compliance - Match original PR #129 structure while maintaining pkg/ import paths This brings the DCRResponse implementation to exact parity with the original PR #129 specification, ensuring full RFC 7591 compliance for Dynamic Client Registration responses. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
kgprs
added a commit
that referenced
this pull request
Sep 18, 2025
- Fix gofmt formatting issues in pkg/oauth/*.go files (missing newlines) - Restore original message format from PR #129 (no emojis, debug logging to stderr) - Match exact output format: stderr for debug, stdout for user messages - Remove emoji additions that weren't in original PR #129 This fixes the lint failures and ensures exact parity with PR #129 message format. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
kgprs
added a commit
that referenced
this pull request
Sep 18, 2025
- Remove enhanced FormatWWWAuthenticate and needsQuoting functions not in original PR #129 - Remove unused strconv import after function removal - Reduce from 253 lines to 210 lines (target: 208, very close) - Keep only the core WWW-Authenticate parsing functions from original PR This brings the implementation much closer to the original PR #129 while maintaining all the essential OAuth header parsing functionality. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
kgprs
added a commit
that referenced
this pull request
Sep 18, 2025
- Simplify pkg/mcp/remote.go header handling to match original PR #129 - Remove enhanced Accept header logic to match original implementation - Remove enhanced FormatWWWAuthenticate and needsQuoting functions from www_authenticate.go - Generate updated documentation for new mcp-oauth-dcr feature flag - Fix docs validation by running make docs to update feature documentation Line count now much closer to original: - www_authenticate.go: 253 -> 210 lines (target: 208) - remote.go: restored to original implementation - Total difference now minimal This should fix both lint and docs validation failures. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Contributor
Author
|
Closing as the code has been rebased and merged with this PR: #148 |
null-runner
pushed a commit
to null-runner/mcp-gateway
that referenced
this pull request
Dec 6, 2025
This commit implements PR docker#129 changes with adaptations for the latest main branch: * Add mcp-oauth-dcr feature flag support to commands and gateway configuration * Implement OAuth 2.0 Dynamic Client Registration (RFC 7591) for public clients * Add OAuth 2.0 Authorization Server Discovery (RFC 8414) and Protected Resource Metadata (RFC 9728) * Support token event handling for OAuth client invalidation on token refresh * Add secure OAuth credential helper using docker-credential-desktop * Update MCP remote client to automatically add OAuth Bearer tokens * Add DCR client management methods to desktop auth client * Update server enable/disable commands to support DCR feature flag * Add comprehensive WWW-Authenticate header parsing (RFC 6750) * Add InvalidateOAuthClients method to gateway client pool * Include OAuth configuration in catalog server types Key features: - Automatic OAuth server discovery from MCP server 401 responses - Public client registration using PKCE for enhanced security - Secure token storage via system credential store - Automatic token refresh handling with client pool invalidation - Full compliance with OAuth 2.0/2.1 and MCP Authorization specifications All tests pass and build succeeds.
null-runner
pushed a commit
to null-runner/mcp-gateway
that referenced
this pull request
Dec 6, 2025
This commit adds the critical DCR integration functionality that was missing from the initial implementation, bringing it to full parity with PR docker#129: DCR Integration in Server Commands: • registerProviderForLazySetup() - Registers OAuth providers during server enable • cleanupOAuthForRemoteServer() - Cleans up OAuth data during server disable • OAuth server detection - Checks server.IsRemoteOAuthServer() for DCR eligibility • User guidance - Provides helpful messages about OAuth setup and requirements Key Features Added: • Automatic DCR provider registration when enabling OAuth-enabled remote servers • Complete OAuth cleanup when disabling servers (tokens + DCR client data) • Smart conditional logic based on mcpOAuthDcrEnabled feature flag • User-friendly messaging for OAuth setup guidance and status • Idempotent operations that handle missing OAuth data gracefully Server Enable Flow: 1. Enable server in registry.yaml 2. Check if server requires OAuth (type=remote + oauth config) 3. If DCR enabled: Register provider for lazy setup + show auth guidance 4. If DCR disabled: Show feature enablement guidance Server Disable Flow: 1. Check if server has OAuth configuration 2. If DCR enabled: Clean up OAuth tokens and DCR client data 3. Remove server from registry.yaml This completes the missing 101 lines of DCR integration from PR docker#129.
null-runner
pushed a commit
to null-runner/mcp-gateway
that referenced
this pull request
Dec 6, 2025
- Expand DCRResponse to include all RFC 7591 fields from original PR docker#129 - Add ClientIDIssuedAt, ClientSecretExpiresAt, RedirectURIs, and metadata fields - Restore complete DCR response handling for full OAuth 2.0 compliance - Match original PR docker#129 structure while maintaining pkg/ import paths This brings the DCRResponse implementation to exact parity with the original PR docker#129 specification, ensuring full RFC 7591 compliance for Dynamic Client Registration responses.
null-runner
pushed a commit
to null-runner/mcp-gateway
that referenced
this pull request
Dec 6, 2025
- Fix gofmt formatting issues in pkg/oauth/*.go files (missing newlines) - Restore original message format from PR docker#129 (no emojis, debug logging to stderr) - Match exact output format: stderr for debug, stdout for user messages - Remove emoji additions that weren't in original PR docker#129 This fixes the lint failures and ensures exact parity with PR docker#129 message format.
null-runner
pushed a commit
to null-runner/mcp-gateway
that referenced
this pull request
Dec 6, 2025
- Remove enhanced FormatWWWAuthenticate and needsQuoting functions not in original PR docker#129 - Remove unused strconv import after function removal - Reduce from 253 lines to 210 lines (target: 208, very close) - Keep only the core WWW-Authenticate parsing functions from original PR This brings the implementation much closer to the original PR docker#129 while maintaining all the essential OAuth header parsing functionality.
null-runner
pushed a commit
to null-runner/mcp-gateway
that referenced
this pull request
Dec 6, 2025
- Simplify pkg/mcp/remote.go header handling to match original PR docker#129 - Remove enhanced Accept header logic to match original implementation - Remove enhanced FormatWWWAuthenticate and needsQuoting functions from www_authenticate.go - Generate updated documentation for new mcp-oauth-dcr feature flag - Fix docs validation by running make docs to update feature documentation Line count now much closer to original: - www_authenticate.go: 253 -> 210 lines (target: 208) - remote.go: restored to original implementation - Total difference now minimal This should fix both lint and docs validation failures.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Latest version of PR: https://github.com/docker/mcp-gateway/pull/148/files
What I did:
This PR implements the MCP Authorization specification in MCP Gateway behind the:
mcp-oauth-dcrfeature flag, enabling automatic OAuth setup for MCP servers through Dynamic Client Registration (DCR). The implementation uses lazy DCR registration where OAuth client registration happens during authorization, not server enable.Component Boundaries:
Key features:
Key Flows
1. Enable → Authorize Flow
sequenceDiagram participant User participant Gateway as MCP Gateway participant DD as Docker Desktop participant AuthServer as Authorization Server Note over User: 1. Enable Server (Unregistered State) User->>Gateway: docker mcp server enable notion-remote Gateway->>DD: Register unregistered DCR client DD->>DD: Store placeholder DCR client DD->>DD: Add provider to OAuth tab Note over User: Provider appears (unregistered) Note over User: 2. Authorize (Atomic DCR + OAuth) User->>DD: Click "Authorize" or use CLI DD->>Gateway: docker mcp oauth authorize notion-remote Gateway->>AuthServer: OAuth discovery (RFC 9728 + RFC 8414) Gateway->>AuthServer: POST /register (DCR) AuthServer-->>Gateway: {client_id, endpoints} Gateway->>DD: Store DCR client via API DD->>DD: Generate PKCE parameters DD->>User: Open browser with auth URL User->>AuthServer: Complete authorization AuthServer->>DD: OAuth callback DD->>DD: Exchange code + verifier for tokens Note over User: Provider shows as "Authorized"2. Token Injection Flow
sequenceDiagram participant Gateway as MCP Gateway participant CredHelper as Credential Helper participant DD as Docker Desktop participant Server as MCP Server Note over Gateway: MCP Request with Token Gateway->>CredHelper: GetOAuthToken(notion-remote) CredHelper->>DD: docker-credential-desktop get DD-->>CredHelper: OAuth token (base64 JSON) CredHelper->>CredHelper: Parse access_token from JSON CredHelper-->>Gateway: Access token Gateway->>Server: MCP request + Authorization: Bearer <token> Server-->>Gateway: MCP response (authorized)3. Token Event File Watching
sequenceDiagram participant DD as Docker Desktop participant EventFile as ~/.docker/token-event.json participant Gateway as MCP Gateway participant ClientPool as Client Pool participant Server as MCP Server Note over DD: Token refresh occurs DD->>EventFile: Write token event Note over EventFile: {"provider": "notion-remote", "event_type": "token_refreshed", ...} EventFile->>Gateway: File watcher detects change Gateway->>Gateway: Parse event JSON Gateway->>ClientPool: Find connection for provider ClientPool->>ClientPool: Close existing connection Gateway->>CredHelper: Get fresh token Gateway->>Server: Reconnect with new token Server-->>Gateway: Connection established4. OAuth Discovery Flow
sequenceDiagram participant Gateway as MCP Gateway participant Server as MCP Server participant AuthServer as Authorization Server Note over Gateway: Discovery Process Gateway->>Server: Initial MCP request (no auth) Server-->>Gateway: 401 + WWW-Authenticate header Note over Gateway: Parse resource metadata URL Gateway->>Server: GET /.well-known/oauth-protected-resource Server-->>Gateway: Resource metadata + auth server URLs Gateway->>AuthServer: GET /.well-known/oauth-authorization-server AuthServer-->>Gateway: Authorization server metadata Note over Gateway: Discovery complete - ready for DCRImplementation Details
OAuth Package (
cmd/docker-mcp/internal/oauth/)Discovery (
discovery.go)DCR Implementation (
dcr.go)Credential Helper (
credhelper.go)Types (
types.go)Gateway Integration (
internal/gateway/)Token Event Watching (
run.go)~/.docker/token-event.jsonClient Pool Enhancement (
clientpool.go)Authorization Commands (
oauth/)Authorize (
auth.go)List (
ls.go)Revoke (
revoke.go)Server Lifecycle (
server/enable.go)On Enable:
On Disable:
Feature Flag Protection
All DCR operations are controlled by the
mcp-oauth-dcrfeature flag:When disabled, users get guidance for manual OAuth setup.
Testing
Manual Verification: