(filePath: string)
| 129 | } |
| 130 | |
| 131 | private async readConfigFile(filePath: string): Promise<MCPConfig> { |
| 132 | try { |
| 133 | const exists = await this.pathExists(filePath); |
| 134 | if (!exists) { |
| 135 | return { servers: {} }; |
| 136 | } |
| 137 | |
| 138 | const raw = await fs.promises.readFile(filePath, "utf-8"); |
| 139 | const parsed = jsonc.parse(raw) as { servers?: Record<string, unknown> } | undefined; |
| 140 | |
| 141 | if (!parsed || typeof parsed !== "object" || !parsed.servers) { |
| 142 | return { servers: {} }; |
| 143 | } |
| 144 | |
| 145 | // Normalize all entries on read |
| 146 | const servers: Record<string, MCPServerInfo> = {}; |
| 147 | for (const [name, entry] of Object.entries(parsed.servers)) { |
| 148 | servers[name] = this.normalizeEntry(entry); |
| 149 | } |
| 150 | return { servers }; |
| 151 | } catch (error) { |
| 152 | // Defensive: never crash on startup due to corrupt config. |
| 153 | log.error("Failed to read MCP config", { filePath, error }); |
| 154 | return { servers: {} }; |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | private async getGlobalConfig(): Promise<MCPConfig> { |
| 159 | return this.readConfigFile(this.getGlobalConfigPath()); |
no test coverage detected