Skip to content

Commit a1cb7e5

Browse files
authored
Merge pull request #198 from docker/add-post-command-tips
2 parents 00034c2 + 6ed6c06 commit a1cb7e5

File tree

12 files changed

+161
-48
lines changed

12 files changed

+161
-48
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/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/root.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func Root(ctx context.Context, cwd string, dockerCli command.Cli) *cobra.Command
7171
dockerClient := docker.NewClient(dockerCli)
7272

7373
cmd.AddCommand(catalogCommand(dockerCli))
74-
cmd.AddCommand(clientCommand(cwd))
74+
cmd.AddCommand(clientCommand(dockerCli, cwd))
7575
cmd.AddCommand(configCommand(dockerClient))
7676
cmd.AddCommand(featureCommand(dockerCli))
7777
cmd.AddCommand(gatewayCommand(dockerClient, dockerCli))
@@ -80,7 +80,7 @@ func Root(ctx context.Context, cwd string, dockerCli command.Cli) *cobra.Command
8080
cmd.AddCommand(registryCommand())
8181
cmd.AddCommand(secretCommand(dockerClient))
8282
cmd.AddCommand(serverCommand(dockerClient, dockerCli))
83-
cmd.AddCommand(toolsCommand(dockerClient))
83+
cmd.AddCommand(toolsCommand(dockerClient, dockerCli))
8484
cmd.AddCommand(versionCommand())
8585

8686
if os.Getenv("DOCKER_MCP_SHOW_HIDDEN") == "1" {

cmd/docker-mcp/commands/server.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/docker/cli/cli/command"
99
"github.com/spf13/cobra"
1010

11+
"github.com/docker/mcp-gateway/cmd/docker-mcp/hints"
1112
"github.com/docker/mcp-gateway/cmd/docker-mcp/server"
1213
"github.com/docker/mcp-gateway/pkg/config"
1314
"github.com/docker/mcp-gateway/pkg/docker"
@@ -42,6 +43,11 @@ func serverCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command {
4243
fmt.Fprintln(cmd.OutOrStdout(), "No server is enabled")
4344
} else {
4445
fmt.Fprintln(cmd.OutOrStdout(), strings.Join(list, ", "))
46+
if hints.Enabled(dockerCli) {
47+
hints.TipCyan.Fprint(cmd.OutOrStdout(), "Tip: To use these servers, connect to a client (IE: claude/cursor) with ")
48+
hints.TipCyanBoldItalic.Fprintln(cmd.OutOrStdout(), "docker mcp client connect <client-name>")
49+
fmt.Fprintln(cmd.OutOrStdout(), "")
50+
}
4551
}
4652

4753
return nil
@@ -57,7 +63,7 @@ func serverCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command {
5763
Args: cobra.MinimumNArgs(1),
5864
RunE: func(cmd *cobra.Command, args []string) error {
5965
mcpOAuthDcrEnabled := isMcpOAuthDcrFeatureEnabled(dockerCli)
60-
return server.Enable(cmd.Context(), docker, args, mcpOAuthDcrEnabled)
66+
return server.Enable(cmd.Context(), docker, dockerCli, args, mcpOAuthDcrEnabled)
6167
},
6268
})
6369

@@ -68,7 +74,7 @@ func serverCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command {
6874
Args: cobra.MinimumNArgs(1),
6975
RunE: func(cmd *cobra.Command, args []string) error {
7076
mcpOAuthDcrEnabled := isMcpOAuthDcrFeatureEnabled(dockerCli)
71-
return server.Disable(cmd.Context(), docker, args, mcpOAuthDcrEnabled)
77+
return server.Disable(cmd.Context(), docker, dockerCli, args, mcpOAuthDcrEnabled)
7278
},
7379
})
7480

cmd/docker-mcp/commands/tools.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package commands
22

33
import (
4+
"github.com/docker/cli/cli/command"
45
"github.com/spf13/cobra"
56

67
"github.com/docker/mcp-gateway/cmd/docker-mcp/tools"
78
"github.com/docker/mcp-gateway/pkg/docker"
89
)
910

10-
func toolsCommand(docker docker.Client) *cobra.Command {
11+
func toolsCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command {
1112
cmd := &cobra.Command{
1213
Use: "tools",
1314
Short: "Manage tools",
@@ -30,7 +31,7 @@ func toolsCommand(docker docker.Client) *cobra.Command {
3031
Short: "List tools",
3132
Args: cobra.NoArgs,
3233
RunE: func(cmd *cobra.Command, _ []string) error {
33-
return tools.List(cmd.Context(), version, gatewayArgs, verbose, "list", "", format)
34+
return tools.List(cmd.Context(), dockerCli, version, gatewayArgs, verbose, "list", "", format)
3435
},
3536
})
3637

@@ -39,7 +40,7 @@ func toolsCommand(docker docker.Client) *cobra.Command {
3940
Short: "Count tools",
4041
Args: cobra.NoArgs,
4142
RunE: func(cmd *cobra.Command, _ []string) error {
42-
return tools.List(cmd.Context(), version, gatewayArgs, verbose, "count", "", format)
43+
return tools.List(cmd.Context(), dockerCli, version, gatewayArgs, verbose, "count", "", format)
4344
},
4445
})
4546

@@ -48,7 +49,7 @@ func toolsCommand(docker docker.Client) *cobra.Command {
4849
Short: "Inspect a tool",
4950
Args: cobra.ExactArgs(1),
5051
RunE: func(cmd *cobra.Command, args []string) error {
51-
return tools.List(cmd.Context(), version, gatewayArgs, verbose, "inspect", args[0], format)
52+
return tools.List(cmd.Context(), dockerCli, version, gatewayArgs, verbose, "inspect", args[0], format)
5253
},
5354
})
5455
cmd.AddCommand(&cobra.Command{

cmd/docker-mcp/hints/hints.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package hints
2+
3+
import (
4+
"github.com/docker/cli/cli/command"
5+
"github.com/fatih/color"
6+
)
7+
8+
func Enabled(dockerCli command.Cli) bool {
9+
configFile := dockerCli.ConfigFile()
10+
if configFile == nil || configFile.Plugins == nil {
11+
return true
12+
}
13+
14+
pluginConfig, ok := configFile.Plugins["-x-cli-hints"]
15+
if !ok {
16+
return true
17+
}
18+
19+
enabledValue, exists := pluginConfig["enabled"]
20+
if !exists {
21+
return true
22+
}
23+
24+
return enabledValue == "true"
25+
}
26+
27+
var (
28+
TipCyan = color.New(color.FgCyan)
29+
TipCyanBoldItalic = color.New(color.FgCyan, color.Bold, color.Italic)
30+
TipGreen = color.New(color.FgGreen)
31+
)

cmd/docker-mcp/server/enable.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,25 @@ import (
55
"context"
66
"fmt"
77

8+
"github.com/docker/cli/cli/command"
89
"gopkg.in/yaml.v3"
910

11+
"github.com/docker/mcp-gateway/cmd/docker-mcp/hints"
1012
"github.com/docker/mcp-gateway/pkg/catalog"
1113
"github.com/docker/mcp-gateway/pkg/config"
1214
"github.com/docker/mcp-gateway/pkg/docker"
1315
"github.com/docker/mcp-gateway/pkg/oauth"
1416
)
1517

16-
func Disable(ctx context.Context, docker docker.Client, serverNames []string, mcpOAuthDcrEnabled bool) error {
17-
return update(ctx, docker, nil, serverNames, mcpOAuthDcrEnabled)
18+
func Disable(ctx context.Context, docker docker.Client, dockerCli command.Cli, serverNames []string, mcpOAuthDcrEnabled bool) error {
19+
return update(ctx, docker, dockerCli, nil, serverNames, mcpOAuthDcrEnabled)
1820
}
1921

20-
func Enable(ctx context.Context, docker docker.Client, serverNames []string, mcpOAuthDcrEnabled bool) error {
21-
return update(ctx, docker, serverNames, nil, mcpOAuthDcrEnabled)
22+
func Enable(ctx context.Context, docker docker.Client, dockerCli command.Cli, serverNames []string, mcpOAuthDcrEnabled bool) error {
23+
return update(ctx, docker, dockerCli, serverNames, nil, mcpOAuthDcrEnabled)
2224
}
2325

24-
func update(ctx context.Context, docker docker.Client, add []string, remove []string, mcpOAuthDcrEnabled bool) error {
26+
func update(ctx context.Context, docker docker.Client, dockerCli command.Cli, add []string, remove []string, mcpOAuthDcrEnabled bool) error {
2527
// Read registry.yaml that contains which servers are enabled.
2628
registryYAML, err := config.ReadRegistry(ctx, docker)
2729
if err != nil {
@@ -94,5 +96,21 @@ func update(ctx context.Context, docker docker.Client, add []string, remove []st
9496
return fmt.Errorf("writing registry config: %w", err)
9597
}
9698

99+
if len(add) > 0 && hints.Enabled(dockerCli) {
100+
hints.TipCyan.Print("Tip: ")
101+
hints.TipGreen.Print("✓")
102+
hints.TipCyan.Print(" Server enabled. To view all enabled servers, use ")
103+
hints.TipCyanBoldItalic.Println("docker mcp server ls")
104+
fmt.Println()
105+
}
106+
107+
if len(remove) > 0 && hints.Enabled(dockerCli) {
108+
hints.TipCyan.Print("Tip: ")
109+
hints.TipGreen.Print("✓")
110+
hints.TipCyan.Print(" Server disabled. To see remaining enabled servers, use ")
111+
hints.TipCyanBoldItalic.Println("docker mcp server ls")
112+
fmt.Println()
113+
}
114+
97115
return nil
98116
}

0 commit comments

Comments
 (0)