diff --git a/src/features/claude-code-mcp-loader/loader.test.ts b/src/features/claude-code-mcp-loader/loader.test.ts index 8faf65718..8a1b9f6ea 100644 --- a/src/features/claude-code-mcp-loader/loader.test.ts +++ b/src/features/claude-code-mcp-loader/loader.test.ts @@ -192,4 +192,57 @@ describe("getSystemMcpServerNames", () => { rmSync(userConfigPath, { force: true }) } }) + + it("reads both ~/.claude.json and ~/.claude/.mcp.json for user scope", async () => { + // given: simulate both user-level config files + const userClaudeJson = join(TEST_DIR, ".claude.json") + const claudeDir = join(TEST_DIR, ".claude") + const claudeDirMcpJson = join(claudeDir, ".mcp.json") + + mkdirSync(claudeDir, { recursive: true }) + + // ~/.claude.json has server-a + writeFileSync(userClaudeJson, JSON.stringify({ + mcpServers: { + "server-from-claude-json": { + command: "npx", + args: ["server-a"], + }, + }, + })) + + // ~/.claude/.mcp.json has server-b (CLI-managed) + writeFileSync(claudeDirMcpJson, JSON.stringify({ + mcpServers: { + "server-from-mcp-json": { + command: "npx", + args: ["server-b"], + }, + }, + })) + + const originalCwd = process.cwd() + process.chdir(TEST_DIR) + + try { + mock.module("os", () => ({ + homedir: () => TEST_DIR, + tmpdir, + })) + + // Also mock getClaudeConfigDir to point to our test .claude dir + mock.module("../../shared", () => ({ + getClaudeConfigDir: () => claudeDir, + })) + + const { getSystemMcpServerNames } = await import("./loader") + const names = getSystemMcpServerNames() + + // Both sources should be merged + expect(names.has("server-from-claude-json")).toBe(true) + expect(names.has("server-from-mcp-json")).toBe(true) + } finally { + process.chdir(originalCwd) + } + }) }) diff --git a/src/features/claude-code-mcp-loader/loader.ts b/src/features/claude-code-mcp-loader/loader.ts index 7e0f5da76..754b71a9a 100644 --- a/src/features/claude-code-mcp-loader/loader.ts +++ b/src/features/claude-code-mcp-loader/loader.ts @@ -17,10 +17,12 @@ interface McpConfigPath { } function getMcpConfigPaths(): McpConfigPath[] { + const claudeConfigDir = getClaudeConfigDir() const cwd = process.cwd() return [ { path: join(homedir(), ".claude.json"), scope: "user" }, + { path: join(claudeConfigDir, ".mcp.json"), scope: "user" }, { path: join(cwd, ".mcp.json"), scope: "project" }, { path: join(cwd, ".claude", ".mcp.json"), scope: "local" }, ]