Change summary
internal/config/docker_mcp.go | 32 +++++++++++++++++++++++---------
internal/ui/model/ui.go | 14 ++++++++++++--
2 files changed, 35 insertions(+), 11 deletions(-)
Detailed changes
@@ -34,30 +34,44 @@ func (c *Config) IsDockerMCPEnabled() bool {
return exists
}
-// EnableDockerMCP adds Docker MCP configuration and persists it.
-func (s *ConfigStore) EnableDockerMCP() error {
- if !IsDockerMCPAvailable() {
- return fmt.Errorf("docker mcp is not available, please ensure docker is installed and 'docker mcp version' succeeds")
- }
-
- mcpConfig := MCPConfig{
+func DockerMCPConfig() MCPConfig {
+ return MCPConfig{
Type: MCPStdio,
Command: "docker",
Args: []string{"mcp", "gateway", "run"},
Disabled: false,
}
+}
+
+func (s *ConfigStore) PrepareDockerMCPConfig() (MCPConfig, error) {
+ if !IsDockerMCPAvailable() {
+ return MCPConfig{}, fmt.Errorf("docker mcp is not available, please ensure docker is installed and 'docker mcp version' succeeds")
+ }
- // Add to in-memory config.
+ mcpConfig := DockerMCPConfig()
if s.config.MCP == nil {
s.config.MCP = make(map[string]MCPConfig)
}
s.config.MCP[DockerMCPName] = mcpConfig
+ return mcpConfig, nil
+}
- // Persist to config file.
+func (s *ConfigStore) PersistDockerMCPConfig(mcpConfig MCPConfig) error {
if err := s.SetConfigField(ScopeGlobal, "mcp."+DockerMCPName, mcpConfig); err != nil {
return fmt.Errorf("failed to persist docker mcp configuration: %w", err)
}
+ return nil
+}
+// EnableDockerMCP adds Docker MCP configuration and persists it.
+func (s *ConfigStore) EnableDockerMCP() error {
+ mcpConfig, err := s.PrepareDockerMCPConfig()
+ if err != nil {
+ return err
+ }
+ if err := s.PersistDockerMCPConfig(mcpConfig); err != nil {
+ return err
+ }
return nil
}
@@ -3465,16 +3465,26 @@ func (m *UI) copyChatHighlight() tea.Cmd {
func (m *UI) enableDockerMCP() tea.Msg {
store := m.com.Store()
- if err := store.EnableDockerMCP(); err != nil {
+ // Stage Docker MCP in memory first so startup and persistence can be atomic.
+ mcpConfig, err := store.PrepareDockerMCPConfig()
+ if err != nil {
return util.ReportError(err)()
}
- // Initialize the Docker MCP client immediately.
ctx := context.Background()
if err := mcp.InitializeSingle(ctx, config.DockerMCPName, store); err != nil {
+ // Roll back in-memory state when startup fails.
+ delete(store.Config().MCP, config.DockerMCPName)
return util.ReportError(fmt.Errorf("docker MCP enabled but failed to start: %w", err))()
}
+ if err := store.PersistDockerMCPConfig(mcpConfig); err != nil {
+ // Roll back runtime and in-memory state if persistence fails.
+ _ = mcp.DisableSingle(store, config.DockerMCPName)
+ delete(store.Config().MCP, config.DockerMCPName)
+ return util.ReportError(fmt.Errorf("docker MCP started but failed to persist configuration: %w", err))()
+ }
+
return util.NewInfoMsg("Docker MCP enabled and started successfully")
}