Hmbown/CodeWhale · error · anyhow::Error

MCP entry must have one target

Error message

MCP entry must have one target

What it means

An imported MCP server must specify exactly one target: either a local `command` or a remote `url`, never both and never neither. The invariant `command.is_some() != url.is_some()` is enforced with XOR; violating it rejects the entry.

Solutions

  1. Delete either the `command` or the `url` key so exactly one target remains
  2. If the server is remote, remove command/args; if local, remove url/transport
  3. Split genuinely dual-mode servers into two distinct named entries

Example fix

// before
{"mcpServers":{"api":{"command":"npx","url":"https://mcp.example.com"}}}
// after
{"mcpServers":{"api":{"url":"https://mcp.example.com"}}}
Defensive patterns

Strategy: validation

Validate before calling

function oneTargetOk(e) { return ("command" in e) !== ("url" in e); }

Try / catch

catch, then check whether the offending entry has 0 or 2 targets and fix accordingly

Prevention

When it happens

Trigger: An entry has both `command` and `url` set, or an entry has neither (only optional fields like transport, env, or headers).

Common situations: Merging two config files by hand so both keys survive; converting a remote entry to local by adding `command` without removing `url`; an empty stub entry with only metadata fields.

Related errors


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

Appendix: source

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

            "scopes",
            "oauth",
            "oauth_resource",
        ];
        anyhow::ensure!(
            fields.keys().all(|key| ALLOWED.contains(&key.as_str())),
            "Source contains unsupported MCP fields; review it at its source"
        );
        if let Some(oauth) = fields.get("oauth").filter(|v| !v.is_null()) {
            anyhow::ensure!(
                oauth
                    .as_object()
                    .is_some_and(|map| map.keys().all(|key| key == "client_id")),
                "Source contains unsupported OAuth fields"
            );
        }
        let server: McpServerConfig = serde_json::from_value(config)
            .map_err(|_| anyhow::anyhow!("Invalid MCP entry; contents omitted"))?;
        anyhow::ensure!(
            server.command.is_some() != server.url.is_some(),
            "MCP entry must have one target"
        );
        if let Some(command) = &server.command {
            anyhow::ensure!(
                !command.trim().is_empty() && !command.chars().any(char::is_control),
                "Invalid MCP command"
            );
        }
        if let Some(url) = &server.url {
            let parsed =
                reqwest::Url::parse(url).map_err(|_| anyhow::anyhow!("Invalid MCP URL"))?;
            anyhow::ensure!(
                matches!(parsed.scheme(), "http" | "https")
                    && parsed.host_str().is_some()
                    && parsed.username().is_empty()
                    && parsed.password().is_none(),
                "Unsupported MCP URL"

View on GitHub (pinned to 73e0f67d83)