warpdotdev/warp · error · anyhow::Error

MCP server '{name}' config must be a JSON object

Error message

MCP server '{name}' config must be a JSON object

What it means

Thrown by mcp_specs_from_mcp_servers when an entry in the agent config file's `mcp_servers` map has a value that is not a JSON object. Each server's value must be a map (containing optionally `warp_id`, or `command`/`url` fields); strings, arrays, numbers, or booleans are rejected at config parse time.

Source

Thrown at app/src/ai/agent_sdk/config_file.rs:120

/// Convert an unwrapped `mcp_servers` map into runtime MCP specs for AgentDriver.
///
/// Behavior:
/// - Entries with a UUID `warp_id` become `MCPSpec::Uuid`.
/// - Entries with any other non-empty `warp_id` (e.g. `"linear"`) become `MCPSpec::WellKnown`
///   when `FeatureFlag::WellKnownMcpIds` is enabled (and are rejected otherwise);
///   the server owns the set of recognized ids and unknown ids are skipped at resolution.
/// - Entries with `command`/`url` remain as inline JSON (`MCPSpec::Json`) containing the unwrapped server map.
pub fn mcp_specs_from_mcp_servers(
    mcp_servers: &Map<String, Value>,
) -> anyhow::Result<Vec<MCPSpec>> {
    let mut uuids: Vec<uuid::Uuid> = Vec::new();
    let mut well_known: Vec<String> = Vec::new();
    let mut json_map: Map<String, Value> = Map::new();

    for (name, config) in mcp_servers {
        let obj = config
            .as_object()
            .ok_or_else(|| anyhow::anyhow!("MCP server '{name}' config must be a JSON object"))?;

        if let Some(warp_id) = obj.get("warp_id").and_then(Value::as_str) {
            if let Ok(uuid) = uuid::Uuid::parse_str(warp_id) {
                uuids.push(uuid);
            } else if !FeatureFlag::WellKnownMcpIds.is_enabled() {
                return Err(anyhow::anyhow!(
                    "MCP server '{name}' field 'warp_id' must be a UUID"
                ));
            } else if warp_id.trim().is_empty() {
                return Err(anyhow::anyhow!(
                    "MCP server '{name}' field 'warp_id' must be non-empty"
                ));
            } else {
                well_known.push(warp_id.to_string());
            }
        } else {
            json_map.insert(name.clone(), config.clone());
        }

View on GitHub (pinned to e72fd7aacb)

Solutions

  1. Make every mcp_servers value a JSON object, e.g. {"github": {"url": "https://mcp.github.com"}} instead of a bare string.
  2. Validate the config with a JSON schema or jq before launching: jq -e '.mcp_servers | to_entries | all(.value | type == "object")' config.json.
  3. Check for stray commas/brackets from hand edits that can collapse an object into a scalar.

Example fix

// before (config file)
{
  "mcp_servers": {
    "github": "https://mcp.github.com"
  }
}

// after
{
  "mcp_servers": {
    "github": { "url": "https://mcp.github.com" }
  }
}
Defensive patterns

Strategy: type-guard

Validate before calling

for (name, config) in &mcp_servers {
    if !config.is_object() {
        anyhow::bail!("mcp_servers.{name} must be a JSON object, got {}", json_type(config));
    }
}

Type guard

fn is_valid_mcp_entry(v: &serde_json::Value) -> bool {
    v.as_object().is_some()
}

Try / catch

match mcp_specs_from_mcp_servers(&mcp_servers) {
    Err(err) if err.to_string().contains("config must be a JSON object") => {
        // point the user at the offending server name parsed from the message
    }
    rest => rest,
}

Prevention

When it happens

Trigger: Loading an agent config file whose mcp_servers looks like {"github": "https://mcp.github.com"} (string shorthand) or {"github": ["npx", "server"]} (array) — any Value::as_object() == None for a server entry triggers this error before any MCP connection is attempted.

Common situations: Hand-editing the config and using the shorthand accepted by other tools (Claude Desktop, Cursor) that allow string URLs; copy-pasting a JSON5/YAML-converted config where nesting got flattened; or a malformed merge leaving a scalar in place of the object.

Related errors


AI-assisted analysis of warpdotdev/warp@e72fd7aacb (2026-08-16). Data as JSON: /api/errors/34ed943174fcb37f. Report an issue: GitHub.