Hmbown/CodeWhale · error · anyhow::Error

Source contains an unsupported server name

Error message

Source contains an unsupported server name

What it means

For each server name extracted from the source, checked_source enforces mcp_name_is_command_safe(&name) and a 128-byte length limit, since imported names are used as command-safe identifiers. A name with unsafe characters (path separators, shell metacharacters) or over 128 bytes aborts the whole discovery.

Solutions

  1. Rename the offending server key in the source file to a short, command-safe identifier (letters, digits, hyphens/underscores) and retry
  2. Split names over 128 bytes into a shorter key and keep the long value in a description field
  3. Remove the offending entry from the source if it is not needed

Example fix

// before
{ "mcpServers": { "../etc/passwd": { "command": "npx" } } }
// after
{ "mcpServers": { "etc-passwd-mirror": { "command": "npx" } } }
Defensive patterns

Strategy: validation

Validate before calling

fn names_are_command_safe(path: &std::path::Path) -> bool {
    std::fs::read_to_string(path).ok()
        .and_then(|s| serde_json::from_str::<serde_json::Value>(&s).ok())
        .and_then(|v| v.get("mcpServers").or_else(|| v.get("servers")).cloned())
        .and_then(|m| m.as_object().cloned())
        .map(|m| m.keys().all(|k| !k.is_empty() && k.len() <= 128
            && k.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '.'))))
        .unwrap_or(false)
}

Type guard

fn is_safe_name(name: &str) -> bool {
    name.len() <= 128
        && name.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '.'))
}

Try / catch

match discover(&path) {
    Err(e) if e.to_string().contains("unsupported server name") => {
        eprintln!("a server key fails the command-safe name rule or exceeds 128 bytes; rename it");
    }
    r => r?,
}

Prevention

When it happens

Trigger: discover / discover_from_json_file where any key in the source's server map fails the command-safe name check (contains characters like '/', '\\', quotes, control chars) or exceeds 128 bytes (e.g. long URLs used as names, non-ASCII names).

Common situations: A source config whose keys were pasted URLs or file paths; names generated from long package specifiers; unicode names from another tool; a name containing spaces or slashes intended as a display name.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/b7e7b2683e932f3e. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/mcp/external_import.rs:146

) -> anyhow::Result<Vec<ImportCandidate>> {
    super::validate_mcp_config_path(path)?;
    let Some(raw) = super::read_mcp_config_file(path)? else {
        return Ok(Vec::new());
    };
    let hash = hex_sha256(raw.as_bytes());
    let value: Value = serde_json::from_str(&raw)
        .map_err(|_| anyhow::anyhow!("Source is not valid JSON; contents omitted"))?;
    anyhow::ensure!(
        value
            .get("mcpServers")
            .or_else(|| value.get("servers"))
            .is_some_and(Value::is_object)
            || value.is_array(),
        "Source has no supported MCP server map"
    );
    let mut out = Vec::new();
    for (name, mut config) in extract_servers_map(&value) {
        anyhow::ensure!(
            super::mcp_name_is_command_safe(&name) && name.len() <= 128,
            "Source contains an unsupported server name"
        );
        if value.is_array()
            && let Some(map) = config.as_object_mut()
        {
            map.remove("name");
        }
        let fields = config
            .as_object()
            .ok_or_else(|| anyhow::anyhow!("Invalid MCP entry; contents omitted"))?;
        const ALLOWED: &[&str] = &[
            "command",
            "args",
            "env",
            "cwd",
            "url",
            "allow_private_network",

View on GitHub (pinned to 73e0f67d83)