{"record":{"id":"18fc77aebb22b771","repo":"coleam00/Archon","slug":"failed-to-read-mcp-config-file-mcppath-e-m","errorCode":null,"errorMessage":"Failed to read MCP config file: ${mcpPath} - ${e.message}","messagePattern":"Failed to read MCP config file: (.+?) - (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/providers/src/mcp/config.ts","lineNumber":142,"sourceCode":"/**\n * Load MCP server config from a JSON file and expand environment variables.\n */\nexport async function loadMcpConfig(\n  mcpPath: string,\n  cwd: string,\n  envSource: EnvSource = process.env\n): Promise<LoadedMcpConfig> {\n  const fullPath = isAbsolute(mcpPath) ? mcpPath : resolve(cwd, mcpPath);\n\n  let raw: string;\n  try {\n    raw = await readFile(fullPath, 'utf-8');\n  } catch (err) {\n    const e = err as NodeJS.ErrnoException;\n    if (e.code === 'ENOENT') {\n      throw new Error(`MCP config file not found: ${mcpPath} (resolved to ${fullPath})`);\n    }\n    throw new Error(`Failed to read MCP config file: ${mcpPath} - ${e.message}`);\n  }\n\n  let parsed: Record<string, unknown>;\n  try {\n    parsed = JSON.parse(raw) as Record<string, unknown>;\n  } catch (parseErr) {\n    const detail = (parseErr as SyntaxError).message;\n    throw new Error(`MCP config file is not valid JSON: ${mcpPath} - ${detail}`);\n  }\n\n  if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n    throw new Error(`MCP config must be a JSON object (Record<string, ServerConfig>): ${mcpPath}`);\n  }\n\n  const normalized = normalizeMcpConfig(parsed, mcpPath);\n  const { expanded, missingVars } = expandEnvVars(normalized, envSource);\n  const serverNames = Object.keys(expanded);\n  return { servers: expanded, serverNames, missingVars };","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/providers/src/mcp/config.ts#L124-L160","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the OS message after the dash and fix the cause (chmod/chown the file, or correct the path if it is a directory).","Run: ls -la <resolved-path> to check permissions and type.","In containers, ensure the file is mounted readable by the process user."],"exampleFix":"// before\n-rw------- 1 root root .mcp.json   # process runs as non-root: EACCES\n// after\n$ chmod 644 .mcp.json   # or chown to the running user","handlingStrategy":"try-catch","validationCode":"import { statSync, accessSync, constants } from 'fs';\nconst st = statSync(fullPath); // throws EACCES/EISDIR before loadMcpConfig if unreadable\naccessSync(fullPath, constants.R_OK);","typeGuard":null,"tryCatchPattern":"try {\n  const cfg = await loadMcpConfig(p, cwd);\n} catch (err) {\n  if (err.message.startsWith('Failed to read MCP config file')) {\n    console.error(`Unreadable MCP config: ${err.message}. Check permissions/ownership.`);\n  } else throw err;\n}","preventionTips":["Deploy configs with 644 and correct ownership for the process user.","Verify the path is a file, not a directory (statSync().isFile()).","In containers, mount config files readable by the runtime user."],"tags":["filesystem","permissions","mcp","config"],"backgroundTag":"file-permission-denied","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}