charmbracelet/crush · error
failed to disable docker MCP: %w
Error message
failed to disable docker MCP: %w
What it means
DisableDockerMCP stops the Docker MCP tool via mcptools.DisableSingle and this error wraps any failure from that shutdown step. It means the Docker MCP tool could not be cleanly disabled from the workspace's tool set.
Source
Thrown at internal/backend/config.go:257
disableErr := mcptools.DisableSingle(ws.Cfg, config.DockerMCPName)
ws.Cfg.RemoveDockerMCPInMemory()
return fmt.Errorf("docker MCP started but failed to persist configuration: %w", errors.Join(err, disableErr))
}
publishConfigChanged(ws)
return nil
}
// DisableDockerMCP closes the Docker MCP client, removes the
// configuration, and persists the change.
func (b *Backend) DisableDockerMCP(workspaceID string) error {
ws, err := b.GetWorkspace(workspaceID)
if err != nil {
return err
}
if err := mcptools.DisableSingle(ws.Cfg, config.DockerMCPName); err != nil {
return fmt.Errorf("failed to disable docker MCP: %w", err)
}
if err := ws.Cfg.DisableDockerMCP(); err != nil {
return err
}
publishConfigChanged(ws)
return nil
}
// RefreshMCPTools refreshes the tools for a named MCP server.
func (b *Backend) RefreshMCPTools(ctx context.Context, workspaceID, name string) error {
ws, err := b.GetWorkspace(workspaceID)
if err != nil {
return err
}
mcptools.RefreshTools(ctx, ws.Cfg, name)
return nilView on GitHub (pinned to 7944b8e522)
Solutions
- Check whether Docker MCP is actually enabled before calling DisableDockerMCP (idempotency guard).
- Inspect the wrapped inner error for the concrete DisableSingle cause (timeout vs not-found).
- If the process is hung, kill the MCP process manually and retry the disable.
- If DisableSingle succeeded but DisableDockerMCP() (config disable) then fails, re-check config file permissions.
Defensive patterns
Strategy: validation
Validate before calling
if !backend.DockerMCPEnabled(wsID) {
return nil // nothing to disable; avoid failed DisableSingle
} Type guard
func IsDisableMCP_err(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to disable docker MCP")
} Try / catch
if err := backend.DisableDockerMCP(ctx, wsID); err != nil {
if strings.Contains(err.Error(), "failed to disable") {
log.Printf("docker MCP disable failed, may need manual kill: %v", err)
}
return err
} Prevention
- Make disable flows idempotent: check enabled state first.
- Add shutdown timeouts to MCP teardown so hung processes surface clearly.
- Avoid double-disable races from rollback paths (EnableDockerMCP already disables on failure).
- Persist enable/disable state atomically.
When it happens
Trigger: Calling DisableDockerMCP(workspaceID) when mcptools.DisableSingle(ws.Cfg, config.DockerMCPName) returns an error — e.g. the docker MCP tool was never enabled, the running MCP process refuses to terminate (shutdown timeout), or the workspace config is missing/corrupt.
Common situations: Double-disable (EnableDockerMCP rollback already disabled it); MCP process hung so teardown times out; concurrent modification of the workspace config between read and disable.
Related errors
- failed to start docker MCP: %w
- session ID is required for creating a new file
- mcp '%s' not found in configuration
- mcp '%s' does not use OAuth authentication
- mcp '%s' already has an authentication in progress
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/d669597aad9d8aff.
Report an issue: GitHub.