Kuberwastaken/claurst · error · anyhow::Error

MCP server ' ' has no URL configured (required for OAuth)

Error message

MCP server '{}' has no URL configured (required for OAuth)

What it means

begin_auth() requires the server config to carry a URL because OAuth discovery is done over HTTP against the server's base URL. If the matched config has no 'url' field, this error is thrown. Stdio (command-based) MCP servers cannot participate in this OAuth flow.

Solutions

  1. Add a 'url' field pointing at the server's HTTP/SSE endpoint in its config entry
  2. If the server is stdio-only, skip OAuth for it — it does not use HTTP auth
  3. Verify the JSON config field is named 'url' and sits on the server object, not a sibling
  4. Use a different auth mechanism (env-var token) for command-based servers

Example fix

// before (settings.json)
{ "mcpServers": { "linear": { "command": "npx", "args": ["-y", "mcp-linear"] } } }
// after
{ "mcpServers": { "linear": { "url": "https://mcp.linear.app/sse" } } }
Defensive patterns

Strategy: validation

Validate before calling

let cfg = hub.server_config(server_name)
    .ok_or_else(|| anyhow::anyhow!("server '{}' not configured", server_name))?;
if cfg.url.is_none() {
    anyhow::bail!("server '{}' is stdio-only; OAuth requires a url", server_name);
}

Type guard

fn has_oauth_url(cfg: &McpServerConfig) -> bool {
    cfg.url.as_deref().map_or(false, |u| u.starts_with("http"))
}

Try / catch

match hub.begin_auth(server).await {
    Ok(s) => s,
    Err(e) if e.to_string().contains("no URL configured") => {
        eprintln!("{server} has no url; use env-var auth instead");
        return Ok(());
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling McpHub::begin_auth(server_name) for a server whose config entry lacks a 'url' key — typically a stdio server defined with 'command' instead of 'url'.

Common situations: Attempting browser OAuth against a local stdio server; config migrated from another tool that used a different field name; url field accidentally deleted or mis-indented in settings.json.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10). Data as JSON: /api/errors/ab3971a0490205cb. Report an issue: GitHub.

Appendix: source

Thrown at src-rust/crates/mcp/src/lib.rs:1228

    }

    /// Initiate OAuth 2.0 + PKCE for an HTTP MCP server.
    pub async fn initiate_auth(&self, server_name: &str) -> anyhow::Result<String> {
        Ok(self.begin_auth(server_name).await?.auth_url)
    }

    /// Build a full OAuth authorization session for an HTTP/SSE MCP server.
    pub async fn begin_auth(&self, server_name: &str) -> anyhow::Result<oauth::McpAuthSession> {
        let config = self
            .server_configs
            .get(server_name)
            .ok_or_else(|| anyhow::anyhow!("Unknown MCP server: {}", server_name))?;

        let base_url = config
            .url
            .as_deref()
            .ok_or_else(|| {
                anyhow::anyhow!(
                    "MCP server '{}' has no URL configured (required for OAuth)",
                    server_name
                )
            })?;

        oauth::begin_mcp_auth(server_name, base_url).await
    }

    /// Run the browser-based OAuth flow and persist the resulting token.
    pub async fn authenticate(&self, server_name: &str) -> anyhow::Result<oauth::McpAuthResult> {
        let config = self
            .server_configs
            .get(server_name)
            .ok_or_else(|| anyhow::anyhow!("Unknown MCP server: {}", server_name))?;

        let base_url = config
            .url
            .as_deref()

View on GitHub (pinned to b0637c97ec)