{"record":{"id":"5522dd4e17c90fa8","repo":"zed-industries/zed","slug":"could-not-fetch-protected-resource-metadata-for","errorCode":null,"errorMessage":"Could not fetch Protected Resource Metadata for {}","messagePattern":"Could not fetch Protected Resource Metadata for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/context_server/src/oauth.rs","lineNumber":797,"sourceCode":"                    );\n                }\n                return Ok(ProtectedResourceMetadata {\n                    resource: response.resource.unwrap_or_else(|| server_url.clone()),\n                    authorization_servers: response.authorization_servers,\n                    scopes_supported: response.scopes_supported,\n                });\n            }\n            Err(err) => {\n                log::debug!(\n                    \"Failed to fetch Protected Resource Metadata from {}: {}\",\n                    url,\n                    err\n                );\n            }\n        }\n    }\n\n    bail!(\n        \"Could not fetch Protected Resource Metadata for {}\",\n        server_url\n    )\n}\n\n/// Fetch Authorization Server Metadata, trying RFC 8414 and OIDC Discovery\n/// endpoints in the priority order specified by the MCP spec.\npub async fn fetch_auth_server_metadata(\n    http_client: &Arc<dyn HttpClient>,\n    issuer: &Url,\n) -> Result<AuthServerMetadata> {\n    let candidate_urls = auth_server_metadata_urls(issuer);\n\n    for url in &candidate_urls {\n        match fetch_json::<AuthServerMetadataResponse>(http_client, url).await {\n            Ok(response) => {\n                let reported_issuer = response.issuer.unwrap_or_else(|| issuer.clone());\n","sourceCodeStart":779,"sourceCodeEnd":815,"githubUrl":"https://github.com/zed-industries/zed/blob/f4178619acd0d47ea1f76a2025c42962c6d6638c/crates/context_server/src/oauth.rs#L779-L815","documentation":"Every candidate URL for the Protected Resource Metadata document failed, so fetch_protected_resource_metadata() gives up. Candidates are the resource_metadata hint from the WWW-Authenticate header (if present) plus the RFC 9724 well-known locations derived from the server URL; each failure is logged at debug level ('Failed to fetch Protected Resource Metadata from ...') before the final bail mentions only the server_url. The individual causes are hidden unless debug logging is enabled, so the underlying reasons are transport errors, non-2xx statuses, or JSON parse failures from fetch_json.","triggerScenarios":"An MCP server returns 401 with a Bearer challenge, Zed then GETs each candidate /.well-known/oauth-protected-resource URL (and the resource_metadata hint), and every request errors — DNS failure, connection refused, TLS error, 404, non-JSON body, or a fetch_json parse/size error.","commonSituations":"Server implements 401 discovery but never deploys the well-known metadata file (404 on all candidates); metadata hosted on a different origin with CORS or a typo'd URL in resource_metadata; local dev server stopped between the 401 and the follow-up fetch; proxy blocking the .well-known path; document served as HTML error page.","solutions":["Serve a valid RFC 9724 JSON document at /.well-known/oauth-protected-resource (and the port-specific variant for non-443 ports) with Content-Type application/json","Set resource_metadata in the WWW-Authenticate Bearer challenge to the exact URL where the document lives so the hint candidate succeeds","Enable debug logging to see the per-URL failure reasons, then curl each candidate URL from the client machine to verify reachability and JSON validity","If the server cannot support OAuth discovery, switch the MCP connection to a transport/auth mode that does not require it (e.g. header-based auth)"],"exampleFix":"# before: well-known file missing (all candidates 404)\n$ curl -i https://mcp.example.com/.well-known/oauth-protected-resource\nHTTP/1.1 404 Not Found\n\n# after: serve the document\n$ curl -i https://mcp.example.com/.well-known/oauth-protected-resource\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n{\"resource\":\"https://mcp.example.com\",\"authorization_servers\":[\"https://auth.example.com\"]}","handlingStrategy":"try-catch","validationCode":"// client-side preflight: probe all candidate PRM URLs before starting the flow\nasync fn prm_reachable(http: &Arc<dyn HttpClient>, urls: &[Url]) -> Option<Url> {\n    for url in urls {\n        if fetch_json::<serde_json::Value>(http, url).await.is_ok() {\n            return Some(url.clone());\n        }\n    }\n    None\n}","typeGuard":null,"tryCatchPattern":"match fetch_protected_resource_metadata(&client, &server_url, &challenge).await {\n    Ok(meta) => Ok(meta),\n    Err(err) if err.to_string().contains(\"Could not fetch Protected Resource Metadata\") => {\n        // enable debug logs to see per-URL causes; distinguish 404 (not implemented) from network errors\n        log::debug!(\"PRM candidates failed for {server_url}\");\n        if is_transient_network(&err) { retry_with_backoff().await } else { Err(err) }\n    }\n    Err(err) => Err(err),\n}","preventionTips":["Serve the RFC 9724 document at every well-known location candidates are derived from, including the port-specific variant","Set resource_metadata in the Bearer challenge so the highest-priority candidate is the correct one","Log at debug level during integration so per-URL failures are visible when this bail appears"],"tags":["oauth","mcp","discovery","network","rfc-9724"],"backgroundTag":"oauth-discovery-endpoint-unreachable","analyzedSha":"f4178619acd0d47ea1f76a2025c42962c6d6638c","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}