Hmbown/CodeWhale · error

Failed to parse MCP config {}; file contents were omitted

Error message

Failed to parse MCP config {}; file contents were omitted

What it means

load_config reads the MCP config file (user-level or workspace .codewhale/mcp.json) and deserializes it with serde into McpConfig. If the bytes are not valid JSON or do not match the McpServerConfig shape, parsing fails; the error deliberately omits file contents so secrets placed in env values are never echoed into logs.

Source

Thrown at crates/tui/src/mcp.rs:3553

    pub resources: Vec<McpDiscoveredItem>,
    pub prompts: Vec<McpDiscoveredItem>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct McpManagerSnapshot {
    pub config_path: std::path::PathBuf,
    pub config_exists: bool,
    pub reload_required: bool,
    pub servers: Vec<McpServerSnapshot>,
}

pub fn load_config(path: &Path) -> Result<McpConfig> {
    validate_mcp_config_path(path)?;
    let Some(contents) = read_mcp_config_file(path)? else {
        return Ok(McpConfig::default());
    };
    serde_json::from_str(&contents).map_err(|_| {
        anyhow::anyhow!(
            "Failed to parse MCP config {}; file contents were omitted",
            codewhale_config::quote_os_path(path)
        )
    })
}

fn read_mcp_config_file(path: &Path) -> Result<Option<String>> {
    let metadata = match fs::symlink_metadata(path) {
        Ok(metadata) => metadata,
        Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None),
        Err(err) => {
            return Err(err)
                .with_context(|| format!("Failed to inspect MCP config {}", path.display()));
        }
    };
    let file_type = metadata.file_type();
    if file_type.is_symlink() || !file_type.is_file() {
        anyhow::bail!("MCP config path must be a regular file: {}", path.display());

View on GitHub (pinned to 8880682c63)

Solutions

  1. Validate the file with a JSON linter (jq . mcp.json) and fix reported syntax errors
  2. Check each server entry uses the expected types: command (string), args (array of strings), env (map string to string), enabled/disabled (bool)
  3. Remove comments and trailing commas - the file must be strict JSON
  4. Restore from a backup, or delete the file to fall back to McpConfig::default() and re-add servers

Example fix

// before (mcp.json)
{ "servers": { "a": { "command": "npx", "args": ["-y", "s"], } } }

// after
{ "servers": { "a": { "command": "npx", "args": ["-y", "s"] } } }
Defensive patterns

Strategy: validation

Validate before calling

// Dry-run the file through the same shape before codewhale loads it:
let contents = std::fs::read_to_string(&mcp_json_path)?;
serde_json::from_str::<codewhale_tui::mcp::McpConfig>(&contents)
    .context("mcp.json does not match the expected schema")?;

Type guard

fn is_valid_mcp_config_json(raw: &str) -> bool {
    serde_json::from_str::<codewhale_tui::mcp::McpConfig>(raw).is_ok()
}

Try / catch

match load_config(&path) {
    Err(e) if e.to_string().contains("Failed to parse MCP config") => {
        eprintln!("mcp.json is invalid JSON; run: jq . {}", path.display());
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling load_config (directly or via add/remove/set_server_enabled, snapshot, or manager startup) on a file with a JSON syntax error, trailing comma, comment, or wrong field types (e.g. args as a string instead of an array of strings).

Common situations: Hand-editing mcp.json and leaving a trailing comma; pasting snippets that use JSON5 features; merge-conflict markers left in the file; an editor saving a BOM-prefixed file.

Understand the failure class

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/ecaedb6f02a8adb9. Report an issue: GitHub.