Hmbown/CodeWhale · error
OAuth login is only supported for URL-based MCP servers
Error message
OAuth login is only supported for URL-based MCP servers
What it means
perform_oauth_login_for_server_inner requires server.url to be set because OAuth needs an HTTP issuer to discover authorization/token endpoints. A stdio/command-based McpServerConfig has no URL, so the function bails immediately (oauth.rs:475) before any discovery request is made. OAuth is only implemented for URL-based (remote) MCP servers.
Source
Thrown at crates/tui/src/mcp/oauth.rs:475
where
F: std::future::Future<Output = Result<T>>,
{
tokio::select! {
biased;
_ = cancellation_token.cancelled() => bail!("OAuth login was cancelled"),
result = future => result,
}
}
async fn perform_oauth_login_for_server_inner(
name: &str,
server: &McpServerConfig,
explicit_scopes: Option<Vec<String>>,
callback_port: Option<u16>,
callback_url: Option<&str>,
) -> Result<()> {
let Some(url) = server.url.as_deref() else {
bail!("OAuth login is only supported for URL-based MCP servers");
};
if server_has_manual_authorization(server) {
bail!("MCP server '{name}' already has bearer/static Authorization configured");
}
let discovery = if explicit_scopes.is_none() && server.scopes.is_empty() {
oauth_login_support(server).await?
} else {
None
};
let resolved_scopes = resolve_oauth_scopes(
explicit_scopes,
server.scopes.clone(),
discovery.and_then(|discovery| discovery.scopes_supported),
);
match perform_oauth_login(
name,View on GitHub (pinned to 0c42157ee5)
Solutions
- Set the server's url to its HTTP(S) endpoint and remove the command-based configuration, then retry login
- If the server is genuinely a local process, use its documented static auth (bearer_token_env_var or an env-provided header) instead of OAuth
- Check whether the server offers an HTTP/Streamable-HTTP mode and point the config at that URL
Example fix
// before (config TOML) [mcp.servers.my-server] command = "npx" args = ["-y", "some-mcp-server"] // after [mcp.servers.my-server] url = "https://mcp.example.com/mcp"
Defensive patterns
Strategy: validation
Validate before calling
if server.url.is_none() {
tracing::info!(target: "mcp", "skipping OAuth login for stdio server {name}");
return Ok(());
} Type guard
fn is_url_based_server(server: &McpServerConfig) -> bool {
server.url.is_some()
} Prevention
- Only expose the OAuth login action in the UI for servers with a url field
- Lint MCP config: warn when OAuth is attempted on command-based entries
- Document per-server which auth modes apply: stdio → env/static, url → OAuth
When it happens
Trigger: Calling perform_oauth_login_for_server (or the TUI MCP login command) on a server entry configured with a command/args (stdio transport) and no url field; the `let Some(url) = server.url.as_deref() else` branch is taken on the first line of the inner function.
Common situations: Config copied from a local stdio server template (npx/node/python launchers) and the user tries OAuth anyway; a server entry where the url key was typo'd or omitted so it silently fell back to stdio; assuming all MCP servers support OAuth.
Related errors
- OAuth logout is only supported for URL-based MCP servers
- MCP server '{server_name}' has no command configured
- MCP server '{name}' already has bearer/static Authorization
- invalid MCP OAuth callback port 0
- app-server auth token cannot be empty
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/d1c5971f13d00fbd.
Report an issue: GitHub.