siyuan-note/siyuan · error
OAuth protected resource metadata has no authorization…
Error message
OAuth protected resource metadata has no authorization server
What it means
OAuth protected-resource discovery fetches the resource metadata (RFC 9728) and requires it to list at least one authorization server in the AuthorizationServers array, which is needed to find the AS metadata and run the flow. If the fetched metadata parses but lists no authorization servers, discovery fails with this error.
Solutions
- Fix the MCP/protected-resource server to include at least one entry in authorization_servers in its RFC 9728 metadata
- Verify you are hitting the correct protected resource metadata URL (check WWW-Authenticate challenge for the resource_metadata URL)
- Clear any cached/stale metadata and re-run discovery
- If you cannot change the server, supply the authorization server configuration manually or pre-register credentials
Example fix
// before (protected resource metadata)
{"resource":"https://mcp.example.com","authorization_servers":[]}
// after
{"resource":"https://mcp.example.com","authorization_servers":["https://auth.example.com"]} Defensive patterns
Strategy: validation
Validate before calling
// Fetch and validate the resource metadata before calling Authorize
prm, err := oauthex.GetProtectedResourceMetadata(ctx, metadataURL, resource, client)
if err == nil && len(prm.AuthorizationServers) == 0 {
return fmt.Errorf("metadata lacks authorization_servers; fix server config")
} Try / catch
if err := h.Authorize(ctx, false); err != nil {
if strings.Contains(err.Error(), "no authorization server") {
// fix the MCP server's RFC 9728 metadata before retrying
}
} Prevention
- Validate the MCP server's RFC 9728 metadata (authorization_servers non-empty) during deployment
- Read the WWW-Authenticate resource_metadata URL from the 401 challenge rather than guessing
- Invalidate cached metadata after changing the server's auth configuration
When it happens
Trigger: discoverProtectedResource successfully called oauthex.GetProtectedResourceMetadata for a candidate URL, but prm.AuthorizationServers was empty (len == 0).
Common situations: MCP server publishes incomplete RFC 9728 metadata (missing authorization_servers array); stale/cached metadata after the server's auth setup changed; wrong metadata URL candidate returning a generic/incomplete document.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- discover OAuth authorization server
- OAuth authorization server metadata not found
- OAuth protected resource metadata not found
- validate OAuth issuer
- validate OAuth protected resource
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/8d3bef3dea18a893.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/client/oauth.go:507
*oauthex.ProtectedResourceMetadata
MetadataURL string
}
func discoverProtectedResource(ctx context.Context, challenges []oauthex.Challenge, resource string, client *http.Client) (*discoveredProtectedResource, error) {
metadataURL := ""
for _, challenge := range challenges {
if strings.EqualFold(challenge.Scheme, "bearer") && challenge.Params["resource_metadata"] != "" {
metadataURL = challenge.Params["resource_metadata"]
break
}
}
for _, candidate := range protectedResourceURLs(metadataURL, resource) {
prm, err := oauthex.GetProtectedResourceMetadata(ctx, candidate.URL, candidate.Resource, client)
if err != nil {
continue
}
if len(prm.AuthorizationServers) == 0 {
return nil, fmt.Errorf("OAuth protected resource metadata has no authorization server")
}
return &discoveredProtectedResource{ProtectedResourceMetadata: prm, MetadataURL: candidate.URL}, nil
}
return nil, fmt.Errorf("OAuth protected resource metadata not found")
}
func (h *mcpOAuthHandler) validateCredentialIssuer(ctx context.Context, credential oauthCredential) (bool, error) {
var challenges []oauthex.Challenge
resource := h.server.URL
if credential.ResourceMetadataURL != "" {
challenges = []oauthex.Challenge{{Scheme: "bearer", Params: map[string]string{"resource_metadata": credential.ResourceMetadataURL}}}
resource = credential.Resource
}
prm, err := discoverProtectedResource(ctx, challenges, resource, h.client)
if err != nil {
return false, fmt.Errorf("validate OAuth protected resource: %w", err)
}
if prm.Resource != credential.Resource || len(prm.AuthorizationServers) == 0 {View on GitHub (pinned to 9f775e8a12)