@@ -6,11 +6,15 @@ import (
66
77 oauthhelpers "github.com/docker/mcp-gateway-oauth-helpers"
88
9+ "github.com/docker/mcp-gateway/cmd/docker-mcp/secret-management/secret"
910 "github.com/docker/mcp-gateway/pkg/catalog"
1011 "github.com/docker/mcp-gateway/pkg/desktop"
1112 "github.com/docker/mcp-gateway/pkg/log"
1213)
1314
15+ // clientSecretSuffix is the naming convention for OAuth client secrets in the secrets store.
16+ const clientSecretSuffix = ".client_secret"
17+
1418// dcrRegistrationClient is the subset of desktop.Tools used for DCR registration.
1519// Extracted as an interface to enable testing.
1620type dcrRegistrationClient interface {
@@ -53,16 +57,36 @@ func RegisterProviderForLazySetup(ctx context.Context, serverName string) error
5357 return fmt .Errorf ("server %s not found in catalog" , serverName )
5458 }
5559
56- // Verify this is a remote OAuth server (Type=" remote" && OAuth providers exist )
57- if ! server .HasExplicitOAuthProviders () {
58- return fmt .Errorf ("server %s is not a remote OAuth server " , serverName )
60+ // Verify this server has OAuth providers ( remote with explicit providers, or pre-registered )
61+ if ! server .HasExplicitOAuthProviders () && ! server . HasPreRegisteredOAuth () {
62+ return fmt .Errorf ("server %s does not have OAuth providers configured " , serverName )
5963 }
6064
61- providerName := server .OAuth .Providers [0 ]. Provider
65+ provider := server .OAuth .Providers [0 ]
6266
63- // Register with DD (pending DCR state)
67+ // Build DCR request with pre-registered metadata if available.
68+ // When registration + server_metadata are provided (from a catalog with
69+ // embedded OAuth metadata), Pinata skips DCR discovery and uses them directly.
6470 dcrRequest := desktop.RegisterDCRRequest {
65- ProviderName : providerName ,
71+ ProviderName : provider .Provider ,
72+ }
73+ if provider .Registration != nil {
74+ dcrRequest .ClientID = provider .Registration .ClientID
75+
76+ // Look up client_secret from the Secrets Engine (user sets it via docker mcp secret set).
77+ // The catalog only contains client_id; the secret is never distributed in catalogs.
78+ clientSecretKey := secret .GetDefaultSecretKey (serverName + clientSecretSuffix )
79+ if env , err := secret .GetSecret (ctx , clientSecretKey ); err == nil && string (env .Value ) != "" {
80+ dcrRequest .ClientSecret = string (env .Value )
81+ log .Logf ("- Registering pre-configured OAuth client for %s with client_secret" , serverName )
82+ } else {
83+ log .Logf ("- Registering pre-configured OAuth client for %s without client_secret (not yet set)" , serverName )
84+ }
85+ }
86+ if provider .ServerMetadata != nil {
87+ dcrRequest .AuthorizationEndpoint = provider .ServerMetadata .AuthorizationEndpoint
88+ dcrRequest .TokenEndpoint = provider .ServerMetadata .TokenEndpoint
89+ dcrRequest .Scopes = provider .ServerMetadata .ScopesSupported
6690 }
6791
6892 return client .RegisterDCRClientPending (ctx , serverName , dcrRequest )
@@ -103,7 +127,7 @@ func registerProviderForDynamicDiscovery(ctx context.Context, serverName, server
103127// RegisterProviderWithSnapshot registers a DCR provider using OAuth metadata from the server snapshot
104128// This avoids querying the catalog since the snapshot already contains all necessary OAuth information
105129// Idempotent - safe to call multiple times for the same server
106- func RegisterProviderWithSnapshot (ctx context.Context , serverName , providerName string ) error {
130+ func RegisterProviderWithSnapshot (ctx context.Context , serverName string , provider catalog. OAuthProvider , scopes [] string ) error {
107131 client := desktop .NewAuthClient ()
108132
109133 // Idempotent check - already registered?
@@ -113,8 +137,26 @@ func RegisterProviderWithSnapshot(ctx context.Context, serverName, providerName
113137 }
114138
115139 // Register with Docker Desktop (pending DCR state)
140+ // Include pre-registered client metadata if available from catalog
116141 dcrRequest := desktop.RegisterDCRRequest {
117- ProviderName : providerName ,
142+ ProviderName : provider .Provider ,
143+ Scopes : scopes ,
144+ }
145+ if provider .Registration != nil {
146+ dcrRequest .ClientID = provider .Registration .ClientID
147+
148+ // Look up client_secret from Secrets Engine (not distributed in catalogs)
149+ clientSecretKey := secret .GetDefaultSecretKey (serverName + clientSecretSuffix )
150+ if env , err := secret .GetSecret (ctx , clientSecretKey ); err == nil && string (env .Value ) != "" {
151+ dcrRequest .ClientSecret = string (env .Value )
152+ }
153+ }
154+ if provider .ServerMetadata != nil {
155+ dcrRequest .AuthorizationEndpoint = provider .ServerMetadata .AuthorizationEndpoint
156+ dcrRequest .TokenEndpoint = provider .ServerMetadata .TokenEndpoint
157+ if len (dcrRequest .Scopes ) == 0 {
158+ dcrRequest .Scopes = provider .ServerMetadata .ScopesSupported
159+ }
118160 }
119161
120162 return client .RegisterDCRClientPending (ctx , serverName , dcrRequest )
0 commit comments