Hmbown/CodeWhale · error

No external MCP candidate named

Error message

No external MCP candidate named '{name}'. Run /mcp import to list sources with provenance.

What it means

Thrown by mcp_import_apply when the named external MCP candidate cannot be found among the sources discovered by discover_external_sources (home dir, workspace, and market paths). Import works only on candidates the discovery pass enumerated, so an unknown name is rejected with a pointer to /mcp import for a provenance listing. Case-insensitive match is used but the name must still exist.

Solutions

  1. Run /mcp import to list candidate names with provenance and copy the exact name
  2. Check that the source file (e.g. claude desktop config, marketplace JSON) is in a scanned path
  3. Re-run import discovery after adding or fixing market paths in config
Defensive patterns

Strategy: validation

Validate before calling

let candidates = discover_external_sources(&home, &workspace, &markets);
if !candidates.iter().any(|c| c.name.eq_ignore_ascii_case(name)) { return Err(anyhow!("no candidate '{name}'")); }

Prevention

When it happens

Trigger: Calling the apply/import UI action with a name never produced by discovery; discovery ran before a new market file was added; name casing differs beyond ASCII case-fold.

Common situations: User typed a server name from memory instead of the /mcp import listing; external source file moved or renamed; marketplace path not configured so discovery never saw the candidate.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/cef4c4eba828acec. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tui/ui/provider_routes.rs:967

) -> anyhow::Result<String> {
    use crate::mcp::external_import::{
        ImportDecision, apply_approved, discover_external_sources, load_consent_store,
        merge_approved_into_config, record_decisions, save_consent_store,
    };
    use std::collections::HashMap;
    use std::time::{SystemTime, UNIX_EPOCH};

    let home = crate::config::effective_home_dir().unwrap_or_else(|| PathBuf::from("."));
    let market_path = codewhale_config::codewhale_home()
        .ok()
        .map(|h| h.join("mcp-marketplace.json"));
    let markets: Vec<PathBuf> = market_path.into_iter().collect();
    let all = discover_external_sources(&home, workspace, &markets);
    let candidate = all
        .iter()
        .find(|c| c.name.eq_ignore_ascii_case(name))
        .ok_or_else(|| {
            anyhow::anyhow!(
                "No external MCP candidate named '{name}'. Run /mcp import to list sources with provenance."
            )
        })?;

    if approve && candidate.hard_blocked {
        anyhow::bail!(
            "Refusing to import '{}': {} (enabled=false is a hard block)",
            candidate.name,
            candidate.block_reason.as_deref().unwrap_or("hard blocked")
        );
    }

    let mut decisions = HashMap::new();
    decisions.insert(
        candidate.name.clone(),
        if approve {
            ImportDecision::Approve
        } else {

View on GitHub (pinned to 433685b202)