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

  1. Set the server's url to its HTTP(S) endpoint and remove the command-based configuration, then retry login
  2. 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
  3. 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

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


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/d1c5971f13d00fbd. Report an issue: GitHub.