coleam00/Archon · error

Failed to read MCP config file: ${mcpPath} - ${e.message}

Error message

Failed to read MCP config file: ${mcpPath} - ${e.message}

What it means

When reading the MCP config file fails for any reason other than a missing file (EACCES permission denied, EISDIR when the path is a directory, ELOOP on symlink cycles), loadMcpConfig wraps the OS error message into a single error prefixed with the requested path, preserving the underlying cause text for diagnosis.

Source

Thrown at packages/providers/src/mcp/config.ts:142

/**
 * 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');
  } catch (err) {
    const e = err as NodeJS.ErrnoException;
    if (e.code === 'ENOENT') {
      throw new Error(`MCP config file not found: ${mcpPath} (resolved to ${fullPath})`);
    }
    throw new Error(`Failed to read MCP config file: ${mcpPath} - ${e.message}`);
  }

  let parsed: Record<string, unknown>;
  try {
    parsed = JSON.parse(raw) as Record<string, unknown>;
  } catch (parseErr) {
    const detail = (parseErr as SyntaxError).message;
    throw new Error(`MCP config file is not valid JSON: ${mcpPath} - ${detail}`);
  }

  if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
    throw new Error(`MCP config must be a JSON object (Record<string, ServerConfig>): ${mcpPath}`);
  }

  const normalized = normalizeMcpConfig(parsed, mcpPath);
  const { expanded, missingVars } = expandEnvVars(normalized, envSource);
  const serverNames = Object.keys(expanded);
  return { servers: expanded, serverNames, missingVars };

View on GitHub (pinned to 0773b97458)

Solutions

  1. Read the OS message after the dash and fix the cause (chmod/chown the file, or correct the path if it is a directory).
  2. Run: ls -la <resolved-path> to check permissions and type.
  3. In containers, ensure the file is mounted readable by the process user.

Example fix

// before
-rw------- 1 root root .mcp.json   # process runs as non-root: EACCES
// after
$ chmod 644 .mcp.json   # or chown to the running user
Defensive patterns

Strategy: try-catch

Validate before calling

import { statSync, accessSync, constants } from 'fs';
const st = statSync(fullPath); // throws EACCES/EISDIR before loadMcpConfig if unreadable
accessSync(fullPath, constants.R_OK);

Try / catch

try {
  const cfg = await loadMcpConfig(p, cwd);
} catch (err) {
  if (err.message.startsWith('Failed to read MCP config file')) {
    console.error(`Unreadable MCP config: ${err.message}. Check permissions/ownership.`);
  } else throw err;
}

Prevention

When it happens

Trigger: loadMcpConfig where the path points to a directory, the file is chmod 000 or owned by another user, an NFS/symlink issue occurs, or the disk errors during read.

Common situations: Clone/config checked out without read permissions; running the process as a different user (container user mismatch); pointing at ~/.mcp.json while it is actually a directory; overly restrictive umask in CI.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/18fc77aebb22b771. Report an issue: GitHub.