{"record":{"id":"1418e05397e4eedd","repo":"Kuberwastaken/claurst","slug":"mcpservers-name-must-be-an-object","errorCode":null,"errorMessage":"mcpServers.{name} must be an object","messagePattern":"mcpServers\\.(.+?) must be an object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-rust/crates/core/src/import_config.rs","lineNumber":653,"sourceCode":"    target.config.hooks = hooks;\n    imported_fields.push(\"hooks\".to_string());\n    if action == PreviewAction::Replace {\n        *replaced_count += 1;\n    } else {\n        *imported_count += 1;\n    }\n}\n\nfn parse_mcp_servers(value: &Value) -> Result<Vec<McpServerConfig>> {\n    let Some(obj) = value.as_object() else {\n        return Err(anyhow!(\"mcpServers must be an object\"));\n    };\n\n    let mut servers = Vec::new();\n    for (name, entry) in obj {\n        let entry_obj = entry\n            .as_object()\n            .ok_or_else(|| anyhow!(\"mcpServers.{name} must be an object\"))?;\n        let command = entry_obj\n            .get(\"command\")\n            .and_then(Value::as_str)\n            .map(ToString::to_string);\n        let url = entry_obj\n            .get(\"url\")\n            .and_then(Value::as_str)\n            .map(ToString::to_string);\n        if command.is_none() && url.is_none() {\n            return Err(anyhow!(\"mcpServers.{name} is missing command/url\"));\n        }\n        let args = entry_obj\n            .get(\"args\")\n            .and_then(Value::as_array)\n            .map(|items| {\n                items\n                    .iter()\n                    .filter_map(Value::as_str)","sourceCodeStart":635,"sourceCodeEnd":671,"githubUrl":"https://github.com/Kuberwastaken/claurst/blob/b0637c97ec34144387cbf2f74f65df6d16a6cef1/src-rust/crates/core/src/import_config.rs#L635-L671","documentation":"Within parse_mcp_servers, each value of the mcpServers object must itself be a JSON object describing one server. If a value is a string, number, null, or array, this error names the offending key (mcpServers.{name}) and aborts the import.","triggerScenarios":"Importing a config where mcpServers maps some name to a non-object, e.g. \"mcpServers\": {\"fs\": \"npx ...\"} or {\"fs\": null}.","commonSituations":"Hand-edited settings.json where a server entry was replaced by a command string, nulling out a disabled server, or merging configs incorrectly so a nested object got flattened.","solutions":["Replace the mcpServers.{name} value with a JSON object containing at least \"command\" or \"url\"","Delete the malformed entry if that server is no longer needed","Validate the source JSON with a schema or jq before importing"],"exampleFix":"// before\n{ \"mcpServers\": { \"fs\": \"npx -y @modelcontextprotocol/server-fs\" } }\n// after\n{ \"mcpServers\": { \"fs\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-fs\"] } } }","handlingStrategy":"type-guard","validationCode":"for (const [name, entry] of Object.entries(cfg.mcpServers ?? {})) {\n  if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) throw new Error(`mcpServers.${name} must be an object`);\n}","typeGuard":"const isServerEntry = (v) => typeof v === 'object' && v !== null && !Array.isArray(v) && (typeof v.command === 'string' || typeof v.url === 'string');","tryCatchPattern":"try { importConfig(path) } catch (e) { const m = String(e).match(/mcpServers\\.(\\S+) must be an object/); if (m) { console.error(`Fix server \"${m[1]}\" in ${path}`); } else { throw e; } }","preventionTips":["Each mcpServers value must be an object with command or url — never a raw string","Use key deletion rather than setting a server entry to null to disable it","Run jq '.mcpServers | map_values(type)' settings.json to spot non-object entries"],"tags":["json","config-import","validation","mcp"],"backgroundTag":"config-type-mismatch","analyzedSha":"b0637c97ec34144387cbf2f74f65df6d16a6cef1","analyzedAt":"2026-09-10T00:24:58.650Z","contentChangedAt":"2026-09-10T00:24:58.650Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}