charmbracelet/crush · error

failed to create OAuth handler for mcp %q: %w

Error message

failed to create OAuth handler for mcp %q: %w

What it means

After resolving URL and credentials, createTransport constructs the OAuth handler via mcpoauth.NewHandler (handling PRM discovery, token storage, registration). Any failure from that constructor is wrapped as 'failed to create OAuth handler for mcp %q'. The URL is trailing-slash-normalized beforehand for PRM discovery compatibility.

Source

Thrown at internal/agent/tools/mcp/init.go:1109

				clientID, err := resolver.ResolveValue(m.OAuthClientID)
				if err != nil {
					return nil, nil, fmt.Errorf("oauth_client_id: %w", err)
				}
				clientSecret, err := resolver.ResolveValue(m.OAuthClientSecret)
				if err != nil {
					return nil, nil, fmt.Errorf("oauth_client_secret: %w", err)
				}
				preregistered = &oauth.OAuthClient{
					ClientID:     strings.TrimSpace(clientID),
					ClientSecret: strings.TrimSpace(clientSecret),
				}
			}

			// Normalize trailing slash for PRM discovery compatibility.
			normalizedURL := strings.TrimSuffix(url, "/")
			oauthHandler, oauthErr := mcpoauth.NewHandler(name, normalizedURL, m.OAuthToken, preregistered, tokenSaver, mcpoauth.IsInteractive(ctx), m.OAuthCallbackPort)
			if oauthErr != nil {
				return nil, nil, fmt.Errorf("failed to create OAuth handler for mcp %q: %w", name, oauthErr)
			}
			authURLs.Set(name, oauthHandler)
			return &mcp.StreamableClientTransport{
				Endpoint:     url,
				OAuthHandler: oauthHandler,
			}, oauthHandler, nil
		}

		headers, err := m.ResolvedHeaders(resolver)
		if err != nil {
			return nil, nil, err
		}
		client := &http.Client{
			Transport: &headerRoundTripper{
				headers: headers,
			},
		}
		return &mcp.StreamableClientTransport{

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Read the wrapped cause for the underlying NewHandler failure
  2. Verify the MCP server's /.well-known/oauth-protected-resource metadata is reachable
  3. Check the OAuth callback port is free (or unset to use the default) and writable token cache dir
  4. Clear cached OAuth state/token files for this server and retry the auth flow

Example fix

// before: port fixed and already in use
mcp api type http url 'https://api.example.com/mcp' oauth oauth_callback_port 8080
// after: let the handler pick a free port
mcp api type http url 'https://api.example.com/mcp' oauth
Defensive patterns

Strategy: fallback

Validate before calling

resp, err := http.Get(strings.TrimSuffix(serverURL, "/") + "/.well-known/oauth-protected-resource")
if err != nil || resp.StatusCode != 200 {
    return errors.New("OAuth metadata discovery unavailable; check server URL and connectivity")
}

Try / catch

if _, err := mcpoauth.NewHandler(name, url, token, nil, saver, interactive, port); err != nil {
    // clear cached token state and retry once, else surface the wrapped error
}

Prevention

When it happens

Trigger: mcpoauth.NewHandler returning an error: invalid OAuth token cache file, malformed server metadata/PRM discovery configuration, invalid callback port, or internal client registration failures.

Common situations: Unwritable token persistence location (HOME not set in CI); OAuth callback port already in use or out of allowed range; MCP server's well-known OAuth metadata unreachable or malformed; stale cached client registration after server-side changes.

Related errors


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