Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions cmd/docker-mcp/commands/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import (
"github.com/docker/mcp-gateway/pkg/yq"
)

func catalogCommand(dockerCli command.Cli) *cobra.Command {
func deprecatedCatalogCommand(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{
Use: "catalog",
Aliases: []string{"catalogs"},
Short: "Manage MCP server catalogs",
Long: `Manage MCP server catalogs for organizing and configuring custom MCP servers alongside Docker's official catalog.`,
Use: "catalog-deprecated",
Aliases: []string{"catalogs-deprecated"},
Short: "Deprecated: Manage MCP server catalogs",
Long: `Deprecated: Manage MCP server catalogs for organizing and configuring custom MCP servers alongside Docker's official catalog.`,
Hidden: true,
}
cmd.AddCommand(bootstrapCatalogCommand())
cmd.AddCommand(importCatalogCommand())
Expand Down
6 changes: 3 additions & 3 deletions cmd/docker-mcp/commands/catalog_next.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import (
"github.com/docker/mcp-gateway/pkg/workingset"
)

func catalogNextCommand() *cobra.Command {
func catalogCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "catalog-next",
Short: "Manage catalogs (next generation)",
Use: "catalog",
Short: "Manage MCP server catalogs",
}

cmd.AddCommand(createCatalogNextCommand())
Expand Down
10 changes: 5 additions & 5 deletions cmd/docker-mcp/commands/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func connectClientCommand(dockerCli command.Cli, cwd string, cfg client.Config)
WorkingSet string
}
cmd := &cobra.Command{
Use: fmt.Sprintf("connect [OPTIONS] <mcp-client>\n\nSupported clients: %s", strings.Join(client.GetSupportedMCPClients(cfg), " ")),
Use: fmt.Sprintf("connect [OPTIONS] <mcp-client> --profile <profile-id>\n\nSupported clients: %s", strings.Join(client.GetSupportedMCPClients(cfg), " ")),
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 {
Expand All @@ -62,9 +62,8 @@ func connectClientCommand(dockerCli command.Cli, cwd string, cfg client.Config)
flags := cmd.Flags()
addGlobalFlag(flags, &opts.Global)
addQuietFlag(flags, &opts.Quiet)
if isWorkingSetsFeatureEnabled(dockerCli) {
addWorkingSetFlag(flags, &opts.WorkingSet)
}
_ = cmd.MarkFlagRequired(addWorkingSetFlag(flags, &opts.WorkingSet))

return cmd
}

Expand Down Expand Up @@ -125,6 +124,7 @@ func addQuietFlag(flags *pflag.FlagSet, p *bool) {
flags.BoolVarP(p, "quiet", "q", false, "Only display errors.")
}

func addWorkingSetFlag(flags *pflag.FlagSet, p *string) {
func addWorkingSetFlag(flags *pflag.FlagSet, p *string) string {
flags.StringVarP(p, "profile", "p", "", "Profile to use for client connection.")
return "profile"
}
13 changes: 2 additions & 11 deletions cmd/docker-mcp/commands/feature.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,14 @@ Available features:
oauth-interceptor Enable GitHub OAuth flow interception for automatic authentication
mcp-oauth-dcr Enable Dynamic Client Registration (DCR) for automatic OAuth client setup
dynamic-tools Enable internal MCP management tools (mcp-find, mcp-add, mcp-remove)
profiles Enable profile management (docker mcp profile <subcommand>)
tool-name-prefix Prefix all tool names with server name to avoid conflicts`,
Args: cobra.ExactArgs(1),
RunE: func(_ *cobra.Command, args []string) error {
featureName := args[0]

// Validate feature name
if !isKnownFeature(featureName) {
return fmt.Errorf("unknown feature: %s\n\nAvailable features:\n oauth-interceptor Enable GitHub OAuth flow interception\n mcp-oauth-dcr Enable Dynamic Client Registration for automatic OAuth setup\n dynamic-tools Enable internal MCP management tools\n profiles Enable profile management (docker mcp profile <subcommand>)\n tool-name-prefix Prefix all tool names with server name", featureName)
return fmt.Errorf("unknown feature: %s\n\nAvailable features:\n oauth-interceptor Enable GitHub OAuth flow interception\n mcp-oauth-dcr Enable Dynamic Client Registration for automatic OAuth setup\n dynamic-tools Enable internal MCP management tools\n tool-name-prefix Prefix all tool names with server name", featureName)
}

// Enable the feature
Expand Down Expand Up @@ -85,11 +84,6 @@ Available features:
fmt.Println(" - mcp-add: add MCP servers to the registry and reload configuration")
fmt.Println(" - mcp-remove: remove MCP servers from the registry and reload configuration")
fmt.Println("\nNo additional flags are needed - this applies to all gateway runs.")
case "profiles":
fmt.Println("\nThis feature enables profile management tools.")
fmt.Println("When enabled, the cli provides commands for managing profiles:")
fmt.Println(" - docker mcp profile <subcommand> ...")
fmt.Println("\nThis also enables the --profile flag for the docker mcp gateway run command.")
case "tool-name-prefix":
fmt.Println("\nThis feature enables automatic prefixing of tool names with server names.")
fmt.Println("When enabled, all tools are automatically prefixed with their server name:")
Expand Down Expand Up @@ -151,7 +145,7 @@ func featureListCommand(dockerCli command.Cli) *cobra.Command {
fmt.Println()

// Show all known features
knownFeatures := []string{"oauth-interceptor", "mcp-oauth-dcr", "dynamic-tools", "profiles", "tool-name-prefix"}
knownFeatures := []string{"oauth-interceptor", "mcp-oauth-dcr", "dynamic-tools", "tool-name-prefix"}
for _, feature := range knownFeatures {
status := "disabled"
if isFeatureEnabledFromCli(dockerCli, feature) {
Expand All @@ -168,8 +162,6 @@ func featureListCommand(dockerCli command.Cli) *cobra.Command {
fmt.Printf(" %-20s %s\n", "", "Enable Dynamic Client Registration (DCR) for automatic OAuth client setup")
case "dynamic-tools":
fmt.Printf(" %-20s %s\n", "", "Enable internal MCP management tools (mcp-find, mcp-add, mcp-remove)")
case "profiles":
fmt.Printf(" %-20s %s\n", "", "Enable profile management tools (docker mcp profile <subcommand>)")
case "tool-name-prefix":
fmt.Printf(" %-20s %s\n", "", "Prefix all tool names with server name to avoid conflicts")
}
Expand Down Expand Up @@ -240,7 +232,6 @@ func isKnownFeature(feature string) bool {
"oauth-interceptor",
"mcp-oauth-dcr",
"dynamic-tools",
"profiles",
"tool-name-prefix",
}

Expand Down
49 changes: 18 additions & 31 deletions cmd/docker-mcp/commands/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,7 @@ func gatewayCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command
} else {
// On-host.
options = gateway.Config{
CatalogPath: []string{catalog.DockerCatalogFilename},
RegistryPath: []string{"registry.yaml"},
ConfigPath: []string{"config.yaml"},
ToolsPath: []string{"tools.yaml"},
SecretsPath: "docker-desktop",
SecretsPath: "docker-desktop",
Options: gateway.Options{
Cpus: 1,
Memory: "2Gb",
Expand All @@ -68,6 +64,22 @@ func gatewayCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command
Short: "Run the gateway",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
if len(options.CatalogPath) == 0 && len(options.RegistryPath) == 0 && len(options.ConfigPath) == 0 && len(options.ToolsPath) == 0 {
// We're in working set mode, so use the default profile if no profile is specified
if options.WorkingSet == "" {
options.WorkingSet = "default"
}
}

if options.WorkingSet != "" &&
(len(options.ServerNames) > 0 || enableAllServers ||
len(options.CatalogPath) > 0 || len(options.RegistryPath) > 0 || len(options.ConfigPath) > 0 || len(options.ToolsPath) > 0 ||
len(additionalCatalogs) > 0 || len(additionalRegistries) > 0 || len(additionalConfigs) > 0 || len(additionalToolsConfig) > 0 ||
len(mcpRegistryUrls) > 0 || len(options.OciRef) > 0 ||
options.SecretsPath != "docker-desktop") {
Comment on lines +67 to +79

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid auto-selecting default profile when extra config flags set

The new defaulting to options.WorkingSet="default" fires whenever the catalog/registry/config/tools paths are empty (lines 67-70), but it ignores other configuration flags such as --additional-catalog, --additional-config, --additional-registry, --additional-tools-config, or --mcp-registry. On a host run the subsequent guard at lines 74-79 then rejects the run because a profile is now set, so commands like docker mcp gateway run --additional-catalog foo.yaml or --mcp-registry … fail even though the user never asked for a profile. This blocks non-profile usage whenever any of those flags are provided. The default profile should be skipped when any extra catalog/registry/config inputs are supplied.

Useful? React with 👍 / 👎.

return fmt.Errorf("cannot use --profile with --servers, --enable-all-servers, --catalog, --additional-catalog, --registry, --additional-registry, --config, --additional-config, --tools-config, --additional-tools-config, --secrets, --oci-ref, --mcp-registry flags")
}

// Check if OAuth interceptor feature is enabled
options.OAuthInterceptorEnabled = isOAuthInterceptorFeatureEnabled(dockerCli)

Expand Down Expand Up @@ -123,15 +135,6 @@ func gatewayCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command
options.MCPRegistryServers = mcpServers
}

if options.WorkingSet != "" {
if len(options.ServerNames) > 0 {
return fmt.Errorf("cannot use --profile with --servers flag")
}
if enableAllServers {
return fmt.Errorf("cannot use --profile with --enable-all-servers flag")
}
}

// Handle --enable-all-servers flag
if enableAllServers {
if len(options.ServerNames) > 0 {
Expand Down Expand Up @@ -169,9 +172,7 @@ func gatewayCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command
}

runCmd.Flags().StringSliceVar(&options.ServerNames, "servers", nil, "Names of the servers to enable (if non empty, ignore --registry flag)")
if isWorkingSetsFeatureEnabled(dockerCli) {
runCmd.Flags().StringVar(&options.WorkingSet, "profile", "", "Profile ID to use (mutually exclusive with --servers and --enable-all-servers)")
}
runCmd.Flags().StringVar(&options.WorkingSet, "profile", options.WorkingSet, "Profile ID to use (incompatible with --servers, --enable-all-servers, --catalog, --registry, --config, --tools-config, --secrets, --oci-ref, --mcp-registry)")
runCmd.Flags().BoolVar(&enableAllServers, "enable-all-servers", false, "Enable all servers in the catalog (instead of using individual --servers options)")
runCmd.Flags().StringSliceVar(&options.CatalogPath, "catalog", options.CatalogPath, "Paths to docker catalogs (absolute or relative to ~/.docker/mcp/catalogs/)")
runCmd.Flags().StringSliceVar(&additionalCatalogs, "additional-catalog", nil, "Additional catalog paths to append to the default catalogs")
Expand Down Expand Up @@ -345,17 +346,3 @@ func isToolNamePrefixFeatureEnabled(dockerCli command.Cli) bool {

return value == "enabled"
}

// isWorkingSetsFeatureEnabled checks if the profiles feature is enabled
func isWorkingSetsFeatureEnabled(dockerCli command.Cli) bool {
configFile := dockerCli.ConfigFile()
if configFile == nil || configFile.Features == nil {
return false
}

value, exists := configFile.Features["profiles"]
if !exists {
return false
}
return value == "enabled"
}
8 changes: 3 additions & 5 deletions cmd/docker-mcp/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,9 @@ func Root(ctx context.Context, cwd string, dockerCli command.Cli) *cobra.Command

dockerClient := docker.NewClient(dockerCli)

if isWorkingSetsFeatureEnabled(dockerCli) {
cmd.AddCommand(workingSetCommand())
cmd.AddCommand(catalogNextCommand())
}
cmd.AddCommand(catalogCommand(dockerCli))
cmd.AddCommand(workingSetCommand())
cmd.AddCommand(catalogCommand())
cmd.AddCommand(deprecatedCatalogCommand(dockerCli))
cmd.AddCommand(clientCommand(dockerCli, cwd))
cmd.AddCommand(configCommand(dockerClient))
cmd.AddCommand(featureCommand(dockerCli))
Expand Down
2 changes: 1 addition & 1 deletion cmd/docker-mcp/commands/workingset.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func workingSetCommand() *cobra.Command {

cmd := &cobra.Command{
Use: "profile",
Short: "Manage profiles",
Short: "Manage MCP profiles",
}

cmd.AddCommand(exportWorkingSetCommand())
Expand Down
Loading
Loading