{"record":{"id":"d1c5971f13d00fbd","repo":"Hmbown/CodeWhale","slug":"oauth-login-is-only-supported-for-url-based-mcp-se","errorCode":null,"errorMessage":"OAuth login is only supported for URL-based MCP servers","messagePattern":"OAuth login is only supported for URL-based MCP servers","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/oauth.rs","lineNumber":1112,"sourceCode":"{\n    tokio::select! {\n        biased;\n        _ = cancellation_token.cancelled() => bail!(\"OAuth login was cancelled\"),\n        result = future => result,\n    }\n}\n\n/// Shared gate + scope resolution for `/mcp login` and the model-driven\n/// authenticate tool: URL-based servers only, no manual Authorization config,\n/// scopes from explicit argument, config, or discovery (in that order).\nasync fn resolve_oauth_login(\n    name: &str,\n    server: &McpServerConfig,\n    explicit_scopes: Option<Vec<String>>,\n    network_policy: Option<&NetworkPolicyDecider>,\n) -> Result<(String, ResolvedMcpOAuthScopes)> {\n    let Some(url) = server.url.as_deref() else {\n        bail!(\"OAuth login is only supported for URL-based MCP servers\");\n    };\n    if server_has_manual_authorization(server) {\n        bail!(\"MCP server '{name}' already has bearer/static Authorization configured\");\n    }\n\n    let discovery = if explicit_scopes.is_none() && server.scopes.is_empty() {\n        oauth_login_support(server, network_policy).await?\n    } else {\n        None\n    };\n    let resolved_scopes = resolve_oauth_scopes(\n        explicit_scopes,\n        server.scopes.clone(),\n        discovery.and_then(|discovery| discovery.scopes_supported),\n    );\n    Ok((url.to_string(), resolved_scopes))\n}\n","sourceCodeStart":1094,"sourceCodeEnd":1130,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/mcp/oauth.rs#L1094-L1130","documentation":"OAuth login resolves the server's authorization endpoints from its URL; servers configured only with a command (stdio transport) have no URL to run a web OAuth flow against, so resolve_oauth_login rejects them up front. OAuth in this library is defined for HTTP/SSE (URL-based) MCP servers only.","triggerScenarios":"Calling perform_oauth_login_for_server (via resolve_oauth_login) for an McpServerConfig where server.url is None — i.e. a stdio/command-based server such as {\"command\": \"npx\", \"args\": [\"-y\", \"some-mcp\"]}.","commonSituations":"Running /mcp login against a locally launched stdio MCP server; a config where the url field was omitted or mistyped so the server fell back to command mode; users assuming all MCP servers support OAuth.","solutions":["Add a valid `url` to the server's McpServerConfig if it is actually an HTTP MCP server","If the server is genuinely stdio-based, authenticate via environment variables or headers in the command config instead of OAuth","Check the config for a typo that dropped the url field","Use the server's documented auth mechanism (API key env var, static header) for command-based servers"],"exampleFix":"// before\n{ \"my-server\": { \"command\": \"npx\", \"args\": [\"-y\", \"mcp-remote\"] } }\n// after\n{ \"my-server\": { \"url\": \"https://mcp.example.com/mcp\" } }","handlingStrategy":"validation","validationCode":"fn can_oauth_login(server: &McpServerConfig) -> bool {\n    server.url.as_deref().map(|u| u.starts_with(\"http\")).unwrap_or(false)\n}","typeGuard":"fn url_based_server(server: &McpServerConfig) -> Option<&str> {\n    server.url.as_deref()\n}","tryCatchPattern":"match server.url.as_deref() {\n    None => eprintln!(\"stdio server: use env vars/headers for auth, not OAuth\"),\n    Some(_) => perform_oauth_login_for_server(&server).await?,\n}","preventionTips":["Only advertise OAuth login for servers with an http(s) url in config","For stdio/command servers, wire auth through environment variables","Validate McpServerConfig shape before presenting login options in UI"],"tags":["oauth","mcp","config","validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}