charmbracelet/crush · error
failed to get MCP auth URL: %w
Error message
failed to get MCP auth URL: %w
What it means
MCPAuthURL performs GET /workspaces/{id}/mcp/auth-url?name=... via the client's transport helper c.get. If the HTTP request itself fails — DNS failure, connection refused, TLS error, context cancellation — the underlying error is wrapped with this message. This happens before any status-code or body checks, so it always indicates a transport-level problem.
Source
Thrown at internal/client/proto.go:355
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to get MCP pending auth: status code %d", rsp.StatusCode)
}
var pending []proto.MCPPendingAuthServer
if err := json.NewDecoder(rsp.Body).Decode(&pending); err != nil {
return nil, fmt.Errorf("failed to decode MCP pending auth: %w", err)
}
return pending, nil
}
// MCPAuthURL retrieves the current OAuth authorization URL for a named MCP
// server, if a flow is in progress.
func (c *Client) MCPAuthURL(ctx context.Context, id, name string) (string, error) {
q := url.Values{"name": []string{name}}
rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/mcp/auth-url", id), q, nil)
if err != nil {
return "", fmt.Errorf("failed to get MCP auth URL: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return "", fmt.Errorf("failed to get MCP auth URL: status code %d", rsp.StatusCode)
}
var resp proto.MCPAuthResponse
if err := json.NewDecoder(rsp.Body).Decode(&resp); err != nil {
return "", fmt.Errorf("failed to decode MCP auth URL: %w", err)
}
return resp.AuthURL, nil
}
// MCPAuthenticate runs the OAuth flow for a named MCP server. The server's
// local browser is suppressed; the caller is responsible for surfacing the
// authorization URL (via polling [Client.MCPPendingAuth] / state events)
// and opening it on the user's machine. The call blocks until the flow
// completes, fails, or ctx is cancelled.
func (c *Client) MCPAuthenticate(ctx context.Context, id, name string) error {View on GitHub (pinned to 7944b8e522)
Solutions
- Print the wrapped error chain (%w) — it names the root cause (dial tcp ...: connection refused, no such host, context canceled).
- Verify the client's server URL/host and that the server is running and reachable (curl the endpoint directly).
- Check network path: DNS, VPN, proxy, and firewall rules for the host/port being dialed.
- If the cause is context deadline exceeded, increase the timeout or check why the server is slow; never retry on context.Canceled without a new context.
Example fix
// before
ctx := context.Background()
url, err := client.MCPAuthURL(ctx, id, "github") // no deadline; hangs then fails on some networks
// after
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
url, err := client.MCPAuthURL(ctx, id, "github")
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
// retry or surface "server unreachable"
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
// Preflight connectivity before calling MCPAuthURL.
if err := ctx.Err(); err != nil {
return fmt.Errorf("context already done: %w", err)
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, serverBaseURL, nil)
if err != nil {
return fmt.Errorf("bad server URL: %w", err)
}
if _, err := http.DefaultClient.Do(req); err != nil {
return fmt.Errorf("server unreachable: %w", err) Type guard
func isTransportError(err error) bool {
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
return true
}
var ne net.Error
return errors.As(err, &ne) || errors.Is(err, syscall.ECONNREFUSED)
} Try / catch
url, err := client.MCPAuthURL(ctx, id, name)
if err != nil {
switch {
case errors.Is(err, context.DeadlineExceeded):
return retryWithBackoff(ctx, func() (string, error) { return client.MCPAuthURL(ctx, id, name) })
case errors.Is(err, context.Canceled):
return "", err // do not retry user cancellation
default:
return "", fmt.Errorf("transport failure reaching auth-url endpoint: %w", err)
}
} Prevention
- Always pass a context with a sane timeout; never use context.Background() unadorned.
- Validate the server base URL and port at client construction time.
- Check server reachability (health endpoint) before OAuth flows that need multiple round-trips.
- Unwrap the error chain with errors.Is to distinguish canceled vs refused vs DNS failures before retrying.
When it happens
Trigger: Calling MCPAuthURL(ctx, id, name) when the server host is unreachable (connection refused/timeout), DNS does not resolve, TLS handshake fails, the request context is canceled/expired, or c.get fails to build the request.
Common situations: Server not running or wrong base URL/port configured, offline or behind a VPN that blocks the host, firewall dropping the connection, or the caller cancels the context (user aborts, deadline exceeded) mid-request.
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
- server health check failed: %s
- failed to set provider API key: %w
- failed to list workspaces: %w
- failed to create workspace: %w
- failed to get MCP pending auth: status code %d
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/295433d4241b370c.
Report an issue: GitHub.