Add getSystemMcpServerNames() sync function to detect system-configured MCP servers from .mcp.json files (user, project, and local scopes). Builtin skills like playwright are now automatically excluded when their MCP server is already configured in system config, preventing duplicate MCP server registration. Also adds comprehensive test suite with 5 BDD-style tests covering empty config, project/local scopes, disabled servers, and merged configurations. Changes: - loader.ts: Add getSystemMcpServerNames() function + readFileSync import - loader.test.ts: Add 5 tests for getSystemMcpServerNames() edge cases - index.ts: Filter builtin skills to exclude those with overlapping MCP names 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
163 lines
4.1 KiB
TypeScript
163 lines
4.1 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach } from "bun:test"
|
|
import { mkdirSync, writeFileSync, rmSync } from "fs"
|
|
import { join } from "path"
|
|
import { tmpdir } from "os"
|
|
|
|
const TEST_DIR = join(tmpdir(), "mcp-loader-test-" + Date.now())
|
|
|
|
describe("getSystemMcpServerNames", () => {
|
|
beforeEach(() => {
|
|
mkdirSync(TEST_DIR, { recursive: true })
|
|
})
|
|
|
|
afterEach(() => {
|
|
rmSync(TEST_DIR, { recursive: true, force: true })
|
|
})
|
|
|
|
it("returns empty set when no .mcp.json files exist", async () => {
|
|
// #given
|
|
const originalCwd = process.cwd()
|
|
process.chdir(TEST_DIR)
|
|
|
|
try {
|
|
// #when
|
|
const { getSystemMcpServerNames } = await import("./loader")
|
|
const names = getSystemMcpServerNames()
|
|
|
|
// #then
|
|
expect(names).toBeInstanceOf(Set)
|
|
expect(names.size).toBe(0)
|
|
} finally {
|
|
process.chdir(originalCwd)
|
|
}
|
|
})
|
|
|
|
it("returns server names from project .mcp.json", async () => {
|
|
// #given
|
|
const mcpConfig = {
|
|
mcpServers: {
|
|
playwright: {
|
|
command: "npx",
|
|
args: ["@playwright/mcp@latest"],
|
|
},
|
|
sqlite: {
|
|
command: "uvx",
|
|
args: ["mcp-server-sqlite"],
|
|
},
|
|
},
|
|
}
|
|
writeFileSync(join(TEST_DIR, ".mcp.json"), JSON.stringify(mcpConfig))
|
|
|
|
const originalCwd = process.cwd()
|
|
process.chdir(TEST_DIR)
|
|
|
|
try {
|
|
// #when
|
|
const { getSystemMcpServerNames } = await import("./loader")
|
|
const names = getSystemMcpServerNames()
|
|
|
|
// #then
|
|
expect(names.has("playwright")).toBe(true)
|
|
expect(names.has("sqlite")).toBe(true)
|
|
expect(names.size).toBe(2)
|
|
} finally {
|
|
process.chdir(originalCwd)
|
|
}
|
|
})
|
|
|
|
it("returns server names from .claude/.mcp.json", async () => {
|
|
// #given
|
|
mkdirSync(join(TEST_DIR, ".claude"), { recursive: true })
|
|
const mcpConfig = {
|
|
mcpServers: {
|
|
memory: {
|
|
command: "npx",
|
|
args: ["-y", "@anthropic-ai/mcp-server-memory"],
|
|
},
|
|
},
|
|
}
|
|
writeFileSync(join(TEST_DIR, ".claude", ".mcp.json"), JSON.stringify(mcpConfig))
|
|
|
|
const originalCwd = process.cwd()
|
|
process.chdir(TEST_DIR)
|
|
|
|
try {
|
|
// #when
|
|
const { getSystemMcpServerNames } = await import("./loader")
|
|
const names = getSystemMcpServerNames()
|
|
|
|
// #then
|
|
expect(names.has("memory")).toBe(true)
|
|
} finally {
|
|
process.chdir(originalCwd)
|
|
}
|
|
})
|
|
|
|
it("excludes disabled MCP servers", async () => {
|
|
// #given
|
|
const mcpConfig = {
|
|
mcpServers: {
|
|
playwright: {
|
|
command: "npx",
|
|
args: ["@playwright/mcp@latest"],
|
|
disabled: true,
|
|
},
|
|
active: {
|
|
command: "npx",
|
|
args: ["some-mcp"],
|
|
},
|
|
},
|
|
}
|
|
writeFileSync(join(TEST_DIR, ".mcp.json"), JSON.stringify(mcpConfig))
|
|
|
|
const originalCwd = process.cwd()
|
|
process.chdir(TEST_DIR)
|
|
|
|
try {
|
|
// #when
|
|
const { getSystemMcpServerNames } = await import("./loader")
|
|
const names = getSystemMcpServerNames()
|
|
|
|
// #then
|
|
expect(names.has("playwright")).toBe(false)
|
|
expect(names.has("active")).toBe(true)
|
|
} finally {
|
|
process.chdir(originalCwd)
|
|
}
|
|
})
|
|
|
|
it("merges server names from multiple .mcp.json files", async () => {
|
|
// #given
|
|
mkdirSync(join(TEST_DIR, ".claude"), { recursive: true })
|
|
|
|
const projectMcp = {
|
|
mcpServers: {
|
|
playwright: { command: "npx", args: ["@playwright/mcp@latest"] },
|
|
},
|
|
}
|
|
const localMcp = {
|
|
mcpServers: {
|
|
memory: { command: "npx", args: ["-y", "@anthropic-ai/mcp-server-memory"] },
|
|
},
|
|
}
|
|
|
|
writeFileSync(join(TEST_DIR, ".mcp.json"), JSON.stringify(projectMcp))
|
|
writeFileSync(join(TEST_DIR, ".claude", ".mcp.json"), JSON.stringify(localMcp))
|
|
|
|
const originalCwd = process.cwd()
|
|
process.chdir(TEST_DIR)
|
|
|
|
try {
|
|
// #when
|
|
const { getSystemMcpServerNames } = await import("./loader")
|
|
const names = getSystemMcpServerNames()
|
|
|
|
// #then
|
|
expect(names.has("playwright")).toBe(true)
|
|
expect(names.has("memory")).toBe(true)
|
|
} finally {
|
|
process.chdir(originalCwd)
|
|
}
|
|
})
|
|
})
|