{"record":{"id":"9b812a192b3e7eb4","repo":"odysseus-dev/odysseus","slug":"server-has-no-oauth-config","errorCode":null,"errorMessage":"Server has no OAuth config","messagePattern":"Server has no OAuth config","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"routes/mcp/mcp_routes.py","lineNumber":438,"sourceCode":"            db.commit()\n\n            return {\"id\": server_id, \"disabled_count\": len(disabled)}\n        finally:\n            db.close()\n\n    # ── OAuth flow for Google MCP servers ──────────────────────────\n\n    @router.get(\"/oauth/authorize/{server_id}\")\n    def oauth_authorize(server_id: str, request: Request):\n        \"\"\"Show OAuth authorization page with Google sign-in link.\"\"\"\n        require_admin(request)\n        db = SessionLocal()\n        try:\n            srv = db.query(McpServer).filter(McpServer.id == server_id).first()\n            if not srv:\n                raise HTTPException(404, \"Server not found\")\n            if not srv.oauth_config:\n                raise HTTPException(400, \"Server has no OAuth config\")\n\n            oauth_cfg = _sanitize_mcp_oauth_config(json.loads(srv.oauth_config))\n            keys_file = oauth_cfg.get(\"keys_file\", \"\")\n            if not keys_file or not os.path.exists(keys_file):\n                raise HTTPException(400, \"OAuth keys file not found\")\n\n            with open(keys_file, encoding=\"utf-8\") as f:\n                keys_data = json.load(f)\n            keys = keys_data.get(\"installed\") or keys_data.get(\"web\")\n            if not keys:\n                raise HTTPException(400, \"Invalid OAuth keys file format\")\n\n            client_id = keys[\"client_id\"]\n            scopes = oauth_cfg.get(\"scopes\", [])\n\n            # For Desktop App creds, default to localhost — the user will\n            # paste the resulting URL back if they're on a different device.\n            redirect_uri = _mcp_oauth_redirect_uri()","sourceCodeStart":420,"sourceCodeEnd":456,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/mcp/mcp_routes.py#L420-L456","documentation":"On GET /oauth/authorize/{server_id}, the server row exists but srv.oauth_config is empty/null, so there is no OAuth configuration to drive the flow and the route returns 400. The field is populated at registration time from the oauth_file/oauth_config form parameters, so this means the server was registered without OAuth credentials.","triggerScenarios":"Registering a server with transport sse/http and no oauth_file/oauth_config, then hitting authorize; registering with an oauth_file whose path failed confinement (error 641) so the config never persisted; a stdio server that never carries OAuth.","commonSituations":"Assuming every listed server supports Google OAuth; OAuth config lost during registration due to path validation; server created before the OAuth feature existed.","solutions":["Re-register or update the server with an oauth_file/oauth_config under the mcp_oauth base dir.","Confirm registration succeeded with OAuth fields by inspecting the server row (GET /servers) before calling authorize.","Only call authorize for servers that genuinely need Google auth."],"exampleFix":"# before: registered without oauth\nrequests.post(f\"{base}/servers\", data={\"transport\": \"http\", \"url\": u, \"name\": \"gdrive\"})\n\n# after\nrequests.post(f\"{base}/servers\", data={\"transport\": \"http\", \"url\": u, \"name\": \"gdrive\",\n    \"oauth_file\": \"client_secret.json\"})","handlingStrategy":"validation","validationCode":"def server_has_oauth(srv_row: dict) -> bool:\n    return bool(srv_row.get(\"oauth_config\"))","typeGuard":null,"tryCatchPattern":"On 400 'Server has no OAuth config', re-register the server with oauth_file instead of retrying authorize.","preventionTips":["Only show OAuth authorize buttons for servers registered with OAuth credentials.","Verify registration persisted oauth_config before starting the flow."],"tags":["mcp","oauth","config","validation"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}