{"record":{"id":"b66c232ba1916032","repo":"can1357/oh-my-pi","slug":"could-not-discover-oauth-endpoints-from-server-res","errorCode":null,"errorMessage":"Could not discover OAuth endpoints from server response.","messagePattern":"Could not discover OAuth endpoints from server response\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/modes/controllers/mcp-command-controller.ts","lineNumber":1264,"sourceCode":"\t\t\t? new Error(`${connectionError?.message ?? \"HTTP 401\"}\\n${authChallenge.wwwAuthenticate.join(\"\\n\")}`)\n\t\t\t: connectionError!;\n\t\tconst authResult = analyzeAuthError(authError, \"url\" in config ? config.url : undefined);\n\t\tlet oauth = authResult.authType === \"oauth\" ? (authResult.oauth ?? null) : null;\n\n\t\tif (!oauth && (config.type === \"http\" || config.type === \"sse\") && config.url) {\n\t\t\toauth = await discoverOAuthEndpoints(config.url, authResult.authServerUrl, authResult.resourceMetadataUrl, {\n\t\t\t\tprotectedScopes: authResult.scopes,\n\t\t\t});\n\t\t}\n\t\tif (oauth && !oauth.scopes && authResult.resourceMetadataUrl) {\n\t\t\t// JSON-error-body path skips `discoverOAuthEndpoints`; fetch the\n\t\t\t// advertised protected-resource metadata for the required scopes.\n\t\t\tconst scopes = await fetchResourceMetadataScopes(authResult.resourceMetadataUrl);\n\t\t\tif (scopes) oauth = { ...oauth, scopes };\n\t\t}\n\n\t\tif (!oauth) {\n\t\t\tthrow new Error(\"Could not discover OAuth endpoints from server response.\");\n\t\t}\n\n\t\treturn oauth;\n\t}\n\n\tasync #waitForServerConnectionWithAnimation(\n\t\tname: string,\n\t\toptions?: { suppressDisconnectedWarning?: boolean },\n\t): Promise<\"connected\" | \"connecting\" | \"disconnected\"> {\n\t\tif (!this.ctx.mcpManager) return \"disconnected\";\n\n\t\tconst block = new McpConnectingBlock(name);\n\t\tthis.ctx.present(block);\n\n\t\ttry {\n\t\t\ttry {\n\t\t\t\tawait withTimeout(this.ctx.mcpManager.waitForConnection(name), 10_000, \"Connection still pending\");\n\t\t\t} catch {","sourceCodeStart":1246,"sourceCodeEnd":1282,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/modes/controllers/mcp-command-controller.ts#L1246-L1282","documentation":"Thrown at the end of #resolveOAuthEndpointsFromServer when every path to obtain OAuth endpoints failed: the auth-error analyzer did not classify the failure as OAuth (or returned no oauth details), and the direct discoverOAuthEndpoints() probe against the server URL also returned null. The controller could not find an authorization/token endpoint to run the OAuth flow against.","triggerScenarios":"Running /mcp auth or /mcp reauth on an http/sse server that returned a 401/connection error but publishes no RFC 9728 protected-resource metadata and no RFC 8414 authorization-server metadata at or behind its URL, and whose error body carries no OAuth hints.","commonSituations":"A server that uses a non-OAuth auth scheme (API key header, basic auth, mTLS) while returning 401; a misconfigured base URL hitting a plain web server (404/HTML) with no well-known files; an API gateway stripping .well-known routes; servers behind proxies that only forward the MCP route.","solutions":["Check that <server-url>/.well-known/oauth-protected-resource and .well-known/oauth-authorization-server return valid JSON metadata; fix server/proxy routing if they 404.","If the server does not use OAuth at all, configure a static auth block (e.g. { \"type\": \"bearer\", \"token\": \"...\" } or header auth) in the server config instead of /mcp auth.","Verify the configured URL points at the MCP endpoint, not the dashboard root or an unrelated path.","If the auth server lives on a different domain, ensure the protected-resource metadata (or WWW-Authenticate header) names it via resource_metadata so discovery can follow it."],"exampleFix":"// before: OAuth auth against a non-OAuth server\n{ \"type\": \"http\", \"url\": \"https://mcp.example.com/mcp\" } // /mcp auth fails: no discovery\n// after: static credentials\n{\n  \"type\": \"http\",\n  \"url\": \"https://mcp.example.com/mcp\",\n  \"auth\": { \"type\": \"bearer\", \"token\": \"<api-token>\" }\n}","handlingStrategy":"validation","validationCode":"const origin = new URL(serverUrl).origin;\nfor (const p of [\"/.well-known/oauth-protected-resource\", \"/.well-known/oauth-authorization-server\"]) {\n  const r = await fetch(origin + p);\n  if (r.ok) { console.log(`Discovery metadata found at ${p}`); return; }\n}\nthrow new Error(\"No OAuth discovery metadata; use static auth instead of /mcp auth\");","typeGuard":"function isDiscoveryFailure(err: unknown): err is Error {\n  return err instanceof Error && err.message === \"Could not discover OAuth endpoints from server response.\";\n}","tryCatchPattern":"try {\n  await mcpAuth(name);\n} catch (err) {\n  if (isDiscoveryFailure(err)) {\n    // server is not OAuth-discoverable: fall back to a static bearer/header auth block\n  } else throw err;\n}","preventionTips":["Verify the server exposes RFC 8414/9728 well-known endpoints; fix proxy/gateway routing that strips them.","If the server uses API keys or basic auth, configure a static auth block instead of running /mcp auth.","Point the config at the MCP endpoint path, not the site root or dashboard URL.","If the auth server is on another domain, ensure WWW-Authenticate includes resource_metadata so discovery can follow it."],"tags":["oauth","mcp","discovery","http"],"backgroundTag":"oauth-discovery-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}