charmbracelet/crush · error

failed to disable docker MCP: status code %d

Error message

failed to disable docker MCP: status code %d

What it means

Returned by Client.DisableDockerMCP when the POST succeeded at the transport level but the server responded with a non-200 status. Only 200 is accepted as success. Typical codes: 404 for a missing workspace or route, 401/403 for auth, 500 if the server errors while disabling the Docker MCP integration (e.g. MCP server already removed).

Source

Thrown at internal/client/config.go:284

	if err != nil {
		return fmt.Errorf("failed to enable docker MCP: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return fmt.Errorf("failed to enable docker MCP: status code %d", rsp.StatusCode)
	}
	return nil
}

// DisableDockerMCP disables the Docker MCP server on the workspace.
func (c *Client) DisableDockerMCP(ctx context.Context, id string) error {
	rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/mcp/docker/disable", id), nil, nil, nil)
	if err != nil {
		return fmt.Errorf("failed to disable docker MCP: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return fmt.Errorf("failed to disable docker MCP: status code %d", rsp.StatusCode)
	}
	return nil
}

// RefreshMCPTools refreshes tools for a named MCP server.
func (c *Client) RefreshMCPTools(ctx context.Context, id, name string) error {
	rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/mcp/refresh-tools", id), nil, jsonBody(struct {
		Name string `json:"name"`
	}{Name: name}), http.Header{"Content-Type": []string{"application/json"}})
	if err != nil {
		return fmt.Errorf("failed to refresh MCP tools: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return fmt.Errorf("failed to refresh MCP tools: status code %d", rsp.StatusCode)
	}
	return nil
}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Parse the status code from the message and branch: 404 may safely mean 'already disabled' — treat idempotently.
  2. For 401/403, refresh credentials and retry.
  3. For 500, inspect server logs for the docker MCP disable handler error.
  4. Ensure the workspace ID is valid and the server supports the disable route.
  5. Guard against concurrent duplicate disable calls for the same workspace.

Example fix

// before
err := client.DisableDockerMCP(ctx, wsID) // status code 404
if err != nil { return err }
// after
err := client.DisableDockerMCP(ctx, wsID)
if err != nil && strings.Contains(err.Error(), "status code 404") {
    return nil // already disabled / workspace gone: treat as idempotent success
}
if err != nil { return err }
Defensive patterns

Strategy: fallback

Type guard

func isNon200(err error) (code int, ok bool) {
    m := regexp.MustCompile(`status code (\d+)`).FindStringSubmatch(err.Error())
    if len(m) < 2 { return 0, false }
    code, err2 := strconv.Atoi(m[1])
    return code, err2 == nil
}

Try / catch

err := client.DisableDockerMCP(ctx, wsID)
if err != nil {
    if code, ok := isNon200(err); ok && code == 404 {
        // already disabled or workspace gone — treat as success (idempotent teardown)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling DisableDockerMCP on a nonexistent or already-deleted workspace (404), with insufficient permissions (403), against a server that predates the docker MCP endpoints (404/405), or when the server-side disable handler fails (500).

Common situations: Double-disable from concurrent cleanup logic hitting a removed MCP entry; server upgrade removed the route; expired credentials; workspace suspended so MCP mutation is rejected.

Related errors


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