{"record":{"id":"5c12500fd4090395","repo":"siyuan-note/siyuan","slug":"server-returned-s","errorCode":null,"errorMessage":"server returned %s","messagePattern":"server returned (.+?)","errorType":"http","errorClass":null,"httpStatus":403,"severity":"error","filePath":"kernel/mcp/client/oauth.go","lineNumber":196,"sourceCode":"\t\tRefreshToken: credential.RefreshToken,\n\t\tExpiry:       credential.Expiry,\n\t}\n}\n\nfunc (h *mcpOAuthHandler) Authorize(ctx context.Context, req *http.Request, resp *http.Response) (retErr error) {\n\tdefer resp.Body.Close()\n\tdefer io.Copy(io.Discard, io.LimitReader(resp.Body, 1<<20))\n\n\tchallenges, err := oauthex.ParseWWWAuthenticate(resp.Header.Values(\"WWW-Authenticate\"))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parse OAuth challenge: %w\", err)\n\t}\n\tif !hasBearerChallenge(challenges) {\n\t\treturn fmt.Errorf(\"server returned %s without an OAuth Bearer challenge\", resp.Status)\n\t}\n\tchallengeError := bearerChallengeParam(challenges, \"error\")\n\tif resp.StatusCode == http.StatusForbidden && challengeError != \"insufficient_scope\" {\n\t\treturn fmt.Errorf(\"server returned %s\", resp.Status)\n\t}\n\tinteractive := h.interactive.Load()\n\tif interactive {\n\t\tdefer func() {\n\t\t\tif retErr != nil && !errors.Is(retErr, context.Canceled) {\n\t\t\t\tsetMCPRuntimeStateForContext(ctx, h.server.ID, \"authorization_required\", 0, retErr.Error(), \"\")\n\t\t\t}\n\t\t}()\n\t}\n\n\tprm, err := discoverProtectedResource(ctx, challenges, req.URL.String(), h.client)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tasm, err := auth.GetAuthServerMetadata(ctx, prm.AuthorizationServers[0], h.client)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"discover OAuth authorization server: %w\", err)","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/mcp/client/oauth.go#L178-L214","documentation":"Authorize was invoked after the MCP server rejected a request, but the WWW-Authenticate response carried no OAuth Bearer challenge (or none could be parsed as one). The library only knows how to start an OAuth flow when the server advertises a Bearer challenge describing the resource/auth servers; anything else (Basic, Digest, none, or a plain error page) is opaque. This guards against guessing auth schemes the client cannot perform.","triggerScenarios":"Calling MCPClient.Authorize when resp.StatusCode is 401/403 but the response lacks a WWW-Authenticate header with scheme Bearer, e.g. a reverse proxy returns 401 with Basic challenge, or the endpoint returns an HTML error page with no challenge at all.","commonSituations":"MCP server URL points at a gateway/proxy that strips or rewrites WWW-Authenticate; wrong URL hits a non-OAuth endpoint; server is not actually an OAuth-protected resource; API gateway uses API keys instead of OAuth.","solutions":["Verify the MCP server URL points at the actual OAuth-protected MCP endpoint, not a proxy or UI route","Check with curl -i that the server returns WWW-Authenticate: Bearer ... on 401; fix server/proxy config to emit it","If a proxy strips the header, configure it to pass through WWW-Authenticate","If the server does not use OAuth at all, supply credentials via a supported non-OAuth auth method instead of calling Authorize"],"exampleFix":"// before: pointing at a proxy that swallows challenges\nserver := mcp.NewClientHandler(\"https://gw.example.com/mcp\")\n// after: point directly at the OAuth-protected resource\nserver := mcp.NewClientHandler(\"https://mcp.example.com/mcp\")","handlingStrategy":"validation","validationCode":"resp, _ := http.Get(serverURL)\nch, err := oauthex.ParseWWWAuthenticate(resp.Header.Values(\"WWW-Authenticate\"))\nif err != nil || !hasBearerChallenge(ch) {\n    return errors.New(\"endpoint does not advertise OAuth Bearer challenge\")\n}","typeGuard":null,"tryCatchPattern":"err := h.Authorize(ctx, req, resp)\nif err != nil && strings.Contains(err.Error(), \"without an OAuth Bearer challenge\") {\n    surfaceToUser(\"Server did not advertise OAuth; check URL/proxy WWW-Authenticate passthrough\")\n}","preventionTips":["Always curl -i the MCP endpoint to confirm a Bearer WWW-Authenticate challenge on 401 before wiring OAuth","Configure reverse proxies to pass through WWW-Authenticate headers","Keep the MCP server URL pointing at the OAuth-protected resource, not a gateway UI"],"tags":["oauth","mcp","http","network"],"backgroundTag":"http-error-response","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"}