11package commands
22
33import (
4+ "context"
5+ "encoding/json"
46 "fmt"
57
68 "github.com/spf13/cobra"
79
810 "github.com/docker/mcp-gateway/cmd/docker-mcp/catalog"
11+ catalogTypes "github.com/docker/mcp-gateway/cmd/docker-mcp/internal/catalog"
12+ "github.com/docker/mcp-gateway/cmd/docker-mcp/internal/yq"
913)
1014
1115func catalogCommand () * cobra.Command {
@@ -31,21 +35,40 @@ func catalogCommand() *cobra.Command {
3135}
3236
3337func importCatalogCommand () * cobra.Command {
34- return & cobra.Command {
38+ var mcpRegistry string
39+ var dryRun bool
40+ cmd := & cobra.Command {
3541 Use : "import <alias|url|file>" ,
3642 Short : "Import a catalog from URL or file" ,
3743 Long : `Import an MCP server catalog from a URL or local file. The catalog will be downloaded
38- and stored locally for use with the MCP gateway.` ,
44+ and stored locally for use with the MCP gateway.
45+
46+ When --mcp-registry flag is used, the argument must be an existing catalog name, and the
47+ command will import servers from the MCP registry URL into that catalog.` ,
3948 Args : cobra .ExactArgs (1 ),
4049 Example : ` # Import from URL
4150 docker mcp catalog import https://example.com/my-catalog.yaml
4251
4352 # Import from local file
44- docker mcp catalog import ./shared-catalog.yaml` ,
53+ docker mcp catalog import ./shared-catalog.yaml
54+
55+ # Import from MCP registry URL into existing catalog
56+ docker mcp catalog import my-catalog --mcp-registry https://registry.example.com/server` ,
4557 RunE : func (cmd * cobra.Command , args []string ) error {
58+ // If mcp-registry flag is provided, import to existing catalog
59+ if mcpRegistry != "" {
60+ if dryRun {
61+ return runOfficialregistryImport (cmd .Context (), mcpRegistry , nil )
62+ }
63+ return importMCPRegistryToCatalog (cmd .Context (), args [0 ], mcpRegistry )
64+ }
65+ // Default behavior: import entire catalog
4666 return catalog .Import (cmd .Context (), args [0 ])
4767 },
4868 }
69+ cmd .Flags ().StringVar (& mcpRegistry , "mcp-registry" , "" , "Import server from MCP registry URL into existing catalog" )
70+ cmd .Flags ().BoolVar (& dryRun , "dry-run" , false , "Show Imported Data but do not update the Catalog" )
71+ return cmd
4972}
5073
5174func exportCatalogCommand () * cobra.Command {
@@ -237,3 +260,69 @@ func resetCatalogCommand() *cobra.Command {
237260 },
238261 }
239262}
263+
264+ // importMCPRegistryToCatalog imports a server from an MCP registry URL into an existing catalog
265+ func importMCPRegistryToCatalog (ctx context.Context , catalogName , mcpRegistryURL string ) error {
266+ // Check if the catalog exists
267+ cfg , err := catalog .ReadConfig ()
268+ if err != nil {
269+ return fmt .Errorf ("failed to read catalog config: %w" , err )
270+ }
271+
272+ _ , exists := cfg .Catalogs [catalogName ]
273+ if ! exists {
274+ return fmt .Errorf ("catalog '%s' does not exist" , catalogName )
275+ }
276+
277+ // Prevent users from modifying the Docker catalog
278+ if catalogName == catalog .DockerCatalogName {
279+ return fmt .Errorf ("cannot import servers into catalog '%s' as it is managed by Docker" , catalogName )
280+ }
281+
282+ // Fetch server from MCP registry
283+ var servers []catalogTypes.Server
284+ if err := runOfficialregistryImport (ctx , mcpRegistryURL , & servers ); err != nil {
285+ return fmt .Errorf ("failed to fetch server from MCP registry: %w" , err )
286+ }
287+
288+ if len (servers ) == 0 {
289+ return fmt .Errorf ("no servers found at MCP registry URL" )
290+ }
291+
292+ // For now, we'll import the first server (MCP registry URLs typically contain one server)
293+ server := servers [0 ]
294+
295+ serverName := server .Name
296+
297+ // Convert the server to JSON for injection into the catalog
298+ serverJSON , err := json .Marshal (server )
299+ if err != nil {
300+ return fmt .Errorf ("failed to marshal server: %w" , err )
301+ }
302+
303+ // Read the current catalog content
304+ catalogContent , err := catalog .ReadCatalogFile (catalogName )
305+ if err != nil {
306+ return fmt .Errorf ("failed to read catalog file: %w" , err )
307+ }
308+
309+ // Inject the server into the catalog using the same pattern as the add function
310+ updatedContent , err := injectServerIntoCatalog (catalogContent , serverName , serverJSON )
311+ if err != nil {
312+ return fmt .Errorf ("failed to inject server into catalog: %w" , err )
313+ }
314+
315+ // Write the updated catalog back
316+ if err := catalog .WriteCatalogFile (catalogName , updatedContent ); err != nil {
317+ return fmt .Errorf ("failed to write updated catalog: %w" , err )
318+ }
319+
320+ fmt .Printf ("Successfully imported server '%s' from MCP registry into catalog '%s'\n " , serverName , catalogName )
321+ return nil
322+ }
323+
324+ // injectServerIntoCatalog injects a server JSON into a catalog YAML using yq
325+ func injectServerIntoCatalog (yamlData []byte , serverName string , serverJSON []byte ) ([]byte , error ) {
326+ query := fmt .Sprintf (`.registry."%s" = %s` , serverName , string (serverJSON ))
327+ return yq .Evaluate (query , yamlData , yq .NewYamlDecoder (), yq .NewYamlEncoder ())
328+ }
0 commit comments