Kuberwastaken/claurst · error
mcpServers. must be an object
Error message
mcpServers.{name} must be an object What it means
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.
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
Example fix
// before
{ "mcpServers": { "fs": "npx -y @modelcontextprotocol/server-fs" } }
// after
{ "mcpServers": { "fs": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-fs"] } } } Defensive patterns
Strategy: type-guard
Validate before calling
for (const [name, entry] of Object.entries(cfg.mcpServers ?? {})) {
if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) throw new Error(`mcpServers.${name} must be an object`);
} Type guard
const isServerEntry = (v) => typeof v === 'object' && v !== null && !Array.isArray(v) && (typeof v.command === 'string' || typeof v.url === 'string');
Try / catch
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; } } Prevention
- 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
When it happens
Trigger: Importing a config where mcpServers maps some name to a non-object, e.g. "mcpServers": {"fs": "npx ..."} or {"fs": null}.
Common situations: 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.
Related errors
- mcpServers must be an object
- mcpServers. is missing command/url
- hooks must be an object
- hooks. must be an array
- hooks. [] must be an object
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/1418e05397e4eedd.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/core/src/import_config.rs:653
target.config.hooks = hooks;
imported_fields.push("hooks".to_string());
if action == PreviewAction::Replace {
*replaced_count += 1;
} else {
*imported_count += 1;
}
}
fn parse_mcp_servers(value: &Value) -> Result<Vec<McpServerConfig>> {
let Some(obj) = value.as_object() else {
return Err(anyhow!("mcpServers must be an object"));
};
let mut servers = Vec::new();
for (name, entry) in obj {
let entry_obj = entry
.as_object()
.ok_or_else(|| anyhow!("mcpServers.{name} must be an object"))?;
let command = entry_obj
.get("command")
.and_then(Value::as_str)
.map(ToString::to_string);
let url = entry_obj
.get("url")
.and_then(Value::as_str)
.map(ToString::to_string);
if command.is_none() && url.is_none() {
return Err(anyhow!("mcpServers.{name} is missing command/url"));
}
let args = entry_obj
.get("args")
.and_then(Value::as_array)
.map(|items| {
items
.iter()
.filter_map(Value::as_str)View on GitHub (pinned to b0637c97ec)