Skip to content
Merged
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
13 changes: 12 additions & 1 deletion cmd/docker-mcp/commands/catalog_next.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,25 @@ import (

catalognext "github.com/docker/mcp-gateway/pkg/catalog_next"
"github.com/docker/mcp-gateway/pkg/db"
"github.com/docker/mcp-gateway/pkg/docker"
"github.com/docker/mcp-gateway/pkg/migrate"
"github.com/docker/mcp-gateway/pkg/oci"
"github.com/docker/mcp-gateway/pkg/workingset"
)

func catalogNextCommand() *cobra.Command {
func catalogNextCommand(docker docker.Client) *cobra.Command {
cmd := &cobra.Command{
Use: "catalog-next",
Short: "Manage catalogs (next generation)",
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
dao, err := db.New()
if err != nil {
return err
}
defer dao.Close()
migrate.MigrateConfig(cmd.Context(), docker, dao)
return nil
},
}

cmd.AddCommand(createCatalogNextCommand())
Expand Down
2 changes: 2 additions & 0 deletions cmd/docker-mcp/commands/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ func gatewayCommand(docker docker.Client, dockerCli command.Cli) *cobra.Command
options.MCPRegistryServers = mcpServers
}

// TODO(cody): When all commands are migrated, we should default this parameter to "default"
// Also need to consider the case when there is no default profile
if options.WorkingSet != "" {
if len(options.ServerNames) > 0 {
return fmt.Errorf("cannot use --profile with --servers flag")
Expand Down
4 changes: 2 additions & 2 deletions cmd/docker-mcp/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ 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(workingSetCommand(dockerClient))
cmd.AddCommand(catalogNextCommand(dockerClient))
}
cmd.AddCommand(catalogCommand(dockerCli))
cmd.AddCommand(clientCommand(dockerCli, cwd))
Expand Down
13 changes: 12 additions & 1 deletion cmd/docker-mcp/commands/workingset.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,29 @@ import (

"github.com/docker/mcp-gateway/pkg/client"
"github.com/docker/mcp-gateway/pkg/db"
"github.com/docker/mcp-gateway/pkg/docker"
"github.com/docker/mcp-gateway/pkg/migrate"
"github.com/docker/mcp-gateway/pkg/oci"
"github.com/docker/mcp-gateway/pkg/registryapi"
"github.com/docker/mcp-gateway/pkg/sliceutil"
"github.com/docker/mcp-gateway/pkg/workingset"
)

func workingSetCommand() *cobra.Command {
func workingSetCommand(docker docker.Client) *cobra.Command {
cfg := client.ReadConfig()

cmd := &cobra.Command{
Use: "profile",
Short: "Manage profiles",
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
dao, err := db.New()
if err != nil {
return err
}
defer dao.Close()
migrate.MigrateConfig(cmd.Context(), docker, dao)
return nil
},
}

cmd.AddCommand(exportWorkingSetCommand())
Expand Down
8 changes: 8 additions & 0 deletions pkg/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ import (
type DAO interface {
WorkingSetDAO
CatalogDAO
MigrationStatusDAO

// Normally unnecessary to call this
Close() error
}

type dao struct {
Expand Down Expand Up @@ -97,6 +101,10 @@ func New(opts ...Option) (DAO, error) {
return &dao{db: sqlxDb}, nil
}

func (d *dao) Close() error {
return d.db.Close()
}

func DefaultDatabaseFilename() (string, error) {
homeDir, err := user.HomeDir()
if err != nil {
Expand Down
56 changes: 56 additions & 0 deletions pkg/db/migration_status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package db

import (
"context"
"time"
)

type MigrationStatusDAO interface {
GetMigrationStatus(ctx context.Context) (*MigrationStatus, error)
UpdateMigrationStatus(ctx context.Context, status MigrationStatus) error
}

type MigrationStatus struct {
ID *int64 `db:"id"`
Status string `db:"status"`
Logs string `db:"logs"`
LastUpdated *time.Time `db:"last_updated"`
}

func (d *dao) GetMigrationStatus(ctx context.Context) (*MigrationStatus, error) {
const query = `SELECT id, status, logs, last_updated FROM migration_status LIMIT 1`

var migrationStatus MigrationStatus
err := d.db.GetContext(ctx, &migrationStatus, query)
if err != nil {
return nil, err
}
return &migrationStatus, nil
}

func (d *dao) UpdateMigrationStatus(ctx context.Context, status MigrationStatus) error {
tx, err := d.db.BeginTxx(ctx, nil)
if err != nil {
return err
}
defer txClose(tx, &err)

const deleteQuery = `DELETE FROM migration_status`
_, err = tx.ExecContext(ctx, deleteQuery)
if err != nil {
return err
}

const query = `INSERT INTO migration_status (status, logs) VALUES ($1, $2)`

_, err = tx.ExecContext(ctx, query, status.Status, status.Logs)
if err != nil {
return err
}

if err = tx.Commit(); err != nil {
return err
}

return nil
}
6 changes: 6 additions & 0 deletions pkg/db/migrations/004_create_migration_status.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
create table migration_status (
id integer primary key,
status text not null,
logs text,
last_updated DATETIME DEFAULT CURRENT_TIMESTAMP
);
18 changes: 11 additions & 7 deletions pkg/gateway/configuration_workingset.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/docker/mcp-gateway/pkg/db"
"github.com/docker/mcp-gateway/pkg/docker"
"github.com/docker/mcp-gateway/pkg/log"
"github.com/docker/mcp-gateway/pkg/migrate"
"github.com/docker/mcp-gateway/pkg/oci"
"github.com/docker/mcp-gateway/pkg/workingset"
)
Expand All @@ -31,7 +32,15 @@ func NewWorkingSetConfiguration(workingSet string, ociService oci.Service, docke
}

func (c *WorkingSetConfiguration) Read(ctx context.Context) (Configuration, chan Configuration, func() error, error) {
configuration, err := c.readOnce(ctx)
dao, err := db.New()
if err != nil {
return Configuration{}, nil, nil, fmt.Errorf("failed to create database client: %w", err)
}

// Do migration from legacy files
migrate.MigrateConfig(ctx, c.docker, dao)

configuration, err := c.readOnce(ctx, dao)
if err != nil {
return Configuration{}, nil, nil, err
}
Expand All @@ -42,15 +51,10 @@ func (c *WorkingSetConfiguration) Read(ctx context.Context) (Configuration, chan
return configuration, updates, func() error { return nil }, nil
}

func (c *WorkingSetConfiguration) readOnce(ctx context.Context) (Configuration, error) {
func (c *WorkingSetConfiguration) readOnce(ctx context.Context, dao db.DAO) (Configuration, error) {
start := time.Now()
log.Log("- Reading profile configuration...")

dao, err := db.New()
if err != nil {
return Configuration{}, fmt.Errorf("failed to create database client: %w", err)
}

dbWorkingSet, err := dao.GetWorkingSet(ctx, c.WorkingSet)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
Expand Down
Loading
Loading