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 nil

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check whether Docker MCP is actually enabled before calling DisableDockerMCP (idempotency guard).
  2. Inspect the wrapped inner error for the concrete DisableSingle cause (timeout vs not-found).
  3. If the process is hung, kill the MCP process manually and retry the disable.
  4. 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

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


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/d669597aad9d8aff. Report an issue: GitHub.