{"record":{"id":"b7e7b2683e932f3e","repo":"Hmbown/CodeWhale","slug":"source-contains-an-unsupported-server-name","errorCode":null,"errorMessage":"Source contains an unsupported server name","messagePattern":"Source contains an unsupported server name","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/external_import.rs","lineNumber":146,"sourceCode":") -> anyhow::Result<Vec<ImportCandidate>> {\n    super::validate_mcp_config_path(path)?;\n    let Some(raw) = super::read_mcp_config_file(path)? else {\n        return Ok(Vec::new());\n    };\n    let hash = hex_sha256(raw.as_bytes());\n    let value: Value = serde_json::from_str(&raw)\n        .map_err(|_| anyhow::anyhow!(\"Source is not valid JSON; contents omitted\"))?;\n    anyhow::ensure!(\n        value\n            .get(\"mcpServers\")\n            .or_else(|| value.get(\"servers\"))\n            .is_some_and(Value::is_object)\n            || value.is_array(),\n        \"Source has no supported MCP server map\"\n    );\n    let mut out = Vec::new();\n    for (name, mut config) in extract_servers_map(&value) {\n        anyhow::ensure!(\n            super::mcp_name_is_command_safe(&name) && name.len() <= 128,\n            \"Source contains an unsupported server name\"\n        );\n        if value.is_array()\n            && let Some(map) = config.as_object_mut()\n        {\n            map.remove(\"name\");\n        }\n        let fields = config\n            .as_object()\n            .ok_or_else(|| anyhow::anyhow!(\"Invalid MCP entry; contents omitted\"))?;\n        const ALLOWED: &[&str] = &[\n            \"command\",\n            \"args\",\n            \"env\",\n            \"cwd\",\n            \"url\",\n            \"allow_private_network\",","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/mcp/external_import.rs#L128-L164","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Rename the offending server key in the source file to a short, command-safe identifier (letters, digits, hyphens/underscores) and retry","Split names over 128 bytes into a shorter key and keep the long value in a description field","Remove the offending entry from the source if it is not needed"],"exampleFix":"// before\n{ \"mcpServers\": { \"../etc/passwd\": { \"command\": \"npx\" } } }\n// after\n{ \"mcpServers\": { \"etc-passwd-mirror\": { \"command\": \"npx\" } } }","handlingStrategy":"validation","validationCode":"fn names_are_command_safe(path: &std::path::Path) -> bool {\n    std::fs::read_to_string(path).ok()\n        .and_then(|s| serde_json::from_str::<serde_json::Value>(&s).ok())\n        .and_then(|v| v.get(\"mcpServers\").or_else(|| v.get(\"servers\")).cloned())\n        .and_then(|m| m.as_object().cloned())\n        .map(|m| m.keys().all(|k| !k.is_empty() && k.len() <= 128\n            && k.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '.'))))\n        .unwrap_or(false)\n}","typeGuard":"fn is_safe_name(name: &str) -> bool {\n    name.len() <= 128\n        && name.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '.'))\n}","tryCatchPattern":"match discover(&path) {\n    Err(e) if e.to_string().contains(\"unsupported server name\") => {\n        eprintln!(\"a server key fails the command-safe name rule or exceeds 128 bytes; rename it\");\n    }\n    r => r?,\n}","preventionTips":["Name servers with short alphanumeric/hyphen/underscore identifiers only","Never use paths, URLs, or shell metacharacters as server names","Keep names under 128 bytes — prefer ASCII to avoid multi-byte length blowups","Sanitize or rename keys when converting exports from other tools"],"tags":["mcp","import","validation"],"backgroundTag":"invalid-identifier-format","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T10:30:35.592Z"}