siyuan-note/siyuan · error
OAuth protected resource metadata not found
Error message
OAuth protected resource metadata not found
What it means
discoverProtectedResource fetches the MCP server's OAuth protected resource metadata (RFC 9728) from well-known URLs (or a WWW-Authenticate resource_metadata URL) to learn which authorization servers protect the resource. All candidate metadata URLs either failed to fetch or returned invalid metadata, so discovery produced nothing. The client cannot proceed with the OAuth flow without knowing an authorization server.
Solutions
- Verify the MCP server URL is correct and the server actually implements RFC 9728 protected resource metadata at /.well-known/oauth-protected-resource (and the path-suffixed variant).
- Check that the server responds with a WWW-Authenticate: Bearer ... resource_metadata="..." header on 401s, or configure the resource metadata URL explicitly in the credential.
- Fetch the well-known URL manually (curl) to confirm it returns JSON, not a redirect to a login page or an error page from a proxy.
- Confirm network/proxy/TLS access to the metadata endpoint; transient fetch failures are swallowed, so the underlying cause is invisible in this message.
- If the server requires no OAuth at all, do not configure it as an OAuth-protected server.
Example fix
// before: resource URL points at app root that does not publish metadata
server: {"url": "https://mcp.example.com/app"}
// after: point at the MCP endpoint whose server publishes RFC 9728 metadata
server: {"url": "https://mcp.example.com/mcp"} Defensive patterns
Strategy: validation
Validate before calling
resp, err := http.Get(serverURL + "/.well-known/oauth-protected-resource")
if err != nil || resp.StatusCode != 200 {
// server does not publish protected resource metadata; fix URL or OAuth config first
} Prevention
- Verify the MCP server implements RFC 9728 metadata before enabling OAuth for it
- curl the /.well-known/oauth-protected-resource endpoint during setup
- Confirm proxies do not block or rewrite /.well-known paths
- Test with the exact server URL the client will use, including path prefix
When it happens
Trigger: Called from Authorize (starting a new OAuth flow) or validateCredentialIssuer (re-validating a stored credential). Thrown when: the server returns no WWW-Authenticate bearer challenge with resource_metadata, none of /.well-known/oauth-protected-resource/... endpoints return HTTP 200 with parseable metadata, or every GetProtectedResourceMetadata call errors and is silently skipped by the continue.
Common situations: The MCP server is not an OAuth resource server at all (no metadata published); a reverse proxy strips or blocks /.well-known paths; the server URL is wrong or points at a different port; the metadata endpoint returns HTML (login page) or 404; network/TLS failures against the metadata endpoint.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- discover OAuth authorization server
- validate OAuth issuer
- validate OAuth protected resource
- OAuth authorization server metadata not found
- OAuth protected resource metadata has no authorization…
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/fc3d0cf5f3468519.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/client/oauth.go:511
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 {
return false, nil
}
asm, err := auth.GetAuthServerMetadata(ctx, prm.AuthorizationServers[0], h.client)
if err != nil {View on GitHub (pinned to 9f775e8a12)