From 2f291f581a3bb6119467da374a49e54423d4bc98 Mon Sep 17 00:00:00 2001 From: Austin Berry Date: Wed, 22 Oct 2025 15:15:18 -0400 Subject: [PATCH 1/7] Add post command tips --- cmd/docker-mcp/catalog/ls.go | 1 + cmd/docker-mcp/catalog/show.go | 2 ++ cmd/docker-mcp/client/connect.go | 1 + cmd/docker-mcp/commands/server.go | 2 ++ cmd/docker-mcp/server/enable.go | 10 ++++++++++ cmd/docker-mcp/tools/list.go | 2 ++ 6 files changed, 18 insertions(+) diff --git a/cmd/docker-mcp/catalog/ls.go b/cmd/docker-mcp/catalog/ls.go index 685e6fe7..26d7c697 100644 --- a/cmd/docker-mcp/catalog/ls.go +++ b/cmd/docker-mcp/catalog/ls.go @@ -47,4 +47,5 @@ func humanPrintCatalog(cfg Config) { for name, catalog := range cfg.Catalogs { fmt.Printf("%s: %s\n", name, catalog.DisplayName) } + fmt.Println("\033[36mTip: Use \033[1;3m'docker mcp catalog show '\033[0;36m to browse a catalog's servers\033[0m") } diff --git a/cmd/docker-mcp/catalog/show.go b/cmd/docker-mcp/catalog/show.go index 822ee975..7b0fb740 100644 --- a/cmd/docker-mcp/catalog/show.go +++ b/cmd/docker-mcp/catalog/show.go @@ -153,6 +153,8 @@ func Show(ctx context.Context, name string, format Format, mcpOAuthDcrEnabled bo fmt.Printf(" %s\n", strings.Repeat("─", headerLineWidth)) fmt.Printf(" %d servers total\n", serverCount) fmt.Println() + fmt.Println("\033[36mTip: \033[1;3mdocker mcp server inspect \033[0;36m to view server details, \033[1;3mdocker mcp server enable \033[0;36m to add servers\033[0m") + fmt.Println() return nil } diff --git a/cmd/docker-mcp/client/connect.go b/cmd/docker-mcp/client/connect.go index 36f1390c..d0fb505a 100644 --- a/cmd/docker-mcp/client/connect.go +++ b/cmd/docker-mcp/client/connect.go @@ -33,5 +33,6 @@ func Connect(ctx context.Context, cwd string, config Config, vendor string, glob return err } fmt.Printf("You might have to restart '%s'.\n", vendor) + fmt.Println("\033[36mTip: Your client is now connected! Try \033[1;3m'docker mcp tools ls'\033[0;36m to see available tools\033[0m") return nil } diff --git a/cmd/docker-mcp/commands/server.go b/cmd/docker-mcp/commands/server.go index 34a04012..9e570823 100644 --- a/cmd/docker-mcp/commands/server.go +++ b/cmd/docker-mcp/commands/server.go @@ -42,6 +42,8 @@ func serverCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command { fmt.Fprintln(cmd.OutOrStdout(), "No server is enabled") } else { fmt.Fprintln(cmd.OutOrStdout(), strings.Join(list, ", ")) + fmt.Fprintln(cmd.OutOrStdout(), "\033[36mTip: Connect to Claude/Cursor to use these servers with \033[1;3m'docker mcp client connect '\033[0m") + fmt.Fprintln(cmd.OutOrStdout(), "") } return nil diff --git a/cmd/docker-mcp/server/enable.go b/cmd/docker-mcp/server/enable.go index ca7a84ea..ec8b1734 100644 --- a/cmd/docker-mcp/server/enable.go +++ b/cmd/docker-mcp/server/enable.go @@ -94,5 +94,15 @@ func update(ctx context.Context, docker docker.Client, add []string, remove []st return fmt.Errorf("writing registry config: %w", err) } + if len(add) > 0 { + fmt.Println("\033[32m✓\033[0m \033[36mServer enabled. Run \033[1;3m'docker mcp server ls'\033[0;36m to view servers\033[0m") + fmt.Println() + } + + if len(remove) > 0 { + fmt.Println("\033[32m✓\033[0m \033[36mServer disabled. Run \033[1;3m'docker mcp server ls'\033[0;36m to see remaining enabled servers\033[0m") + fmt.Println() + } + return nil } diff --git a/cmd/docker-mcp/tools/list.go b/cmd/docker-mcp/tools/list.go index d6fb4de4..c8700dfe 100644 --- a/cmd/docker-mcp/tools/list.go +++ b/cmd/docker-mcp/tools/list.go @@ -50,12 +50,14 @@ func List(ctx context.Context, version string, gatewayArgs []string, debug bool, for _, tool := range response.Tools { fmt.Println(" -", tool.Name, "-", toolDescription(tool)) } + fmt.Println("\033[36mTip: Use \033[1;3m'docker mcp tools inspect '\033[0;36m to see tool details, or \033[1;3m'docker mcp tools call '\033[0;36m to test it\033[0m") } case "count": if format == "json" { fmt.Printf("{\"count\": %d}\n", len(response.Tools)) } else { fmt.Println(len(response.Tools), "tools") + fmt.Println("\033[36mTip: Run \033[1;3m'docker mcp tools ls'\033[0;36m to see all available tools\033[0m") } case "inspect": var found *mcp.Tool From ae6a68df1ec0e2c4a8b113bd8cca7d1401e248a6 Mon Sep 17 00:00:00 2001 From: Austin Berry Date: Thu, 23 Oct 2025 13:15:26 -0400 Subject: [PATCH 2/7] add missing tip prefix on server enable / disable --- cmd/docker-mcp/server/enable.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/docker-mcp/server/enable.go b/cmd/docker-mcp/server/enable.go index ec8b1734..8cfe1ba9 100644 --- a/cmd/docker-mcp/server/enable.go +++ b/cmd/docker-mcp/server/enable.go @@ -95,12 +95,12 @@ func update(ctx context.Context, docker docker.Client, add []string, remove []st } if len(add) > 0 { - fmt.Println("\033[32m✓\033[0m \033[36mServer enabled. Run \033[1;3m'docker mcp server ls'\033[0;36m to view servers\033[0m") + fmt.Println("\033[36mTip: \033[32m✓\033[0m \033[36mServer enabled. Run \033[1;3m'docker mcp server ls'\033[0;36m to view servers\033[0m") fmt.Println() } if len(remove) > 0 { - fmt.Println("\033[32m✓\033[0m \033[36mServer disabled. Run \033[1;3m'docker mcp server ls'\033[0;36m to see remaining enabled servers\033[0m") + fmt.Println("\033[36mTip: \033[32m✓\033[0m \033[36mServer disabled. Run \033[1;3m'docker mcp server ls'\033[0;36m to see remaining enabled servers\033[0m") fmt.Println() } From f4fb93267dbf92521bee36e79f0a7a195e2317f3 Mon Sep 17 00:00:00 2001 From: Austin Berry Date: Thu, 23 Oct 2025 13:17:46 -0400 Subject: [PATCH 3/7] update tip to specify it lists enabled servers --- cmd/docker-mcp/server/enable.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/docker-mcp/server/enable.go b/cmd/docker-mcp/server/enable.go index 8cfe1ba9..54b623e8 100644 --- a/cmd/docker-mcp/server/enable.go +++ b/cmd/docker-mcp/server/enable.go @@ -95,7 +95,7 @@ func update(ctx context.Context, docker docker.Client, add []string, remove []st } if len(add) > 0 { - fmt.Println("\033[36mTip: \033[32m✓\033[0m \033[36mServer enabled. Run \033[1;3m'docker mcp server ls'\033[0;36m to view servers\033[0m") + fmt.Println("\033[36mTip: \033[32m✓\033[0m \033[36mServer enabled. Run \033[1;3m'docker mcp server ls'\033[0;36m to view all enabled servers\033[0m") fmt.Println() } From 14207bf52e18d61b468f2d338d942f31eeb61352 Mon Sep 17 00:00:00 2001 From: Austin Berry Date: Thu, 23 Oct 2025 15:51:10 -0400 Subject: [PATCH 4/7] use cli hints flag setting from DD --- cmd/docker-mcp/catalog/ls.go | 5 ++++- cmd/docker-mcp/catalog/show.go | 6 ++++-- cmd/docker-mcp/client/connect.go | 6 +++++- cmd/docker-mcp/commands/server.go | 7 +++++-- cmd/docker-mcp/hints/hints.go | 27 +++++++++++++++++++++++++++ cmd/docker-mcp/server/enable.go | 5 +++-- cmd/docker-mcp/tools/list.go | 10 ++++++++-- 7 files changed, 56 insertions(+), 10 deletions(-) create mode 100644 cmd/docker-mcp/hints/hints.go diff --git a/cmd/docker-mcp/catalog/ls.go b/cmd/docker-mcp/catalog/ls.go index 26d7c697..b07b64b4 100644 --- a/cmd/docker-mcp/catalog/ls.go +++ b/cmd/docker-mcp/catalog/ls.go @@ -6,6 +6,7 @@ import ( "fmt" "time" + "github.com/docker/mcp-gateway/cmd/docker-mcp/hints" "github.com/docker/mcp-gateway/pkg/telemetry" ) @@ -47,5 +48,7 @@ func humanPrintCatalog(cfg Config) { for name, catalog := range cfg.Catalogs { fmt.Printf("%s: %s\n", name, catalog.DisplayName) } - fmt.Println("\033[36mTip: Use \033[1;3m'docker mcp catalog show '\033[0;36m to browse a catalog's servers\033[0m") + if hints.Enabled() { + fmt.Println("\033[36mTip: Use \033[1;3m'docker mcp catalog show '\033[0;36m to browse a catalog's servers\033[0m") + } } diff --git a/cmd/docker-mcp/catalog/show.go b/cmd/docker-mcp/catalog/show.go index 7b0fb740..7f295853 100644 --- a/cmd/docker-mcp/catalog/show.go +++ b/cmd/docker-mcp/catalog/show.go @@ -13,6 +13,7 @@ import ( "github.com/moby/term" "gopkg.in/yaml.v3" + "github.com/docker/mcp-gateway/cmd/docker-mcp/hints" "github.com/docker/mcp-gateway/pkg/yq" ) @@ -153,8 +154,9 @@ func Show(ctx context.Context, name string, format Format, mcpOAuthDcrEnabled bo fmt.Printf(" %s\n", strings.Repeat("─", headerLineWidth)) fmt.Printf(" %d servers total\n", serverCount) fmt.Println() - fmt.Println("\033[36mTip: \033[1;3mdocker mcp server inspect \033[0;36m to view server details, \033[1;3mdocker mcp server enable \033[0;36m to add servers\033[0m") - fmt.Println() + if hints.Enabled() { + fmt.Println("\033[36mTip: \033[1;3mdocker mcp server inspect \033[0;36m to view server details, \033[1;3mdocker mcp server enable \033[0;36m to add servers\033[0m") + } return nil } diff --git a/cmd/docker-mcp/client/connect.go b/cmd/docker-mcp/client/connect.go index d0fb505a..4831293c 100644 --- a/cmd/docker-mcp/client/connect.go +++ b/cmd/docker-mcp/client/connect.go @@ -3,6 +3,8 @@ package client import ( "context" "fmt" + + "github.com/docker/mcp-gateway/cmd/docker-mcp/hints" ) func Connect(ctx context.Context, cwd string, config Config, vendor string, global, quiet bool) error { @@ -33,6 +35,8 @@ func Connect(ctx context.Context, cwd string, config Config, vendor string, glob return err } fmt.Printf("You might have to restart '%s'.\n", vendor) - fmt.Println("\033[36mTip: Your client is now connected! Try \033[1;3m'docker mcp tools ls'\033[0;36m to see available tools\033[0m") + if hints.Enabled() { + fmt.Println("\033[36mTip: Your client is now connected! Try \033[1;3m'docker mcp tools ls'\033[0;36m to see available tools\033[0m") + } return nil } diff --git a/cmd/docker-mcp/commands/server.go b/cmd/docker-mcp/commands/server.go index 9e570823..de6250bd 100644 --- a/cmd/docker-mcp/commands/server.go +++ b/cmd/docker-mcp/commands/server.go @@ -8,6 +8,7 @@ import ( "github.com/docker/cli/cli/command" "github.com/spf13/cobra" + "github.com/docker/mcp-gateway/cmd/docker-mcp/hints" "github.com/docker/mcp-gateway/cmd/docker-mcp/server" "github.com/docker/mcp-gateway/pkg/config" "github.com/docker/mcp-gateway/pkg/docker" @@ -42,8 +43,10 @@ func serverCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command { fmt.Fprintln(cmd.OutOrStdout(), "No server is enabled") } else { fmt.Fprintln(cmd.OutOrStdout(), strings.Join(list, ", ")) - fmt.Fprintln(cmd.OutOrStdout(), "\033[36mTip: Connect to Claude/Cursor to use these servers with \033[1;3m'docker mcp client connect '\033[0m") - fmt.Fprintln(cmd.OutOrStdout(), "") + if hints.Enabled() { + fmt.Fprintln(cmd.OutOrStdout(), "\033[36mTip: Connect to a client (IE: Claude/Cursor) to use these servers with \033[1;3m'docker mcp client connect '\033[0m") + fmt.Fprintln(cmd.OutOrStdout(), "") + } } return nil diff --git a/cmd/docker-mcp/hints/hints.go b/cmd/docker-mcp/hints/hints.go new file mode 100644 index 00000000..9f2123fe --- /dev/null +++ b/cmd/docker-mcp/hints/hints.go @@ -0,0 +1,27 @@ +package hints + +import ( + "github.com/docker/cli/cli/config" + "github.com/docker/cli/cli/config/configfile" +) + +func Enabled() bool { + configFile := getDockerConfigFile() + if configFile != nil && configFile.Plugins != nil { + if pluginConfig, ok := configFile.Plugins["-x-cli-hints"]; ok { + if enabledValue, exists := pluginConfig["enabled"]; exists { + return enabledValue == "true" + } + } + } + + return true +} + +func getDockerConfigFile() *configfile.ConfigFile { + configFile, err := config.Load("") + if err != nil { + return nil + } + return configFile +} diff --git a/cmd/docker-mcp/server/enable.go b/cmd/docker-mcp/server/enable.go index 54b623e8..cfdb3496 100644 --- a/cmd/docker-mcp/server/enable.go +++ b/cmd/docker-mcp/server/enable.go @@ -7,6 +7,7 @@ import ( "gopkg.in/yaml.v3" + "github.com/docker/mcp-gateway/cmd/docker-mcp/hints" "github.com/docker/mcp-gateway/pkg/catalog" "github.com/docker/mcp-gateway/pkg/config" "github.com/docker/mcp-gateway/pkg/docker" @@ -94,12 +95,12 @@ func update(ctx context.Context, docker docker.Client, add []string, remove []st return fmt.Errorf("writing registry config: %w", err) } - if len(add) > 0 { + if len(add) > 0 && hints.Enabled() { fmt.Println("\033[36mTip: \033[32m✓\033[0m \033[36mServer enabled. Run \033[1;3m'docker mcp server ls'\033[0;36m to view all enabled servers\033[0m") fmt.Println() } - if len(remove) > 0 { + if len(remove) > 0 && hints.Enabled() { fmt.Println("\033[36mTip: \033[32m✓\033[0m \033[36mServer disabled. Run \033[1;3m'docker mcp server ls'\033[0;36m to see remaining enabled servers\033[0m") fmt.Println() } diff --git a/cmd/docker-mcp/tools/list.go b/cmd/docker-mcp/tools/list.go index c8700dfe..dd5233a2 100644 --- a/cmd/docker-mcp/tools/list.go +++ b/cmd/docker-mcp/tools/list.go @@ -10,6 +10,8 @@ import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" + + "github.com/docker/mcp-gateway/cmd/docker-mcp/hints" ) func List(ctx context.Context, version string, gatewayArgs []string, debug bool, show, tool, format string) error { @@ -50,14 +52,18 @@ func List(ctx context.Context, version string, gatewayArgs []string, debug bool, for _, tool := range response.Tools { fmt.Println(" -", tool.Name, "-", toolDescription(tool)) } - fmt.Println("\033[36mTip: Use \033[1;3m'docker mcp tools inspect '\033[0;36m to see tool details, or \033[1;3m'docker mcp tools call '\033[0;36m to test it\033[0m") + if hints.Enabled() { + fmt.Println("\033[36mTip: Use \033[1;3m'docker mcp tools inspect '\033[0;36m to see tool details, or \033[1;3m'docker mcp tools call '\033[0;36m to test it\033[0m") + } } case "count": if format == "json" { fmt.Printf("{\"count\": %d}\n", len(response.Tools)) } else { fmt.Println(len(response.Tools), "tools") - fmt.Println("\033[36mTip: Run \033[1;3m'docker mcp tools ls'\033[0;36m to see all available tools\033[0m") + if hints.Enabled() { + fmt.Println("\033[36mTip: Run \033[1;3m'docker mcp tools ls'\033[0;36m to see all available tools\033[0m") + } } case "inspect": var found *mcp.Tool From f0e554c53f3703eb899909e4cc1f6d4de9a68d85 Mon Sep 17 00:00:00 2001 From: Austin Berry Date: Fri, 24 Oct 2025 11:53:45 -0400 Subject: [PATCH 5/7] update tips UI copy, use library for colors to improve readability --- cmd/docker-mcp/catalog/ls.go | 4 +++- cmd/docker-mcp/catalog/show.go | 5 ++++- cmd/docker-mcp/client/connect.go | 5 ++++- cmd/docker-mcp/commands/server.go | 3 ++- cmd/docker-mcp/hints/hints.go | 7 +++++++ cmd/docker-mcp/server/enable.go | 10 ++++++++-- cmd/docker-mcp/tools/list.go | 10 ++++++++-- 7 files changed, 36 insertions(+), 8 deletions(-) diff --git a/cmd/docker-mcp/catalog/ls.go b/cmd/docker-mcp/catalog/ls.go index b07b64b4..13815160 100644 --- a/cmd/docker-mcp/catalog/ls.go +++ b/cmd/docker-mcp/catalog/ls.go @@ -49,6 +49,8 @@ func humanPrintCatalog(cfg Config) { fmt.Printf("%s: %s\n", name, catalog.DisplayName) } if hints.Enabled() { - fmt.Println("\033[36mTip: Use \033[1;3m'docker mcp catalog show '\033[0;36m to browse a catalog's servers\033[0m") + hints.TipCyan.Print("Tip: To browse a catalog's servers, use ") + hints.TipCyanBoldItalic.Print("docker mcp catalog show ") + fmt.Println() } } diff --git a/cmd/docker-mcp/catalog/show.go b/cmd/docker-mcp/catalog/show.go index 7f295853..df034d39 100644 --- a/cmd/docker-mcp/catalog/show.go +++ b/cmd/docker-mcp/catalog/show.go @@ -155,7 +155,10 @@ func Show(ctx context.Context, name string, format Format, mcpOAuthDcrEnabled bo fmt.Printf(" %d servers total\n", serverCount) fmt.Println() if hints.Enabled() { - fmt.Println("\033[36mTip: \033[1;3mdocker mcp server inspect \033[0;36m to view server details, \033[1;3mdocker mcp server enable \033[0;36m to add servers\033[0m") + hints.TipCyan.Print("Tip: To view server details, use ") + hints.TipCyanBoldItalic.Print("docker mcp server inspect ") + hints.TipCyan.Print(". To add servers, use ") + hints.TipCyanBoldItalic.Println("docker mcp server enable ") } return nil diff --git a/cmd/docker-mcp/client/connect.go b/cmd/docker-mcp/client/connect.go index 4831293c..44aeaff0 100644 --- a/cmd/docker-mcp/client/connect.go +++ b/cmd/docker-mcp/client/connect.go @@ -36,7 +36,10 @@ func Connect(ctx context.Context, cwd string, config Config, vendor string, glob } fmt.Printf("You might have to restart '%s'.\n", vendor) if hints.Enabled() { - fmt.Println("\033[36mTip: Your client is now connected! Try \033[1;3m'docker mcp tools ls'\033[0;36m to see available tools\033[0m") + hints.TipCyan.Print("Tip: Your client is now connected! Use ") + hints.TipCyanBoldItalic.Print("docker mcp tools ls") + hints.TipCyan.Println(" to see your available tools") + fmt.Println() } return nil } diff --git a/cmd/docker-mcp/commands/server.go b/cmd/docker-mcp/commands/server.go index de6250bd..7f645a4c 100644 --- a/cmd/docker-mcp/commands/server.go +++ b/cmd/docker-mcp/commands/server.go @@ -44,7 +44,8 @@ func serverCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command { } else { fmt.Fprintln(cmd.OutOrStdout(), strings.Join(list, ", ")) if hints.Enabled() { - fmt.Fprintln(cmd.OutOrStdout(), "\033[36mTip: Connect to a client (IE: Claude/Cursor) to use these servers with \033[1;3m'docker mcp client connect '\033[0m") + hints.TipCyan.Fprint(cmd.OutOrStdout(), "Tip: To use these servers, connect to a client (IE: claude/cursor) with ") + hints.TipCyanBoldItalic.Fprintln(cmd.OutOrStdout(), "docker mcp client connect ") fmt.Fprintln(cmd.OutOrStdout(), "") } } diff --git a/cmd/docker-mcp/hints/hints.go b/cmd/docker-mcp/hints/hints.go index 9f2123fe..23e9927e 100644 --- a/cmd/docker-mcp/hints/hints.go +++ b/cmd/docker-mcp/hints/hints.go @@ -3,6 +3,7 @@ package hints import ( "github.com/docker/cli/cli/config" "github.com/docker/cli/cli/config/configfile" + "github.com/fatih/color" ) func Enabled() bool { @@ -18,6 +19,12 @@ func Enabled() bool { return true } +var ( + TipCyan = color.New(color.FgCyan) + TipCyanBoldItalic = color.New(color.FgCyan, color.Bold, color.Italic) + TipGreen = color.New(color.FgGreen) +) + func getDockerConfigFile() *configfile.ConfigFile { configFile, err := config.Load("") if err != nil { diff --git a/cmd/docker-mcp/server/enable.go b/cmd/docker-mcp/server/enable.go index cfdb3496..3972e447 100644 --- a/cmd/docker-mcp/server/enable.go +++ b/cmd/docker-mcp/server/enable.go @@ -96,12 +96,18 @@ func update(ctx context.Context, docker docker.Client, add []string, remove []st } if len(add) > 0 && hints.Enabled() { - fmt.Println("\033[36mTip: \033[32m✓\033[0m \033[36mServer enabled. Run \033[1;3m'docker mcp server ls'\033[0;36m to view all enabled servers\033[0m") + hints.TipCyan.Print("Tip: ") + hints.TipGreen.Print("✓") + hints.TipCyan.Print(" Server enabled. To view all enabled servers, use ") + hints.TipCyanBoldItalic.Println("docker mcp server ls") fmt.Println() } if len(remove) > 0 && hints.Enabled() { - fmt.Println("\033[36mTip: \033[32m✓\033[0m \033[36mServer disabled. Run \033[1;3m'docker mcp server ls'\033[0;36m to see remaining enabled servers\033[0m") + hints.TipCyan.Print("Tip: ") + hints.TipGreen.Print("✓") + hints.TipCyan.Print(" Server disabled. To see remaining enabled servers, use ") + hints.TipCyanBoldItalic.Println("docker mcp server ls") fmt.Println() } diff --git a/cmd/docker-mcp/tools/list.go b/cmd/docker-mcp/tools/list.go index dd5233a2..63a43434 100644 --- a/cmd/docker-mcp/tools/list.go +++ b/cmd/docker-mcp/tools/list.go @@ -53,7 +53,11 @@ func List(ctx context.Context, version string, gatewayArgs []string, debug bool, fmt.Println(" -", tool.Name, "-", toolDescription(tool)) } if hints.Enabled() { - fmt.Println("\033[36mTip: Use \033[1;3m'docker mcp tools inspect '\033[0;36m to see tool details, or \033[1;3m'docker mcp tools call '\033[0;36m to test it\033[0m") + hints.TipCyan.Print("Tip: For tool details, use ") + hints.TipCyanBoldItalic.Print("docker mcp tools inspect ") + hints.TipCyan.Print(". To test the tool, use ") + hints.TipCyanBoldItalic.Println("docker mcp tools call ") + fmt.Println() } } case "count": @@ -62,7 +66,9 @@ func List(ctx context.Context, version string, gatewayArgs []string, debug bool, } else { fmt.Println(len(response.Tools), "tools") if hints.Enabled() { - fmt.Println("\033[36mTip: Run \033[1;3m'docker mcp tools ls'\033[0;36m to see all available tools\033[0m") + hints.TipCyan.Print("Tip: To see all available tools, use ") + hints.TipCyanBoldItalic.Println("docker mcp tools ls") + fmt.Println() } } case "inspect": From cc2e0c74fda9ca2f2d9dcba234cbfad223d962a3 Mon Sep 17 00:00:00 2001 From: Austin Berry Date: Fri, 24 Oct 2025 16:12:56 -0400 Subject: [PATCH 6/7] use dockerCli to get the config instead --- cmd/docker-mcp/catalog/ls.go | 10 +++--- cmd/docker-mcp/catalog/show.go | 5 +-- cmd/docker-mcp/client/connect.go | 6 ++-- cmd/docker-mcp/commands/catalog.go | 8 ++--- cmd/docker-mcp/commands/client.go | 12 +++---- cmd/docker-mcp/commands/root.go | 4 +-- cmd/docker-mcp/commands/server.go | 6 ++-- cmd/docker-mcp/commands/tools.go | 9 ++--- cmd/docker-mcp/hints/hints.go | 15 ++------ cmd/docker-mcp/server/enable.go | 15 ++++---- cmd/docker-mcp/server/server_test.go | 54 ++++++++++++++++++---------- cmd/docker-mcp/tools/list.go | 7 ++-- 12 files changed, 83 insertions(+), 68 deletions(-) diff --git a/cmd/docker-mcp/catalog/ls.go b/cmd/docker-mcp/catalog/ls.go index 13815160..73f793a6 100644 --- a/cmd/docker-mcp/catalog/ls.go +++ b/cmd/docker-mcp/catalog/ls.go @@ -6,11 +6,13 @@ import ( "fmt" "time" + "github.com/docker/cli/cli/command" + "github.com/docker/mcp-gateway/cmd/docker-mcp/hints" "github.com/docker/mcp-gateway/pkg/telemetry" ) -func Ls(ctx context.Context, format Format) error { +func Ls(ctx context.Context, dockerCli command.Cli, format Format) error { // Initialize telemetry telemetry.Init() @@ -33,13 +35,13 @@ func Ls(ctx context.Context, format Format) error { } fmt.Println(string(data)) } else { - humanPrintCatalog(*cfg) + humanPrintCatalog(dockerCli, *cfg) } return nil } -func humanPrintCatalog(cfg Config) { +func humanPrintCatalog(dockerCli command.Cli, cfg Config) { if len(cfg.Catalogs) == 0 { fmt.Println("No catalogs configured.") return @@ -48,7 +50,7 @@ func humanPrintCatalog(cfg Config) { for name, catalog := range cfg.Catalogs { fmt.Printf("%s: %s\n", name, catalog.DisplayName) } - if hints.Enabled() { + if hints.Enabled(dockerCli) { hints.TipCyan.Print("Tip: To browse a catalog's servers, use ") hints.TipCyanBoldItalic.Print("docker mcp catalog show ") fmt.Println() diff --git a/cmd/docker-mcp/catalog/show.go b/cmd/docker-mcp/catalog/show.go index df034d39..0f5c273a 100644 --- a/cmd/docker-mcp/catalog/show.go +++ b/cmd/docker-mcp/catalog/show.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/docker/cli/cli/command" "github.com/mikefarah/yq/v4/pkg/yqlib" "github.com/moby/term" "gopkg.in/yaml.v3" @@ -54,7 +55,7 @@ func SupportedFormats() string { return strings.Join(quoted, ", ") } -func Show(ctx context.Context, name string, format Format, mcpOAuthDcrEnabled bool) error { +func Show(ctx context.Context, dockerCli command.Cli, name string, format Format, mcpOAuthDcrEnabled bool) error { cfg, err := ReadConfigWithDefaultCatalog(ctx) if err != nil { return err @@ -154,7 +155,7 @@ func Show(ctx context.Context, name string, format Format, mcpOAuthDcrEnabled bo fmt.Printf(" %s\n", strings.Repeat("─", headerLineWidth)) fmt.Printf(" %d servers total\n", serverCount) fmt.Println() - if hints.Enabled() { + if hints.Enabled(dockerCli) { hints.TipCyan.Print("Tip: To view server details, use ") hints.TipCyanBoldItalic.Print("docker mcp server inspect ") hints.TipCyan.Print(". To add servers, use ") diff --git a/cmd/docker-mcp/client/connect.go b/cmd/docker-mcp/client/connect.go index 44aeaff0..9eb918bc 100644 --- a/cmd/docker-mcp/client/connect.go +++ b/cmd/docker-mcp/client/connect.go @@ -4,10 +4,12 @@ import ( "context" "fmt" + "github.com/docker/cli/cli/command" + "github.com/docker/mcp-gateway/cmd/docker-mcp/hints" ) -func Connect(ctx context.Context, cwd string, config Config, vendor string, global, quiet bool) error { +func Connect(ctx context.Context, dockerCli command.Cli, cwd string, config Config, vendor string, global, quiet bool) error { if vendor == vendorCodex { if !global { return fmt.Errorf("codex only supports global configuration. Re-run with --global or -g") @@ -35,7 +37,7 @@ func Connect(ctx context.Context, cwd string, config Config, vendor string, glob return err } fmt.Printf("You might have to restart '%s'.\n", vendor) - if hints.Enabled() { + if hints.Enabled(dockerCli) { hints.TipCyan.Print("Tip: Your client is now connected! Use ") hints.TipCyanBoldItalic.Print("docker mcp tools ls") hints.TipCyan.Println(" to see your available tools") diff --git a/cmd/docker-mcp/commands/catalog.go b/cmd/docker-mcp/commands/catalog.go index b550cfd8..eb3c20aa 100644 --- a/cmd/docker-mcp/commands/catalog.go +++ b/cmd/docker-mcp/commands/catalog.go @@ -23,7 +23,7 @@ func catalogCommand(dockerCli command.Cli) *cobra.Command { cmd.AddCommand(bootstrapCatalogCommand()) cmd.AddCommand(importCatalogCommand()) cmd.AddCommand(exportCatalogCommand()) - cmd.AddCommand(lsCatalogCommand()) + cmd.AddCommand(lsCatalogCommand(dockerCli)) cmd.AddCommand(rmCatalogCommand()) cmd.AddCommand(updateCatalogCommand(dockerCli)) cmd.AddCommand(showCatalogCommand(dockerCli)) @@ -86,7 +86,7 @@ cannot be exported as it is managed by Docker.`, } } -func lsCatalogCommand() *cobra.Command { +func lsCatalogCommand(dockerCli command.Cli) *cobra.Command { var opts struct { Format catalog.Format } @@ -101,7 +101,7 @@ func lsCatalogCommand() *cobra.Command { # List catalogs in JSON format docker mcp catalog ls --format=json`, RunE: func(cmd *cobra.Command, _ []string) error { - return catalog.Ls(cmd.Context(), opts.Format) + return catalog.Ls(cmd.Context(), dockerCli, opts.Format) }, } flags := cmd.Flags() @@ -165,7 +165,7 @@ If no name is provided, shows the Docker official catalog.`, } mcpOAuthDcrEnabled := isMcpOAuthDcrFeatureEnabled(dockerCli) - return catalog.Show(cmd.Context(), name, opts.Format, mcpOAuthDcrEnabled) + return catalog.Show(cmd.Context(), dockerCli, name, opts.Format, mcpOAuthDcrEnabled) }, } flags := cmd.Flags() diff --git a/cmd/docker-mcp/commands/client.go b/cmd/docker-mcp/commands/client.go index 27d540f7..5cdf07b4 100644 --- a/cmd/docker-mcp/commands/client.go +++ b/cmd/docker-mcp/commands/client.go @@ -5,21 +5,21 @@ import ( "fmt" "strings" - "github.com/spf13/pflag" - + "github.com/docker/cli/cli/command" "github.com/spf13/cobra" + "github.com/spf13/pflag" "github.com/docker/mcp-gateway/cmd/docker-mcp/client" ) -func clientCommand(cwd string) *cobra.Command { +func clientCommand(dockerCli command.Cli, cwd string) *cobra.Command { cfg := client.ReadConfig() cmd := &cobra.Command{ Use: fmt.Sprintf("client (Supported: %s)", strings.Join(client.GetSupportedMCPClients(*cfg), ", ")), Short: "Manage MCP clients", } cmd.AddCommand(listClientCommand(cwd, *cfg)) - cmd.AddCommand(connectClientCommand(cwd, *cfg)) + cmd.AddCommand(connectClientCommand(dockerCli, cwd, *cfg)) cmd.AddCommand(disconnectClientCommand(cwd, *cfg)) cmd.AddCommand(manualClientCommand()) return cmd @@ -44,7 +44,7 @@ func listClientCommand(cwd string, cfg client.Config) *cobra.Command { return cmd } -func connectClientCommand(cwd string, cfg client.Config) *cobra.Command { +func connectClientCommand(dockerCli command.Cli, cwd string, cfg client.Config) *cobra.Command { var opts struct { Global bool Quiet bool @@ -54,7 +54,7 @@ func connectClientCommand(cwd string, cfg client.Config) *cobra.Command { Short: fmt.Sprintf("Connect the Docker MCP Toolkit to a client. Supported clients: %s", strings.Join(client.GetSupportedMCPClients(cfg), " ")), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return client.Connect(cmd.Context(), cwd, cfg, args[0], opts.Global, opts.Quiet) + return client.Connect(cmd.Context(), dockerCli, cwd, cfg, args[0], opts.Global, opts.Quiet) }, } flags := cmd.Flags() diff --git a/cmd/docker-mcp/commands/root.go b/cmd/docker-mcp/commands/root.go index 615a01e3..7ef4e53f 100644 --- a/cmd/docker-mcp/commands/root.go +++ b/cmd/docker-mcp/commands/root.go @@ -71,7 +71,7 @@ func Root(ctx context.Context, cwd string, dockerCli command.Cli) *cobra.Command dockerClient := docker.NewClient(dockerCli) cmd.AddCommand(catalogCommand(dockerCli)) - cmd.AddCommand(clientCommand(cwd)) + cmd.AddCommand(clientCommand(dockerCli, cwd)) cmd.AddCommand(configCommand(dockerClient)) cmd.AddCommand(featureCommand(dockerCli)) cmd.AddCommand(gatewayCommand(dockerClient, dockerCli)) @@ -80,7 +80,7 @@ func Root(ctx context.Context, cwd string, dockerCli command.Cli) *cobra.Command cmd.AddCommand(registryCommand()) cmd.AddCommand(secretCommand(dockerClient)) cmd.AddCommand(serverCommand(dockerClient, dockerCli)) - cmd.AddCommand(toolsCommand(dockerClient)) + cmd.AddCommand(toolsCommand(dockerClient, dockerCli)) cmd.AddCommand(versionCommand()) if os.Getenv("DOCKER_MCP_SHOW_HIDDEN") == "1" { diff --git a/cmd/docker-mcp/commands/server.go b/cmd/docker-mcp/commands/server.go index 7f645a4c..40b2d9f6 100644 --- a/cmd/docker-mcp/commands/server.go +++ b/cmd/docker-mcp/commands/server.go @@ -43,7 +43,7 @@ func serverCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command { fmt.Fprintln(cmd.OutOrStdout(), "No server is enabled") } else { fmt.Fprintln(cmd.OutOrStdout(), strings.Join(list, ", ")) - if hints.Enabled() { + if hints.Enabled(dockerCli) { hints.TipCyan.Fprint(cmd.OutOrStdout(), "Tip: To use these servers, connect to a client (IE: claude/cursor) with ") hints.TipCyanBoldItalic.Fprintln(cmd.OutOrStdout(), "docker mcp client connect ") fmt.Fprintln(cmd.OutOrStdout(), "") @@ -63,7 +63,7 @@ func serverCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command { Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { mcpOAuthDcrEnabled := isMcpOAuthDcrFeatureEnabled(dockerCli) - return server.Enable(cmd.Context(), docker, args, mcpOAuthDcrEnabled) + return server.Enable(cmd.Context(), docker, dockerCli, args, mcpOAuthDcrEnabled) }, }) @@ -74,7 +74,7 @@ func serverCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command { Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { mcpOAuthDcrEnabled := isMcpOAuthDcrFeatureEnabled(dockerCli) - return server.Disable(cmd.Context(), docker, args, mcpOAuthDcrEnabled) + return server.Disable(cmd.Context(), docker, dockerCli, args, mcpOAuthDcrEnabled) }, }) diff --git a/cmd/docker-mcp/commands/tools.go b/cmd/docker-mcp/commands/tools.go index e4793667..bf44de6b 100644 --- a/cmd/docker-mcp/commands/tools.go +++ b/cmd/docker-mcp/commands/tools.go @@ -1,13 +1,14 @@ package commands import ( + "github.com/docker/cli/cli/command" "github.com/spf13/cobra" "github.com/docker/mcp-gateway/cmd/docker-mcp/tools" "github.com/docker/mcp-gateway/pkg/docker" ) -func toolsCommand(docker docker.Client) *cobra.Command { +func toolsCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command { cmd := &cobra.Command{ Use: "tools", Short: "Manage tools", @@ -30,7 +31,7 @@ func toolsCommand(docker docker.Client) *cobra.Command { Short: "List tools", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { - return tools.List(cmd.Context(), version, gatewayArgs, verbose, "list", "", format) + return tools.List(cmd.Context(), dockerCli, version, gatewayArgs, verbose, "list", "", format) }, }) @@ -39,7 +40,7 @@ func toolsCommand(docker docker.Client) *cobra.Command { Short: "Count tools", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { - return tools.List(cmd.Context(), version, gatewayArgs, verbose, "count", "", format) + return tools.List(cmd.Context(), dockerCli, version, gatewayArgs, verbose, "count", "", format) }, }) @@ -48,7 +49,7 @@ func toolsCommand(docker docker.Client) *cobra.Command { Short: "Inspect a tool", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return tools.List(cmd.Context(), version, gatewayArgs, verbose, "inspect", args[0], format) + return tools.List(cmd.Context(), dockerCli, version, gatewayArgs, verbose, "inspect", args[0], format) }, }) cmd.AddCommand(&cobra.Command{ diff --git a/cmd/docker-mcp/hints/hints.go b/cmd/docker-mcp/hints/hints.go index 23e9927e..cc533b08 100644 --- a/cmd/docker-mcp/hints/hints.go +++ b/cmd/docker-mcp/hints/hints.go @@ -1,13 +1,12 @@ package hints import ( - "github.com/docker/cli/cli/config" - "github.com/docker/cli/cli/config/configfile" + "github.com/docker/cli/cli/command" "github.com/fatih/color" ) -func Enabled() bool { - configFile := getDockerConfigFile() +func Enabled(dockerCli command.Cli) bool { + configFile := dockerCli.ConfigFile() if configFile != nil && configFile.Plugins != nil { if pluginConfig, ok := configFile.Plugins["-x-cli-hints"]; ok { if enabledValue, exists := pluginConfig["enabled"]; exists { @@ -24,11 +23,3 @@ var ( TipCyanBoldItalic = color.New(color.FgCyan, color.Bold, color.Italic) TipGreen = color.New(color.FgGreen) ) - -func getDockerConfigFile() *configfile.ConfigFile { - configFile, err := config.Load("") - if err != nil { - return nil - } - return configFile -} diff --git a/cmd/docker-mcp/server/enable.go b/cmd/docker-mcp/server/enable.go index 3972e447..df5b4795 100644 --- a/cmd/docker-mcp/server/enable.go +++ b/cmd/docker-mcp/server/enable.go @@ -5,6 +5,7 @@ import ( "context" "fmt" + "github.com/docker/cli/cli/command" "gopkg.in/yaml.v3" "github.com/docker/mcp-gateway/cmd/docker-mcp/hints" @@ -14,15 +15,15 @@ import ( "github.com/docker/mcp-gateway/pkg/oauth" ) -func Disable(ctx context.Context, docker docker.Client, serverNames []string, mcpOAuthDcrEnabled bool) error { - return update(ctx, docker, nil, serverNames, mcpOAuthDcrEnabled) +func Disable(ctx context.Context, docker docker.Client, dockerCli command.Cli, serverNames []string, mcpOAuthDcrEnabled bool) error { + return update(ctx, docker, dockerCli, nil, serverNames, mcpOAuthDcrEnabled) } -func Enable(ctx context.Context, docker docker.Client, serverNames []string, mcpOAuthDcrEnabled bool) error { - return update(ctx, docker, serverNames, nil, mcpOAuthDcrEnabled) +func Enable(ctx context.Context, docker docker.Client, dockerCli command.Cli, serverNames []string, mcpOAuthDcrEnabled bool) error { + return update(ctx, docker, dockerCli, serverNames, nil, mcpOAuthDcrEnabled) } -func update(ctx context.Context, docker docker.Client, add []string, remove []string, mcpOAuthDcrEnabled bool) error { +func update(ctx context.Context, docker docker.Client, dockerCli command.Cli, add []string, remove []string, mcpOAuthDcrEnabled bool) error { // Read registry.yaml that contains which servers are enabled. registryYAML, err := config.ReadRegistry(ctx, docker) if err != nil { @@ -95,7 +96,7 @@ func update(ctx context.Context, docker docker.Client, add []string, remove []st return fmt.Errorf("writing registry config: %w", err) } - if len(add) > 0 && hints.Enabled() { + if len(add) > 0 && hints.Enabled(dockerCli) { hints.TipCyan.Print("Tip: ") hints.TipGreen.Print("✓") hints.TipCyan.Print(" Server enabled. To view all enabled servers, use ") @@ -103,7 +104,7 @@ func update(ctx context.Context, docker docker.Client, add []string, remove []st fmt.Println() } - if len(remove) > 0 && hints.Enabled() { + if len(remove) > 0 && hints.Enabled(dockerCli) { hints.TipCyan.Print("Tip: ") hints.TipGreen.Print("✓") hints.TipCyan.Print(" Server disabled. To see remaining enabled servers, use ") diff --git a/cmd/docker-mcp/server/server_test.go b/cmd/docker-mcp/server/server_test.go index 6447fa36..7dd9aae3 100644 --- a/cmd/docker-mcp/server/server_test.go +++ b/cmd/docker-mcp/server/server_test.go @@ -10,6 +10,8 @@ import ( "strconv" "testing" + "github.com/docker/cli/cli/command" + "github.com/docker/cli/cli/config/configfile" "github.com/docker/docker/api/types/volume" "github.com/docker/docker/errdefs" "github.com/stretchr/testify/assert" @@ -20,7 +22,7 @@ import ( ) func TestListVolumeNotFound(t *testing.T) { - ctx, home, docker := setup(t, withoutPromptsVolume()) + ctx, home, docker := setupForList(t, withoutPromptsVolume()) enabled, err := List(ctx, docker) require.NoError(t, err) @@ -30,7 +32,7 @@ func TestListVolumeNotFound(t *testing.T) { } func TestListEmptyVolume(t *testing.T) { - ctx, home, docker := setup(t, withEmptyPromptsVolume()) + ctx, home, docker := setupForList(t, withEmptyPromptsVolume()) enabled, err := List(ctx, docker) require.NoError(t, err) @@ -40,7 +42,7 @@ func TestListEmptyVolume(t *testing.T) { } func TestListImportVolume(t *testing.T) { - ctx, home, docker := setup(t, withRegistryYamlInPromptsVolume("registry:\n github-official:\n ref: \"\"")) + ctx, home, docker := setupForList(t, withRegistryYamlInPromptsVolume("registry:\n github-official:\n ref: \"\"")) enabled, err := List(ctx, docker) require.NoError(t, err) @@ -50,7 +52,7 @@ func TestListImportVolume(t *testing.T) { } func TestListEmpty(t *testing.T) { - ctx, _, docker := setup(t, withEmptyRegistryYaml()) + ctx, _, docker := setupForList(t, withEmptyRegistryYaml()) enabled, err := List(ctx, docker) require.NoError(t, err) @@ -58,7 +60,7 @@ func TestListEmpty(t *testing.T) { } func TestList(t *testing.T) { - ctx, _, docker := setup(t, withRegistryYaml("registry:\n git:\n ref: \"\"")) + ctx, _, docker := setupForList(t, withRegistryYaml("registry:\n git:\n ref: \"\"")) enabled, err := List(ctx, docker) require.NoError(t, err) @@ -66,16 +68,16 @@ func TestList(t *testing.T) { } func TestEnableNotFound(t *testing.T) { - ctx, _, docker := setup(t, withEmptyRegistryYaml(), withEmptyCatalog()) + ctx, _, docker, dockerCli := setup(t, withEmptyRegistryYaml(), withEmptyCatalog()) - err := Enable(ctx, docker, []string{"duckduckgo"}, false) + err := Enable(ctx, docker, dockerCli, []string{"duckduckgo"}, false) require.ErrorContains(t, err, "server duckduckgo not found in catalog") } func TestEnable(t *testing.T) { - ctx, _, docker := setup(t, withEmptyRegistryYaml(), withCatalog("registry:\n duckduckgo:\n")) + ctx, _, docker, dockerCli := setup(t, withEmptyRegistryYaml(), withCatalog("registry:\n duckduckgo:\n")) - err := Enable(ctx, docker, []string{"duckduckgo"}, false) + err := Enable(ctx, docker, dockerCli, []string{"duckduckgo"}, false) require.NoError(t, err) enabled, err := List(ctx, docker) @@ -84,9 +86,9 @@ func TestEnable(t *testing.T) { } func TestDisable(t *testing.T) { - ctx, _, docker := setup(t, withRegistryYaml("registry:\n duckduckgo:\n ref: \"\"\n git:\n ref: \"\""), withCatalog("registry:\n git:\n duckduckgo:\n")) + ctx, _, docker, dockerCli := setup(t, withRegistryYaml("registry:\n duckduckgo:\n ref: \"\"\n git:\n ref: \"\""), withCatalog("registry:\n git:\n duckduckgo:\n")) - err := Disable(ctx, docker, []string{"duckduckgo"}, false) + err := Disable(ctx, docker, dockerCli, []string{"duckduckgo"}, false) require.NoError(t, err) enabled, err := List(ctx, docker) @@ -95,9 +97,9 @@ func TestDisable(t *testing.T) { } func TestDisableUnknown(t *testing.T) { - ctx, _, docker := setup(t, withRegistryYaml("registry:\n duckduckgo:\n ref: \"\""), withCatalog("registry:\n duckduckgo:\n")) + ctx, _, docker, dockerCli := setup(t, withRegistryYaml("registry:\n duckduckgo:\n ref: \"\""), withCatalog("registry:\n duckduckgo:\n")) - err := Disable(ctx, docker, []string{"unknown"}, false) + err := Disable(ctx, docker, dockerCli, []string{"unknown"}, false) require.NoError(t, err) enabled, err := List(ctx, docker) @@ -106,9 +108,9 @@ func TestDisableUnknown(t *testing.T) { } func TestRemoveOutdatedServerOnEnable(t *testing.T) { - ctx, _, docker := setup(t, withRegistryYaml("registry:\n outdated:\n ref: \"\""), withCatalog("registry:\n git:\n")) + ctx, _, docker, dockerCli := setup(t, withRegistryYaml("registry:\n outdated:\n ref: \"\""), withCatalog("registry:\n git:\n")) - err := Enable(ctx, docker, []string{"git"}, false) + err := Enable(ctx, docker, dockerCli, []string{"git"}, false) require.NoError(t, err) enabled, err := List(ctx, docker) @@ -117,9 +119,9 @@ func TestRemoveOutdatedServerOnEnable(t *testing.T) { } func TestRemoveOutdatedServerOnDisable(t *testing.T) { - ctx, _, docker := setup(t, withRegistryYaml("registry:\n outdated:\n ref: \"\""), withEmptyCatalog()) + ctx, _, docker, dockerCli := setup(t, withRegistryYaml("registry:\n outdated:\n ref: \"\""), withEmptyCatalog()) - err := Disable(ctx, docker, []string{"git"}, false) + err := Disable(ctx, docker, dockerCli, []string{"git"}, false) require.NoError(t, err) enabled, err := List(ctx, docker) @@ -129,7 +131,7 @@ func TestRemoveOutdatedServerOnDisable(t *testing.T) { // Fixtures -func setup(t *testing.T, options ...option) (context.Context, string, docker.Client) { +func setup(t *testing.T, options ...option) (context.Context, string, docker.Client, command.Cli) { t.Helper() // Mock for Docker API @@ -147,7 +149,13 @@ func setup(t *testing.T, options ...option) (context.Context, string, docker.Cli o(t, home, docker) } - return t.Context(), home, docker + return t.Context(), home, docker, &fakeCli{} +} + +func setupForList(t *testing.T, options ...option) (context.Context, string, docker.Client) { + t.Helper() + ctx, home, docker, _ := setup(t, options...) + return ctx, home, docker } func writeFile(t *testing.T, path string, content []byte) { @@ -168,6 +176,14 @@ func (f *fakeDocker) InspectVolume(context.Context, string) (volume.Volume, erro return f.volume, f.inspectErr } +type fakeCli struct { + command.Cli +} + +func (fakeCli) ConfigFile() *configfile.ConfigFile { + return &configfile.ConfigFile{} +} + type exitCodeErr struct { exitCode int } diff --git a/cmd/docker-mcp/tools/list.go b/cmd/docker-mcp/tools/list.go index 63a43434..0e393050 100644 --- a/cmd/docker-mcp/tools/list.go +++ b/cmd/docker-mcp/tools/list.go @@ -6,6 +6,7 @@ import ( "fmt" "strings" + "github.com/docker/cli/cli/command" "github.com/modelcontextprotocol/go-sdk/mcp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" @@ -14,7 +15,7 @@ import ( "github.com/docker/mcp-gateway/cmd/docker-mcp/hints" ) -func List(ctx context.Context, version string, gatewayArgs []string, debug bool, show, tool, format string) error { +func List(ctx context.Context, dockerCli command.Cli, version string, gatewayArgs []string, debug bool, show, tool, format string) error { // Initialize telemetry for CLI operations meter := otel.GetMeterProvider().Meter("github.com/docker/mcp-gateway") toolsDiscoveredGauge, _ := meter.Int64Gauge("mcp.cli.tools.discovered", @@ -52,7 +53,7 @@ func List(ctx context.Context, version string, gatewayArgs []string, debug bool, for _, tool := range response.Tools { fmt.Println(" -", tool.Name, "-", toolDescription(tool)) } - if hints.Enabled() { + if hints.Enabled(dockerCli) { hints.TipCyan.Print("Tip: For tool details, use ") hints.TipCyanBoldItalic.Print("docker mcp tools inspect ") hints.TipCyan.Print(". To test the tool, use ") @@ -65,7 +66,7 @@ func List(ctx context.Context, version string, gatewayArgs []string, debug bool, fmt.Printf("{\"count\": %d}\n", len(response.Tools)) } else { fmt.Println(len(response.Tools), "tools") - if hints.Enabled() { + if hints.Enabled(dockerCli) { hints.TipCyan.Print("Tip: To see all available tools, use ") hints.TipCyanBoldItalic.Println("docker mcp tools ls") fmt.Println() From 6ed6c0676e10dfb24239f9bc2663c5fffba80039 Mon Sep 17 00:00:00 2001 From: Austin Berry Date: Fri, 24 Oct 2025 16:24:50 -0400 Subject: [PATCH 7/7] make the conditions more readable --- cmd/docker-mcp/hints/hints.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/cmd/docker-mcp/hints/hints.go b/cmd/docker-mcp/hints/hints.go index cc533b08..0e57766d 100644 --- a/cmd/docker-mcp/hints/hints.go +++ b/cmd/docker-mcp/hints/hints.go @@ -7,15 +7,21 @@ import ( func Enabled(dockerCli command.Cli) bool { configFile := dockerCli.ConfigFile() - if configFile != nil && configFile.Plugins != nil { - if pluginConfig, ok := configFile.Plugins["-x-cli-hints"]; ok { - if enabledValue, exists := pluginConfig["enabled"]; exists { - return enabledValue == "true" - } - } + if configFile == nil || configFile.Plugins == nil { + return true } - return true + pluginConfig, ok := configFile.Plugins["-x-cli-hints"] + if !ok { + return true + } + + enabledValue, exists := pluginConfig["enabled"] + if !exists { + return true + } + + return enabledValue == "true" } var (