Skip to content

Commit 1c7fae8

Browse files
committed
Merge branch 'main' of https://github.com/docker/mcp-gateway into bootstrap_server
2 parents d115db2 + a1cb7e5 commit 1c7fae8

File tree

26 files changed

+1120
-74
lines changed

26 files changed

+1120
-74
lines changed

cmd/docker-mcp/catalog/ls.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ import (
66
"fmt"
77
"time"
88

9+
"github.com/docker/cli/cli/command"
10+
11+
"github.com/docker/mcp-gateway/cmd/docker-mcp/hints"
912
"github.com/docker/mcp-gateway/pkg/telemetry"
1013
)
1114

12-
func Ls(ctx context.Context, format Format) error {
15+
func Ls(ctx context.Context, dockerCli command.Cli, format Format) error {
1316
// Initialize telemetry
1417
telemetry.Init()
1518

@@ -32,13 +35,13 @@ func Ls(ctx context.Context, format Format) error {
3235
}
3336
fmt.Println(string(data))
3437
} else {
35-
humanPrintCatalog(*cfg)
38+
humanPrintCatalog(dockerCli, *cfg)
3639
}
3740

3841
return nil
3942
}
4043

41-
func humanPrintCatalog(cfg Config) {
44+
func humanPrintCatalog(dockerCli command.Cli, cfg Config) {
4245
if len(cfg.Catalogs) == 0 {
4346
fmt.Println("No catalogs configured.")
4447
return
@@ -47,4 +50,9 @@ func humanPrintCatalog(cfg Config) {
4750
for name, catalog := range cfg.Catalogs {
4851
fmt.Printf("%s: %s\n", name, catalog.DisplayName)
4952
}
53+
if hints.Enabled(dockerCli) {
54+
hints.TipCyan.Print("Tip: To browse a catalog's servers, use ")
55+
hints.TipCyanBoldItalic.Print("docker mcp catalog show <catalog-name>")
56+
fmt.Println()
57+
}
5058
}

cmd/docker-mcp/catalog/show.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ import (
99
"strings"
1010
"time"
1111

12+
"github.com/docker/cli/cli/command"
1213
"github.com/mikefarah/yq/v4/pkg/yqlib"
1314
"github.com/moby/term"
1415
"gopkg.in/yaml.v3"
1516

17+
"github.com/docker/mcp-gateway/cmd/docker-mcp/hints"
1618
"github.com/docker/mcp-gateway/pkg/yq"
1719
)
1820

@@ -53,7 +55,7 @@ func SupportedFormats() string {
5355
return strings.Join(quoted, ", ")
5456
}
5557

56-
func Show(ctx context.Context, name string, format Format, mcpOAuthDcrEnabled bool) error {
58+
func Show(ctx context.Context, dockerCli command.Cli, name string, format Format, mcpOAuthDcrEnabled bool) error {
5759
cfg, err := ReadConfigWithDefaultCatalog(ctx)
5860
if err != nil {
5961
return err
@@ -153,6 +155,12 @@ func Show(ctx context.Context, name string, format Format, mcpOAuthDcrEnabled bo
153155
fmt.Printf(" %s\n", strings.Repeat("─", headerLineWidth))
154156
fmt.Printf(" %d servers total\n", serverCount)
155157
fmt.Println()
158+
if hints.Enabled(dockerCli) {
159+
hints.TipCyan.Print("Tip: To view server details, use ")
160+
hints.TipCyanBoldItalic.Print("docker mcp server inspect <server-name>")
161+
hints.TipCyan.Print(". To add servers, use ")
162+
hints.TipCyanBoldItalic.Println("docker mcp server enable <server-name>")
163+
}
156164

157165
return nil
158166
}

cmd/docker-mcp/client/config.yml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,25 @@ system:
7171
list: '.mcpServers | to_entries | map(.value + {"name": .key})'
7272
set: .mcpServers[$NAME] = $JSON
7373
del: del(.mcpServers[$NAME])
74+
vscode:
75+
displayName: Visual Studio Code
76+
source: https://code.visualstudio.com/
77+
icon: https://raw.githubusercontent.com/docker/mcp-gateway/main/img/client/vscode.svg
78+
installCheckPaths:
79+
- /Applications/Visual Studio Code.app
80+
- $APPDATA\Code\
81+
- $HOME/.config/Code
82+
paths:
83+
linux:
84+
- $HOME/.config/Code/User/mcp.json
85+
darwin:
86+
- $HOME/Library/Application Support/Code/User/mcp.json
87+
windows:
88+
- $APPDATA\Code\User\mcp.json
89+
yq:
90+
list: '.servers | to_entries | map(.value + {"name": .key})'
91+
set: .servers[$NAME] = $JSON+{"type":"stdio"}
92+
del: del(.servers[$NAME])
7493
gemini:
7594
displayName: Gemini CLI
7695
source: https://github.com/google-gemini/gemini-cli
@@ -211,7 +230,7 @@ project:
211230
set: .mcpServers[$NAME] = $JSON
212231
del: del(.mcpServers[$NAME])
213232
vscode:
214-
displayname: VSCode
233+
displayname: Visual Studio Code
215234
projectfile: .vscode/mcp.json
216235
icon: https://raw.githubusercontent.com/docker/mcp-gateway/main/img/client/vscode.svg
217236
yq:
@@ -226,4 +245,3 @@ project:
226245
list: '.mcpServers | to_entries | map(.value + {"name": .key})'
227246
set: .mcpServers[$NAME] = $JSON+{"type":"stdio"}
228247
del: del(.mcpServers[$NAME])
229-

cmd/docker-mcp/client/connect.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ package client
33
import (
44
"context"
55
"fmt"
6+
7+
"github.com/docker/cli/cli/command"
8+
9+
"github.com/docker/mcp-gateway/cmd/docker-mcp/hints"
610
)
711

8-
func Connect(ctx context.Context, cwd string, config Config, vendor string, global, quiet bool) error {
12+
func Connect(ctx context.Context, dockerCli command.Cli, cwd string, config Config, vendor string, global, quiet bool) error {
913
if vendor == vendorCodex {
1014
if !global {
1115
return fmt.Errorf("codex only supports global configuration. Re-run with --global or -g")
@@ -33,5 +37,11 @@ func Connect(ctx context.Context, cwd string, config Config, vendor string, glob
3337
return err
3438
}
3539
fmt.Printf("You might have to restart '%s'.\n", vendor)
40+
if hints.Enabled(dockerCli) {
41+
hints.TipCyan.Print("Tip: Your client is now connected! Use ")
42+
hints.TipCyanBoldItalic.Print("docker mcp tools ls")
43+
hints.TipCyan.Println(" to see your available tools")
44+
fmt.Println()
45+
}
3646
return nil
3747
}

cmd/docker-mcp/commands/catalog.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func catalogCommand(dockerCli command.Cli) *cobra.Command {
2323
cmd.AddCommand(bootstrapCatalogCommand())
2424
cmd.AddCommand(importCatalogCommand())
2525
cmd.AddCommand(exportCatalogCommand())
26-
cmd.AddCommand(lsCatalogCommand())
26+
cmd.AddCommand(lsCatalogCommand(dockerCli))
2727
cmd.AddCommand(rmCatalogCommand())
2828
cmd.AddCommand(updateCatalogCommand(dockerCli))
2929
cmd.AddCommand(showCatalogCommand(dockerCli))
@@ -86,7 +86,7 @@ cannot be exported as it is managed by Docker.`,
8686
}
8787
}
8888

89-
func lsCatalogCommand() *cobra.Command {
89+
func lsCatalogCommand(dockerCli command.Cli) *cobra.Command {
9090
var opts struct {
9191
Format catalog.Format
9292
}
@@ -101,7 +101,7 @@ func lsCatalogCommand() *cobra.Command {
101101
# List catalogs in JSON format
102102
docker mcp catalog ls --format=json`,
103103
RunE: func(cmd *cobra.Command, _ []string) error {
104-
return catalog.Ls(cmd.Context(), opts.Format)
104+
return catalog.Ls(cmd.Context(), dockerCli, opts.Format)
105105
},
106106
}
107107
flags := cmd.Flags()
@@ -165,7 +165,7 @@ If no name is provided, shows the Docker official catalog.`,
165165
}
166166

167167
mcpOAuthDcrEnabled := isMcpOAuthDcrFeatureEnabled(dockerCli)
168-
return catalog.Show(cmd.Context(), name, opts.Format, mcpOAuthDcrEnabled)
168+
return catalog.Show(cmd.Context(), dockerCli, name, opts.Format, mcpOAuthDcrEnabled)
169169
},
170170
}
171171
flags := cmd.Flags()

cmd/docker-mcp/commands/client.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,21 @@ import (
55
"fmt"
66
"strings"
77

8-
"github.com/spf13/pflag"
9-
8+
"github.com/docker/cli/cli/command"
109
"github.com/spf13/cobra"
10+
"github.com/spf13/pflag"
1111

1212
"github.com/docker/mcp-gateway/cmd/docker-mcp/client"
1313
)
1414

15-
func clientCommand(cwd string) *cobra.Command {
15+
func clientCommand(dockerCli command.Cli, cwd string) *cobra.Command {
1616
cfg := client.ReadConfig()
1717
cmd := &cobra.Command{
1818
Use: fmt.Sprintf("client (Supported: %s)", strings.Join(client.GetSupportedMCPClients(*cfg), ", ")),
1919
Short: "Manage MCP clients",
2020
}
2121
cmd.AddCommand(listClientCommand(cwd, *cfg))
22-
cmd.AddCommand(connectClientCommand(cwd, *cfg))
22+
cmd.AddCommand(connectClientCommand(dockerCli, cwd, *cfg))
2323
cmd.AddCommand(disconnectClientCommand(cwd, *cfg))
2424
cmd.AddCommand(manualClientCommand())
2525
return cmd
@@ -44,7 +44,7 @@ func listClientCommand(cwd string, cfg client.Config) *cobra.Command {
4444
return cmd
4545
}
4646

47-
func connectClientCommand(cwd string, cfg client.Config) *cobra.Command {
47+
func connectClientCommand(dockerCli command.Cli, cwd string, cfg client.Config) *cobra.Command {
4848
var opts struct {
4949
Global bool
5050
Quiet bool
@@ -54,7 +54,7 @@ func connectClientCommand(cwd string, cfg client.Config) *cobra.Command {
5454
Short: fmt.Sprintf("Connect the Docker MCP Toolkit to a client. Supported clients: %s", strings.Join(client.GetSupportedMCPClients(cfg), " ")),
5555
Args: cobra.ExactArgs(1),
5656
RunE: func(cmd *cobra.Command, args []string) error {
57-
return client.Connect(cmd.Context(), cwd, cfg, args[0], opts.Global, opts.Quiet)
57+
return client.Connect(cmd.Context(), dockerCli, cwd, cfg, args[0], opts.Global, opts.Quiet)
5858
},
5959
}
6060
flags := cmd.Flags()

cmd/docker-mcp/commands/feature.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,13 +199,19 @@ func isFeatureEnabledFromCli(dockerCli command.Cli, feature string) bool {
199199

200200
// isFeatureEnabledFromConfig checks if a feature is enabled from a config file
201201
func isFeatureEnabledFromConfig(configFile *configfile.ConfigFile, feature string) bool {
202+
// Features that are enabled by default
203+
defaultEnabledFeatures := map[string]bool{
204+
"mcp-oauth-dcr": true,
205+
"dynamic-tools": true,
206+
}
207+
202208
if configFile.Features == nil {
203-
return feature == "mcp-oauth-dcr" // mcp-oauth-dcr is enabled by default
209+
return defaultEnabledFeatures[feature]
204210
}
205211

206212
value, exists := configFile.Features[feature]
207213
if !exists {
208-
return feature == "mcp-oauth-dcr" // mcp-oauth-dcr is enabled by default
214+
return defaultEnabledFeatures[feature]
209215
}
210216

211217
// Handle both boolean string values and "enabled"/"disabled" strings

cmd/docker-mcp/commands/feature_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,15 @@ func TestIsFeatureEnabledDynamicTools(t *testing.T) {
6363
Features: make(map[string]string),
6464
}
6565
enabled := isFeatureEnabledFromConfig(configFile, "dynamic-tools")
66-
assert.False(t, enabled, "missing features should default to disabled")
66+
assert.True(t, enabled, "dynamic-tools should default to enabled when missing")
67+
})
68+
69+
t.Run("nil features map", func(t *testing.T) {
70+
configFile := &configfile.ConfigFile{
71+
Features: nil,
72+
}
73+
enabled := isFeatureEnabledFromConfig(configFile, "dynamic-tools")
74+
assert.True(t, enabled, "dynamic-tools should default to enabled when Features is nil")
6775
})
6876
}
6977

cmd/docker-mcp/commands/gateway.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ func gatewayCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command
177177
runCmd.Flags().StringVar(&options.Memory, "memory", options.Memory, "Memory allocated to each MCP Server (default is 2Gb)")
178178
runCmd.Flags().BoolVar(&options.Static, "static", options.Static, "Enable static mode (aka pre-started servers)")
179179
runCmd.Flags().StringVar(&options.LogFilePath, "log", options.LogFilePath, "Path to log file for stderr output (relative or absolute)")
180+
runCmd.Flags().StringVar(&options.SessionName, "session", "", "Session name for loading and persisting configuration from ~/.docker/mcp/{SessionName}/")
180181

181182
// Very experimental features
182183
_ = runCmd.Flags().MarkHidden("log")
@@ -295,12 +296,12 @@ func isMcpOAuthDcrFeatureEnabled(dockerCli command.Cli) bool {
295296
func isDynamicToolsFeatureEnabled(dockerCli command.Cli) bool {
296297
configFile := dockerCli.ConfigFile()
297298
if configFile == nil || configFile.Features == nil {
298-
return false
299+
return true // Default enabled when no config exists
299300
}
300301

301302
value, exists := configFile.Features["dynamic-tools"]
302303
if !exists {
303-
return false
304+
return true // Default enabled when not in config
304305
}
305306

306307
return value == "enabled"

cmd/docker-mcp/commands/gateway_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,31 +88,31 @@ func TestIsDynamicToolsFeatureEnabled(t *testing.T) {
8888
Features: map[string]string{},
8989
}
9090
enabled := isDynamicToolsFeatureEnabledFromConfig(configFile)
91-
assert.False(t, enabled, "should return false when dynamic-tools is not set")
91+
assert.True(t, enabled, "should return true when dynamic-tools is not set")
9292
})
9393

9494
t.Run("nil config", func(t *testing.T) {
9595
enabled := isDynamicToolsFeatureEnabledFromConfig(nil)
96-
assert.False(t, enabled, "should return false when config is nil")
96+
assert.True(t, enabled, "should return true when config is nil")
9797
})
9898

9999
t.Run("nil features", func(t *testing.T) {
100100
configFile := &configfile.ConfigFile{
101101
Features: nil,
102102
}
103103
enabled := isDynamicToolsFeatureEnabledFromConfig(configFile)
104-
assert.False(t, enabled, "should return false when features is nil")
104+
assert.True(t, enabled, "should return true when features is nil")
105105
})
106106
}
107107

108108
// Helper function for testing (extract logic from isDynamicToolsFeatureEnabled)
109109
func isDynamicToolsFeatureEnabledFromConfig(configFile *configfile.ConfigFile) bool {
110110
if configFile == nil || configFile.Features == nil {
111-
return false
111+
return true // Default enabled when no config exists
112112
}
113113
value, exists := configFile.Features["dynamic-tools"]
114114
if !exists {
115-
return false
115+
return true // Default enabled when not in config
116116
}
117117
return value == "enabled"
118118
}

0 commit comments

Comments
 (0)