Add MCP scope subdirectory regression tests
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
|||||||
import { mkdirSync, rmSync, writeFileSync } from "fs"
|
import { mkdirSync, rmSync, writeFileSync } from "fs"
|
||||||
import { tmpdir } from "os"
|
import { tmpdir } from "os"
|
||||||
import { join } from "path"
|
import { join } from "path"
|
||||||
|
import { shouldLoadMcpServer } from "./scope-filter"
|
||||||
|
|
||||||
const TEST_DIR = join(tmpdir(), `mcp-scope-filtering-test-${Date.now()}`)
|
const TEST_DIR = join(tmpdir(), `mcp-scope-filtering-test-${Date.now()}`)
|
||||||
const TEST_HOME = join(TEST_DIR, "home")
|
const TEST_HOME = join(TEST_DIR, "home")
|
||||||
@@ -27,6 +28,56 @@ describe("loadMcpConfigs", () => {
|
|||||||
rmSync(TEST_DIR, { recursive: true, force: true })
|
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", () => {
|
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 () => {
|
it("#when loading configs #then only servers matching the current project path are loaded", async () => {
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ import type { LoadedPlugin } from "./types"
|
|||||||
|
|
||||||
const TEST_DIR = join(tmpdir(), `plugin-mcp-loader-test-${Date.now()}`)
|
const TEST_DIR = join(tmpdir(), `plugin-mcp-loader-test-${Date.now()}`)
|
||||||
const PROJECT_DIR = join(TEST_DIR, "project")
|
const PROJECT_DIR = join(TEST_DIR, "project")
|
||||||
|
const PROJECT_SUBDIRECTORY = join(PROJECT_DIR, "packages", "app")
|
||||||
const PLUGIN_DIR = join(TEST_DIR, "plugin")
|
const PLUGIN_DIR = join(TEST_DIR, "plugin")
|
||||||
const MCP_CONFIG_PATH = join(PLUGIN_DIR, "mcp.json")
|
const MCP_CONFIG_PATH = join(PLUGIN_DIR, "mcp.json")
|
||||||
|
|
||||||
describe("loadPluginMcpServers", () => {
|
describe("loadPluginMcpServers", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mkdirSync(PROJECT_DIR, { recursive: true })
|
mkdirSync(PROJECT_DIR, { recursive: true })
|
||||||
|
mkdirSync(PROJECT_SUBDIRECTORY, { recursive: true })
|
||||||
mkdirSync(PLUGIN_DIR, { recursive: true })
|
mkdirSync(PLUGIN_DIR, { recursive: true })
|
||||||
mock.module("../../shared/logger", () => ({
|
mock.module("../../shared/logger", () => ({
|
||||||
log: () => {},
|
log: () => {},
|
||||||
@@ -24,7 +26,7 @@ describe("loadPluginMcpServers", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("#given plugin MCP entries with local scope metadata", () => {
|
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(
|
writeFileSync(
|
||||||
MCP_CONFIG_PATH,
|
MCP_CONFIG_PATH,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@@ -45,6 +47,12 @@ describe("loadPluginMcpServers", () => {
|
|||||||
scope: "local",
|
scope: "local",
|
||||||
projectPath: join(PROJECT_DIR, "other-project"),
|
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()
|
const originalCwd = process.cwd()
|
||||||
process.chdir(PROJECT_DIR)
|
process.chdir(PROJECT_SUBDIRECTORY)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { loadPluginMcpServers } = await import("./mcp-server-loader")
|
const { loadPluginMcpServers } = await import("./mcp-server-loader")
|
||||||
@@ -68,6 +76,7 @@ describe("loadPluginMcpServers", () => {
|
|||||||
expect(servers).toHaveProperty("demo-plugin:globalServer")
|
expect(servers).toHaveProperty("demo-plugin:globalServer")
|
||||||
expect(servers).toHaveProperty("demo-plugin:matchingLocal")
|
expect(servers).toHaveProperty("demo-plugin:matchingLocal")
|
||||||
expect(servers).not.toHaveProperty("demo-plugin:nonMatchingLocal")
|
expect(servers).not.toHaveProperty("demo-plugin:nonMatchingLocal")
|
||||||
|
expect(servers).not.toHaveProperty("demo-plugin:parentLocal")
|
||||||
} finally {
|
} finally {
|
||||||
process.chdir(originalCwd)
|
process.chdir(originalCwd)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user