{"record":{"id":"a9ab4d399a7d8f34","repo":"Kuberwastaken/claurst","slug":"mcpservers-must-be-an-object","errorCode":null,"errorMessage":"mcpServers 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":646,"sourceCode":"        PreviewAction::Import\n    };\n    preview_fields.push(PreviewField {\n        name: format!(\"hooks ({})\", hooks.len()),\n        action,\n        reason: None,\n    });\n    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        }","sourceCodeStart":628,"sourceCodeEnd":664,"githubUrl":"https://github.com/Kuberwastaken/claurst/blob/b0637c97ec34144387cbf2f74f65df6d16a6cef1/src-rust/crates/core/src/import_config.rs#L628-L664","documentation":"parse_mcp_servers in import_config.rs requires the JSON value under the `mcpServers` key to be a JSON object mapping server names to server configs. If the value is any other JSON type (string, array, number, null), this error is thrown. It guards the MCP-server import path during settings/config import from another tool's config file.","triggerScenarios":"Calling the config importer (via map_mcp_servers_field or parse_mcp_servers_object) with a settings file where \"mcpServers\" is null, a string, or an array instead of an object like {\"server\": {...}}.","commonSituations":"Importing a settings.json where mcpServers was manually emptied (set to null), a typo like \"mcpServer\", copying config fragments between tools, or a foreign config format that stores servers as a list.","solutions":["Open the source settings file and make \"mcpServers\" a JSON object keyed by server name","Remove the mcpServers key entirely if no MCP servers should be imported (it is then skipped instead of parsed)","If the source tool stores servers as an array, convert entries into an object keyed by server name"],"exampleFix":"// before\n{ \"mcpServers\": [ {\"name\": \"fs\", \"command\": \"npx\"} ] }\n// after\n{ \"mcpServers\": { \"fs\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-fs\"] } } }","handlingStrategy":"validation","validationCode":"const cfg = JSON.parse(fs.readFileSync(path, 'utf8'));\nif (cfg.mcpServers !== undefined && (typeof cfg.mcpServers !== 'object' || Array.isArray(cfg.mcpServers) || cfg.mcpServers === null)) {\n  throw new Error('mcpServers must be a JSON object keyed by server name');\n}","typeGuard":"const isMcpServersMap = (v) => typeof v === 'object' && v !== null && !Array.isArray(v) && Object.values(v).every((e) => typeof e === 'object' && e !== null);","tryCatchPattern":"try { importConfig(path) } catch (e) { if (String(e).includes('mcpServers must be an object')) { fixMcpServersShape(path); } else { throw e; } }","preventionTips":["Never null out mcpServers to disable it; delete the key instead","Validate settings JSON against the importer schema before running import","Keep mcpServers entries as an object map, not an array"],"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"}