{"record":{"id":"fc3d0cf5f3468519","repo":"siyuan-note/siyuan","slug":"oauth-protected-resource-metadata-not-found","errorCode":null,"errorMessage":"OAuth protected resource metadata not found","messagePattern":"OAuth protected resource metadata not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/client/oauth.go","lineNumber":511,"sourceCode":"func discoverProtectedResource(ctx context.Context, challenges []oauthex.Challenge, resource string, client *http.Client) (*discoveredProtectedResource, error) {\n\tmetadataURL := \"\"\n\tfor _, challenge := range challenges {\n\t\tif strings.EqualFold(challenge.Scheme, \"bearer\") && challenge.Params[\"resource_metadata\"] != \"\" {\n\t\t\tmetadataURL = challenge.Params[\"resource_metadata\"]\n\t\t\tbreak\n\t\t}\n\t}\n\tfor _, candidate := range protectedResourceURLs(metadataURL, resource) {\n\t\tprm, err := oauthex.GetProtectedResourceMetadata(ctx, candidate.URL, candidate.Resource, client)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif len(prm.AuthorizationServers) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"OAuth protected resource metadata has no authorization server\")\n\t\t}\n\t\treturn &discoveredProtectedResource{ProtectedResourceMetadata: prm, MetadataURL: candidate.URL}, nil\n\t}\n\treturn nil, fmt.Errorf(\"OAuth protected resource metadata not found\")\n}\n\nfunc (h *mcpOAuthHandler) validateCredentialIssuer(ctx context.Context, credential oauthCredential) (bool, error) {\n\tvar challenges []oauthex.Challenge\n\tresource := h.server.URL\n\tif credential.ResourceMetadataURL != \"\" {\n\t\tchallenges = []oauthex.Challenge{{Scheme: \"bearer\", Params: map[string]string{\"resource_metadata\": credential.ResourceMetadataURL}}}\n\t\tresource = credential.Resource\n\t}\n\tprm, err := discoverProtectedResource(ctx, challenges, resource, h.client)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"validate OAuth protected resource: %w\", err)\n\t}\n\tif prm.Resource != credential.Resource || len(prm.AuthorizationServers) == 0 {\n\t\treturn false, nil\n\t}\n\tasm, err := auth.GetAuthServerMetadata(ctx, prm.AuthorizationServers[0], h.client)\n\tif err != nil {","sourceCodeStart":493,"sourceCodeEnd":529,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/mcp/client/oauth.go#L493-L529","documentation":"Returned at oauth.go:510-511 when every candidate URL produced by protectedResourceURLs fails to yield a valid PRM document. Candidates include the resource_metadata hint from the WWW-Authenticate challenge and the well-known paths /.well-known/oauth-protected-resource and /.well-known/oauth-protected-resource/<path>; all of them errored in GetProtectedResourceMetadata.","triggerScenarios":"Initial discovery (Authorize) or issuer validation where none of the candidate URLs return a fetchable, parseable PRM document. Each candidate's error is silently continued past via the `continue` at oauth.go:503-505.","commonSituations":"Resource server does not implement RFC 9728 (no well-known endpoint); resource URL incorrect or redirected; 404 on all candidates; network blocked to the resource server; malformed JSON in the document causing parse errors.","solutions":["Confirm the resource server implements RFC 9728 and serves /.well-known/oauth-protected-resource at the resource origin.","Check the WWW-Authenticate challenge's resource_metadata hint (if present) and verify that URL is reachable.","Verify network connectivity / TLS / proxy to the resource server URL.","Ensure the resource URL in the MCP server config (h.server.URL) is correct and stable (no trailing path or query that shifts the well-known location)."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// discoverProtectedResource iterates candidate URLs; transient failures yield error 336.\nprm, err := discoverProtectedResource(ctx, challenges, resource, client)\nif err != nil {\n    // Retry once on transient network failures before surfacing as a hard config error.\n    if isTransientNetworkErr(err) { prm, err = discoverProtectedResource(ctx, challenges, resource, client) }\n    if err != nil { return err } // genuine RFC 9728 gap or persistent network issue\n}","preventionTips":["Ensure the resource server implements RFC 9728 well-known discovery.","Verify the WWW-Authenticate resource_metadata hint and the resource URL are reachable.","Validate resource server TLS and proxy configuration before first authorization."],"tags":["oauth","mcp","resource-metadata","rfc9728","discovery","network","well-known"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}