diff --git a/src/features/claude-code-mcp-loader/scope-filtering.test.ts b/src/features/claude-code-mcp-loader/scope-filtering.test.ts index e90136b24..16618c879 100644 --- a/src/features/claude-code-mcp-loader/scope-filtering.test.ts +++ b/src/features/claude-code-mcp-loader/scope-filtering.test.ts @@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test" import { mkdirSync, rmSync, writeFileSync } from "fs" import { tmpdir } from "os" import { join } from "path" +import { shouldLoadMcpServer } from "./scope-filter" const TEST_DIR = join(tmpdir(), `mcp-scope-filtering-test-${Date.now()}`) const TEST_HOME = join(TEST_DIR, "home") @@ -27,6 +28,56 @@ describe("loadMcpConfigs", () => { rmSync(TEST_DIR, { recursive: true, force: true }) }) + describe("#given local MCP scope checks", () => { + it("#when cwd exactly matches project path #then the server is loaded", () => { + const result = shouldLoadMcpServer( + { + scope: "local", + projectPath: "/tmp/repo", + }, + "/tmp/repo" + ) + + expect(result).toBe(true) + }) + + it("#when cwd is a subdirectory of project path #then the server is loaded", () => { + const result = shouldLoadMcpServer( + { + scope: "local", + projectPath: "/tmp/repo", + }, + "/tmp/repo/packages/app" + ) + + expect(result).toBe(true) + }) + + it("#when cwd does not overlap project path #then the server is not loaded", () => { + const result = shouldLoadMcpServer( + { + scope: "local", + projectPath: "/tmp/repo", + }, + "/tmp/other" + ) + + expect(result).toBe(false) + }) + + it("#when cwd is the parent of project path #then the server is not loaded", () => { + const result = shouldLoadMcpServer( + { + scope: "local", + projectPath: "/tmp/repo", + }, + "/tmp" + ) + + expect(result).toBe(false) + }) + }) + describe("#given user-scoped MCP entries with local scope metadata", () => { it("#when loading configs #then only servers matching the current project path are loaded", async () => { writeFileSync( diff --git a/src/features/claude-code-plugin-loader/mcp-server-loader.test.ts b/src/features/claude-code-plugin-loader/mcp-server-loader.test.ts index 7f474b4cc..8bb1ea034 100644 --- a/src/features/claude-code-plugin-loader/mcp-server-loader.test.ts +++ b/src/features/claude-code-plugin-loader/mcp-server-loader.test.ts @@ -6,12 +6,14 @@ import type { LoadedPlugin } from "./types" const TEST_DIR = join(tmpdir(), `plugin-mcp-loader-test-${Date.now()}`) const PROJECT_DIR = join(TEST_DIR, "project") +const PROJECT_SUBDIRECTORY = join(PROJECT_DIR, "packages", "app") const PLUGIN_DIR = join(TEST_DIR, "plugin") const MCP_CONFIG_PATH = join(PLUGIN_DIR, "mcp.json") describe("loadPluginMcpServers", () => { beforeEach(() => { mkdirSync(PROJECT_DIR, { recursive: true }) + mkdirSync(PROJECT_SUBDIRECTORY, { recursive: true }) mkdirSync(PLUGIN_DIR, { recursive: true }) mock.module("../../shared/logger", () => ({ log: () => {}, @@ -24,7 +26,7 @@ describe("loadPluginMcpServers", () => { }) describe("#given plugin MCP entries with local scope metadata", () => { - it("#when loading plugin MCP servers #then only entries matching the current cwd are included", async () => { + it("#when loading plugin MCP servers from a project subdirectory #then only entries within the same project are included", async () => { writeFileSync( MCP_CONFIG_PATH, JSON.stringify({ @@ -45,6 +47,12 @@ describe("loadPluginMcpServers", () => { scope: "local", projectPath: join(PROJECT_DIR, "other-project"), }, + parentLocal: { + command: "npx", + args: ["parent-plugin-local"], + scope: "local", + projectPath: join(PROJECT_SUBDIRECTORY, "nested-project"), + }, }, }) ) @@ -59,7 +67,7 @@ describe("loadPluginMcpServers", () => { } const originalCwd = process.cwd() - process.chdir(PROJECT_DIR) + process.chdir(PROJECT_SUBDIRECTORY) try { const { loadPluginMcpServers } = await import("./mcp-server-loader") @@ -68,6 +76,7 @@ describe("loadPluginMcpServers", () => { expect(servers).toHaveProperty("demo-plugin:globalServer") expect(servers).toHaveProperty("demo-plugin:matchingLocal") expect(servers).not.toHaveProperty("demo-plugin:nonMatchingLocal") + expect(servers).not.toHaveProperty("demo-plugin:parentLocal") } finally { process.chdir(originalCwd) }