Hmbown/CodeWhale · error · anyhow::Error

No external MCP candidate named '{name}'. Run /mcp import to

Error message

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

What it means

MCP import resolves the requested name (case-insensitive equality) against external MCP sources discovered from the home dir, the workspace, and the marketplace file (~/.codewhale/mcp-marketplace.json via codewhale_home). A miss bails with this message pointing to /mcp import, which lists candidates with provenance. Note this is a discovery miss - a discovered-but-hard-blocked candidate is found and then refused by a separate check.

Source

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

) -> 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 0c42157ee5)

Solutions

  1. Run /mcp import with no argument to list candidates with provenance, then copy the exact name
  2. Add or refresh the source: place it in a discovered location or update mcp-marketplace.json
  3. Check spelling - matching is case-insensitive but exact, not fuzzy
Defensive patterns

Strategy: validation

Validate before calling

// Rust - list discovered candidates and exact-match before import
let home = crate::config::effective_home_dir().unwrap_or_else(|| PathBuf::from("."));
let all = discover_external_sources(&home, workspace, &markets);
if !all.iter().any(|c| c.name.eq_ignore_ascii_case(name)) {
    return list_candidates_with_provenance(&all); // show what IS importable instead of erroring blind
}

Try / catch

match all.iter().find(|c| c.name.eq_ignore_ascii_case(name)) {
    Some(candidate) => import_candidate(candidate),
    None => show_hint("run /mcp import to list sources with provenance"),
}

Prevention

When it happens

Trigger: Importing a name that matches no discovered candidate: typo, the source file or mcp-marketplace.json absent/empty, discovery paths not covering where the source lives, or the entry renamed upstream.

Common situations: Name copied from stale docs; marketplace JSON not synced; workspace-level source moved; case differences beyond exact-ignore-case (no fuzzy or prefix matching).

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/cef4c4eba828acec. Report an issue: GitHub.