{"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/9f775e8a12daef8255556097396f9b2739078892/kernel/mcp/client/oauth.go#L493-L529","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: resource URL points at app root that does not publish metadata\nserver: {\"url\": \"https://mcp.example.com/app\"}\n// after: point at the MCP endpoint whose server publishes RFC 9728 metadata\nserver: {\"url\": \"https://mcp.example.com/mcp\"}","handlingStrategy":"validation","validationCode":"resp, err := http.Get(serverURL + \"/.well-known/oauth-protected-resource\")\nif err != nil || resp.StatusCode != 200 {\n    // server does not publish protected resource metadata; fix URL or OAuth config first\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["oauth","mcp","discovery","network"],"backgroundTag":"resource-not-found","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}