charmbracelet/crush · error

failed to read MCP resource: status code %d

Error message

failed to read MCP resource: status code %d

What it means

ReadMCPResource requires an HTTP 200 from /workspaces/{id}/mcp/read-resource. Any other status produces 'failed to read MCP resource: status code %d'. The response body (which may hold server-side error details) is discarded.

Source

Thrown at internal/client/config.go:315

	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()
	if rsp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("failed to read MCP resource: status code %d", rsp.StatusCode)
	}
	var contents []MCPResourceContents
	if err := json.NewDecoder(rsp.Body).Decode(&contents); err != nil {
		return nil, fmt.Errorf("failed to decode MCP resource: %w", err)
	}
	return contents, nil
}

func (c *Client) ListMCPPrompts(ctx context.Context, id string) ([]proto.MCPPrompt, error) {
	rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/mcp/prompts", id), nil, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to list MCP prompts: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("failed to list MCP prompts: status code %d", rsp.StatusCode)
	}
	var prompts []proto.MCPPrompt

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Match the status code to action: 404 → verify MCP server name and workspace ID; 401 → re-authenticate.
  2. Verify the resource URI exists on that MCP server (list resources first if possible).
  3. Check server logs for 5xx root causes.
  4. Ensure the workspace is running before reading resources.

Example fix

// before
contents, err := client.ReadMCPResource(ctx, id, name, uri)
// after
contents, err := client.ReadMCPResource(ctx, id, name, uri)
if err != nil && strings.Contains(err.Error(), "status code 404") {
    return nil, fmt.Errorf("resource %q not found on MCP server %q (check server name and URI)", uri, name)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check: ensure the MCP server is configured and workspace is up
servers, err := client.WorkspaceAgentMCPStatus(ctx, workspaceID)
// or simply verify the resource URI scheme matches the server's expectations before calling

Try / catch

contents, err := client.ReadMCPResource(ctx, id, name, uri)
if err != nil {
    var code int
    if n, _ := fmt.Sscanf(err.Error(), "failed to read MCP resource: status code %d", &code); n == 1 {
        if code == 401 || code == 403 {
            // re-authenticate then retry once
        } else if code == 404 {
            return nil, fmt.Errorf("resource %q not found on server %q", uri, name)
        }
    }
    return nil, err
}

Prevention

When it happens

Trigger: Server replies 401/403 (auth), 404 (workspace ID or MCP server name not found), 400 (malformed URI), or 500 (MCP server failed to serve the resource) instead of 200.

Common situations: Resource URI typo (wrong scheme/path for that MCP server); MCP server name mismatch with config; expired credentials; workspace stopped.

Related errors


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