charmbracelet/crush · error

failed to get MCP prompt: %w

Error message

failed to get MCP prompt: %w

What it means

GetMCPPrompt POSTs to /workspaces/{id}/mcp/get-prompt to render a prompt from a named MCP server with arguments. This error wraps transport failures from c.post — the request never got a response, so no status was checked.

Source

Thrown at internal/client/config.go:348

	if rsp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("failed to list MCP prompts: status code %d", rsp.StatusCode)
	}
	var prompts []proto.MCPPrompt
	if err := json.NewDecoder(rsp.Body).Decode(&prompts); err != nil {
		return nil, fmt.Errorf("failed to decode MCP prompts: %w", err)
	}
	return prompts, nil
}

// GetMCPPrompt retrieves a prompt from a named MCP server.
func (c *Client) GetMCPPrompt(ctx context.Context, id, clientID, promptID string, args map[string]string) (string, error) {
	rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/mcp/get-prompt", id), nil, jsonBody(struct {
		ClientID string            `json:"client_id"`
		PromptID string            `json:"prompt_id"`
		Args     map[string]string `json:"args"`
	}{ClientID: clientID, PromptID: promptID, Args: args}), http.Header{"Content-Type": []string{"application/json"}})
	if err != nil {
		return "", fmt.Errorf("failed to get MCP prompt: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("failed to get MCP prompt: status code %d", rsp.StatusCode)
	}
	var result struct {
		Prompt string `json:"prompt"`
	}
	if err := json.NewDecoder(rsp.Body).Decode(&result); err != nil {
		return "", fmt.Errorf("failed to decode MCP prompt response: %w", err)
	}
	return result.Prompt, nil
}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check connectivity to the Coder server.
  2. Validate workspace ID, clientID, and promptID before calling.
  3. Inspect the wrapped error for the root cause.
  4. Retry with a longer context timeout for slow prompt rendering.

Example fix

// before
prompt, err := client.GetMCPPrompt(ctx, id, clientID, promptID, args)
// after
prompt, err := client.GetMCPPrompt(ctx, id, clientID, promptID, args)
if err != nil {
    return "", fmt.Errorf("get prompt %s (server %s): %w", promptID, clientID, err)
}
Defensive patterns

Strategy: retry

Validate before calling

func validateGetPromptInput(workspaceID, clientID, promptID string, args map[string]string) error {
    if workspaceID == "" || clientID == "" || promptID == "" {
        return errors.New("workspace ID, client ID, and prompt ID are required")
    }
    return nil
}

Try / catch

ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
prompt, err := client.GetMCPPrompt(ctx, id, clientID, promptID, args)
if err != nil && isTransientNetworkError(err) {
    prompt, err = client.GetMCPPrompt(ctx, id, clientID, promptID, args)
}
if err != nil {
    return "", fmt.Errorf("get prompt %q: %w", promptID, err)
}

Prevention

When it happens

Trigger: c.post errors: unreachable host, DNS/TLS failure, malformed workspace ID in the URL, cancelled context, or timeout while the MCP server rendered the prompt.

Common situations: Coder daemon down; network/VPN issues; oversized args payload failing to serialize; context cancelled by an upstream deadline.

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


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