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

  1. 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).
  2. 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.
  3. 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.
  4. Confirm network/proxy/TLS access to the metadata endpoint; transient fetch failures are swallowed, so the underlying cause is invisible in this message.
  5. 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

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


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)