googleapis/mcp-toolbox · error

failed to parse introspection URL: %w

Error message

failed to parse introspection URL: %w

What it means

For GET-style introspection, validateOpaqueToken parses the resolved introspection URL with url.Parse before appending the token as a query parameter. A parse failure means the URL string is not a valid absolute or relative URL, so no request can be built.

Source

Thrown at internal/auth/generic/generic.go:366

	introspectionURL := a.introspectionURL
	if introspectionURL == "" {
		introspectionURL, err = url.JoinPath(a.AuthorizationServer, "introspect")
		if err != nil {
			return nil, fmt.Errorf("failed to construct introspection URL: %w", err)
		}
	}

	paramName := a.IntrospectionParamName
	if paramName == "" {
		paramName = "token"
	}

	var req *http.Request
	if a.IntrospectionMethod == "GET" {
		u, err := url.Parse(introspectionURL)
		if err != nil {
			return nil, fmt.Errorf("failed to parse introspection URL: %w", err)
		}
		q := u.Query()
		q.Set(paramName, tokenStr)
		u.RawQuery = q.Encode()
		req, err = http.NewRequestWithContext(ctx, "GET", u.String(), nil)
		if err != nil {
			return nil, fmt.Errorf("failed to create introspection request: %w", err)
		}
	} else {
		data := url.Values{}
		data.Set(paramName, tokenStr)
		req, err = http.NewRequestWithContext(ctx, "POST", introspectionURL, strings.NewReader(data.Encode()))
		if err != nil {
			return nil, fmt.Errorf("failed to create introspection request: %w", err)
		}
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}
	req.Header.Set("Accept", "application/json")

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Print and inspect the resolved introspection URL; remove spaces/control characters and percent-encode special chars.
  2. Fix an invalid percent-encoding sequence (e.g. a lone '%' should be '%25').
  3. Set the exact introspection URL in config rather than deriving it from authorizationServer.

Example fix

// before
introspectionUrl: "https://idp.example.com/introspect %"
// after
introspectionUrl: "https://idp.example.com/introspect"
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(cfg.IntrospectionURL)
if err != nil {
    return fmt.Errorf("introspectionUrl %q is not a valid URL: %w", cfg.IntrospectionURL, err)
}
if u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("introspectionUrl must be absolute")
}

Type guard

func isParseableURL(s string) bool {
    _, err := url.Parse(s)
    return err == nil && strings.TrimSpace(s) == s
}

Try / catch

claims, err := svc.ValidateMCPAuth(ctx, header)
if err != nil {
    if strings.Contains(err.Error(), "failed to parse introspection URL") {
        // fix introspectionUrl / authorizationServer config; this is a config error
        return claims, fmt.Errorf("config error: %w", err)
    }
    return claims, err
}

Prevention

When it happens

Trigger: Config has IntrospectionMethod == "GET" and url.Parse(introspectionURL) fails — typically because the configured introspection URL or derived AuthorizationServer value contains invalid characters (spaces, unmatched '%', control chars).

Common situations: Introspection URL pasted with trailing spaces or newline, unencoded special characters, or a bad env-var substitution producing something like 'https://idp/api/ introspect'.

Understand the failure class

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/ff3f0be6cd20194a. Report an issue: GitHub.