windmill-labs/windmill · error
MCP server does not publish OAuth authorization metadata
Error message
MCP server does not publish OAuth authorization metadata
What it means
Per OAuth 2.0 authorization-server metadata discovery (RFC 8414), the MCP server refuses to fall back to well-known legacy endpoints that the operator never published. When `resolve_metadata` reports `LegacyEndpointFallback` — meaning no authorization metadata was actually configured — discovery bails so clients don't authenticate against endpoints the server never designated.
Source
Thrown at backend/windmill-mcp/src/lib.rs:62
pub use rmcp::transport::auth::{AuthorizationManager, AuthorizationMetadata};
const DEFAULT_OAUTH_HTTP_TIMEOUT: Duration = Duration::from_secs(30);
/// Discover the MCP server's OAuth metadata, refusing endpoints the server
/// never advertised.
///
/// When a server publishes no metadata at all, rmcp's `resolve_metadata`
/// falls back to inventing `/authorize`, `/token` and `/register` on the
/// server's own host. Dynamic client registration and the token exchange
/// both carry secrets, so they must only ever reach endpoints the server
/// actually published — a guessed path would send them somewhere the
/// operator never designated as an authorization server.
pub async fn discover_authorization_metadata(
manager: &AuthorizationManager,
) -> anyhow::Result<AuthorizationMetadata> {
let resolution = manager.resolve_metadata().await?;
if resolution.source == AuthorizationMetadataSource::LegacyEndpointFallback {
anyhow::bail!("MCP server does not publish OAuth authorization metadata");
}
Ok(resolution.metadata)
}
pub fn no_redirect_http_client() -> Result<reqwest::Client, reqwest::Error> {
no_redirect_http_client_with_timeout(DEFAULT_OAUTH_HTTP_TIMEOUT)
}
pub(crate) fn no_redirect_http_client_with_timeout(
timeout: Duration,
) -> Result<reqwest::Client, reqwest::Error> {
reqwest::Client::builder()
.timeout(timeout)
.redirect(reqwest::redirect::Policy::none())
.build()
}
/// Like [`no_redirect_http_client`], but pins DNS to the address the SSRFView on GitHub (pinned to e474e8803c)
Solutions
- Configure OAuth authorization server metadata for the MCP server (issuer, authorization/token endpoints) in instance settings
- Verify the AuthorizationManager is initialized with published metadata before clients perform discovery
- Use a non-OAuth auth method (token) if the deployment intentionally has no OAuth metadata
Defensive patterns
Strategy: type-guard
Validate before calling
// before discovery, check that metadata is configured
let resolution = manager.resolve_metadata().await?;
if resolution.source == AuthorizationMetadataSource::LegacyEndpointFallback {
// OAuth discovery will fail; surface config instructions instead
} Type guard
fn has_published_metadata(source: &AuthorizationMetadataSource) -> bool {
*source != AuthorizationMetadataSource::LegacyEndpointFallback
} Try / catch
match discover_authorization_metadata(&manager).await {
Err(e) if e.to_string().contains("does not publish OAuth") =>
eprintln!("configure OAuth authorization server metadata first"),
Err(e) => return Err(e),
Ok(meta) => meta,
} Prevention
- Configure OAuth authorization server metadata before advertising OAuth to clients
- Check resolution.source before trusting fallback endpoints
- Fall back to static token auth when OAuth metadata is absent
When it happens
Trigger: Calling `discover_authorization_metadata` when the AuthorizationManager has no configured OAuth authorization server metadata and would fall back to a legacy well-known endpoint; exercised by test `discovery_refuses_endpoints_the_server_never_published`.
Common situations: MCP OAuth not yet configured by the instance operator; misconfigured or missing authorization server metadata in instance settings; clients attempting OAuth discovery against a server that only supports legacy flows.
Related errors
- The tool list for ${path} changed while it was loading. Try
- A connection already exists at ${resourcePath}. Pick another
- Variable at path ${path} already exists. Delete it or pick a
- ${what}: ${supabaseErrorMessage(body) || res.statusText}
- Failed to complete GitHub app installation
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/f8a8846954dd12a5.
Report an issue: GitHub.