@@ -11,85 +11,89 @@ import (
1111// ServerSecretConfig contains the secret definitions and OAuth config for a server.
1212type ServerSecretConfig struct {
1313 Secrets []catalog.Secret // Secret definitions from server catalog
14- OAuth * catalog.OAuth // OAuth config (if present, OAuth takes priority over PAT )
14+ OAuth * catalog.OAuth // OAuth config (if present, OAuth takes priority over direct secret )
1515 Namespace string // Prefix for map keys (used by WorkingSet for namespacing)
1616}
1717
1818// BuildSecretsURIs generates se:// URIs for secrets with OAuth priority handling.
1919//
20- // For servers WITH OAuth configured:
21- // - Check if OAuth token exists (docker/mcp/oauth/{provider})
22- // - If yes, use OAuth URI
23- // - If no, fall back to PAT URI (docker/mcp/{secret_name})
20+ // When the secrets engine is reachable, URIs are only generated for secrets that
21+ // actually exist in the store (OAuth token checked first, then direct secret).
2422//
25- // For servers WITHOUT OAuth:
26- // - Use PAT URI directly if secret exists
27- //
28- // Docker Desktop resolves se:// URIs at container runtime.
29- // Remote servers fetch actual values via remote.go.
23+ // When the secrets engine is unreachable (e.g. MSIX-sandboxed clients on Windows
24+ // cannot follow AF_UNIX reparse points), URIs are generated for all declared secrets
25+ // since we cannot check existence. Docker Desktop resolves se:// URIs at container
26+ // runtime via named pipes, which are unaffected by MSIX restrictions.
3027func BuildSecretsURIs (ctx context.Context , configs []ServerSecretConfig ) map [string ]string {
31- // secretNameToURI maps secret names to their se:// URIs
32- // Key: secret name (e.g., "github.token" or "default_github.token" with namespace)
33- // Value: se:// URI (e.g., "se://docker/mcp/github.token")
34- secretNameToURI := make (map [string ]string )
35-
36- // availableSecrets maps secret IDs to their values (used to check existence)
3728 allSecrets , err := secret .GetSecrets (ctx )
3829 if err != nil {
3930 log .Logf ("Warning: Failed to fetch secrets from secrets engine: %v" , err )
40- // Fallback: generate se:// URIs for all declared secrets without checking existence.
41- // Docker Desktop resolves se:// URIs at container runtime via named pipes,
42- // which works even when the secrets engine Unix socket is unreachable
43- // (e.g. MSIX-sandboxed clients on Windows cannot follow AF_UNIX reparse points).
44- for _ , cfg := range configs {
45- for _ , s := range cfg .Secrets {
46- secretID := secret .GetDefaultSecretKey (s .Name )
47- secretName := cfg .Namespace + s .Name
48- secretNameToURI [secretName ] = "se://" + secretID
49- }
50- }
51- return secretNameToURI
31+ return buildFallbackURIs (configs )
5232 }
33+
5334 availableSecrets := make (map [string ]string )
5435 for _ , envelope := range allSecrets {
5536 availableSecrets [envelope .ID ] = string (envelope .Value )
5637 }
38+ return buildVerifiedURIs (configs , availableSecrets )
39+ }
40+
41+ // buildFallbackURIs generates se:// URIs for all declared secrets without checking
42+ // existence. Used when the secrets engine is unreachable. OAuth URIs are preferred
43+ // when configured (matching the normal priority order).
44+ func buildFallbackURIs (configs []ServerSecretConfig ) map [string ]string {
45+ secretNameToURI := make (map [string ]string )
5746
5847 for _ , cfg := range configs {
59- // Server has no OAuth configured - use secret directly
60- if cfg . OAuth == nil {
61- for _ , s := range cfg .Secrets {
62- secretID := secret . GetDefaultSecretKey ( s .Name )
63- if availableSecrets [ secretID ] != "" {
64- secretName := cfg . Namespace + s . Name
65- secretNameToURI [ secretName ] = "se://" + secretID
66- }
48+ secretToOAuthID := oauthMapping ( cfg )
49+
50+ for _ , s := range cfg .Secrets {
51+ secretName := cfg . Namespace + s .Name
52+ if oauthSecretID , ok := secretToOAuthID [ s . Name ]; ok {
53+ secretNameToURI [ secretName ] = "se://" + oauthSecretID
54+ } else {
55+ secretNameToURI [ secretName ] = "se://" + secret . GetDefaultSecretKey ( s . Name )
6756 }
68- continue
6957 }
58+ }
59+ return secretNameToURI
60+ }
7061
71- // Build mapping from secret name to OAuth storage key
72- secretToOAuthID := make (map [string ]string )
73- for _ , p := range cfg .OAuth .Providers {
74- secretToOAuthID [p .Secret ] = secret .GetOAuthKey (p .Provider )
75- }
62+ // buildVerifiedURIs generates se:// URIs only for secrets that exist in the store.
63+ // For servers with OAuth, checks OAuth token first, then falls back to direct secret.
64+ func buildVerifiedURIs (configs []ServerSecretConfig , availableSecrets map [string ]string ) map [string ]string {
65+ secretNameToURI := make (map [string ]string )
66+
67+ for _ , cfg := range configs {
68+ secretToOAuthID := oauthMapping (cfg )
7669
7770 for _ , s := range cfg .Secrets {
7871 secretName := cfg .Namespace + s .Name
7972
80- // Try OAuth first
73+ // Try OAuth token first
8174 if oauthSecretID , ok := secretToOAuthID [s .Name ]; ok {
8275 if availableSecrets [oauthSecretID ] != "" {
8376 secretNameToURI [secretName ] = "se://" + oauthSecretID
8477 continue
8578 }
8679 }
87- // Fall back to PAT if it exists
88- patSecretID := secret .GetDefaultSecretKey (s .Name )
89- if availableSecrets [patSecretID ] != "" {
90- secretNameToURI [secretName ] = "se://" + patSecretID
80+ // Fall back to direct secret (API keys, tokens, etc.)
81+ secretID := secret .GetDefaultSecretKey (s .Name )
82+ if availableSecrets [secretID ] != "" {
83+ secretNameToURI [secretName ] = "se://" + secretID
9184 }
9285 }
9386 }
9487 return secretNameToURI
9588}
89+
90+ // oauthMapping builds a map from secret name to OAuth storage key for a server config.
91+ func oauthMapping (cfg ServerSecretConfig ) map [string ]string {
92+ m := make (map [string ]string )
93+ if cfg .OAuth != nil {
94+ for _ , p := range cfg .OAuth .Providers {
95+ m [p .Secret ] = secret .GetOAuthKey (p .Provider )
96+ }
97+ }
98+ return m
99+ }
0 commit comments