charmbracelet/crush · error
failed to refresh MCP tools: %w
Error message
failed to refresh MCP tools: %w
What it means
RefreshMCPTools sends a POST to /workspaces/{id}/mcp/refresh-tools to re-fetch the tool list of a named MCP server. The client wraps any transport-level error from c.post with 'failed to refresh MCP tools: %w'. It is thrown before any status code is checked, so it means the HTTP request itself could not be completed.
Source
Thrown at internal/client/config.go:295
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
}
// ReadMCPResource reads a resource from a named MCP server.
func (c *Client) ReadMCPResource(ctx context.Context, id, name, uri string) ([]MCPResourceContents, error) {
rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/mcp/read-resource", id), nil, jsonBody(struct {
Name string `json:"name"`
URI string `json:"uri"`
}{Name: name, URI: uri}), http.Header{"Content-Type": []string{"application/json"}})
if err != nil {
return nil, fmt.Errorf("failed to read MCP resource: %w", err)
}
defer rsp.Body.Close()View on GitHub (pinned to 7944b8e522)
Solutions
- Verify the Coder URL and network connectivity (curl the server's / or health endpoint).
- Confirm the workspace ID exists via the API (GET /workspaces) before calling RefreshMCPTools.
- Inspect the wrapped error (%w) for the root cause — connection refused vs DNS vs TLS.
- Retry with a fresh context if the context was cancelled or timed out.
Example fix
// before
if err := client.RefreshMCPTools(ctx, workspaceID, "my-mcp"); err != nil {
log.Fatal(err)
}
// after
if err := client.RefreshMCPTools(ctx, workspaceID, "my-mcp"); err != nil {
var statusErr interface{ HTTPStatus() int }
if errors.As(err, &wrapped) && strings.Contains(err.Error(), "connection refused") {
log.Printf("coder server unreachable, retrying later: %v", err)
return
}
return fmt.Errorf("refresh MCP tools for %q: %w", "my-mcp", err)
} Defensive patterns
Strategy: retry
Validate before calling
func validateRefreshInput(workspaceID, mcpName string) error {
if workspaceID == "" || mcpName == "" {
return errors.New("workspace ID and MCP name are required")
}
return nil
} Try / catch
err := client.RefreshMCPTools(ctx, id, name)
if err != nil {
if strings.Contains(err.Error(), "connection refused") || errors.Is(ctx.Err(), context.DeadlineExceeded) {
// transient: retry with backoff
}
return fmt.Errorf("refresh MCP tools %q: %w", name, err)
} Prevention
- Always wrap the call and log the wrapped root cause, not just the outer message.
- Health-check the Coder server before batching tool refreshes.
- Use a context with a sensible timeout instead of context.Background().
- Verify workspace ID and MCP server name against a prior list call.
When it happens
Trigger: c.post returns an error: DNS failure, connection refused, TLS error, invalid workspace ID producing a malformed URL, cancelled/expired context, or failure building the request body.
Common situations: Coder server not running or wrong URL configured; network outage or VPN down; workspace ID typo; client-side proxy misconfiguration; the underlying MCP server crashed and the daemon endpoint is unreachable.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- failed to enable docker MCP: %w
- failed to disable docker MCP: %w
- failed to read MCP resource: %w
- failed to list MCP prompts: %w
- failed to get MCP prompt: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/1a0e8867e12c21a1.
Report an issue: GitHub.