coleam00/Archon · error
MCP config field "mcpServers" must be a JSON object: ${mcpPa
Error message
MCP config field "mcpServers" must be a JSON object: ${mcpPath} What it means
When a config uses the {"mcpServers": ...} wrapper form, the value of mcpServers must be a JSON object mapping server names to server objects. A null, array, or primitive value means there are no valid server definitions, so normalizeMcpConfig throws including the config path.
Source
Thrown at packages/providers/src/mcp/config.ts:118
function normalizeMcpConfig(
parsed: Record<string, unknown>,
mcpPath: string
): Record<string, unknown> {
const keys = Object.keys(parsed);
if (!keys.includes('mcpServers')) {
return parsed;
}
if (keys.length > 1) {
throw new Error(
`MCP config cannot mix top-level "mcpServers" with other keys: ${mcpPath}. Use either a direct server map or { "mcpServers": { ... } }.`
);
}
const servers = parsed.mcpServers;
if (typeof servers !== 'object' || servers === null || Array.isArray(servers)) {
throw new Error(`MCP config field "mcpServers" must be a JSON object: ${mcpPath}`);
}
return servers as Record<string, unknown>;
}
/**
* Load MCP server config from a JSON file and expand environment variables.
*/
export async function loadMcpConfig(
mcpPath: string,
cwd: string,
envSource: EnvSource = process.env
): Promise<LoadedMcpConfig> {
const fullPath = isAbsolute(mcpPath) ? mcpPath : resolve(cwd, mcpPath);
let raw: string;
try {
raw = await readFile(fullPath, 'utf-8');View on GitHub (pinned to 0773b97458)
Solutions
- Replace null/array with an object: {"mcpServers": {}} for zero servers.
- Add at least one server definition under mcpServers.
- If the file was meant to disable MCP entirely, remove the mcpServers key and point the caller at a different config.
Example fix
// before
{"mcpServers": null}
// after
{"mcpServers": {"fs": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]}}} Defensive patterns
Strategy: validation
Validate before calling
if ('mcpServers' in cfg) {
const s = cfg.mcpServers;
if (typeof s !== 'object' || s === null || Array.isArray(s)) {
throw new Error('mcpServers must be an object');
}
} Type guard
const isServerMap = (v: unknown): v is Record<string, Record<string, unknown>> => typeof v === 'object' && v !== null && !Array.isArray(v) && Object.values(v).every((x) => typeof x === 'object' && x !== null && !Array.isArray(x));
Prevention
- Use {} for an empty server set, never null or [].
- Generate configs from templates that emit object literals, not nullable values.
- Validate with a schema: mcpServers?: { [name: string]: ServerConfig }.
When it happens
Trigger: loadMcpConfig on {"mcpServers": null}, {"mcpServers": []}, or {"mcpServers": "..."} (alone as the only key).
Common situations: A template left mcpServers empty/null; a script serialized an empty list instead of an object; hand-deleting all servers left the wrong JSON shape; YAML empty value became null.
Related errors
- MCP server "${serverName}" must be a JSON object (got ${desc
- MCP config must be a JSON object (Record<string, ServerConfi
- MCP config ${fieldPath}.${key} must be a string (got ${descr
- MCP config ${serverName}.env must be a JSON object of string
- MCP config ${serverName}.headers must be a JSON object of st
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/032f73c524a30d82.
Report an issue: GitHub.