import { describe, expect, it } from "vitest"; import { resolveServers } from "./config.js"; describe("resolveServers", () => { it("resolves from .dispatch/mcp.json", () => { const dispatchConfig = JSON.stringify({ servers: { freecad: { command: "uvx", args: ["freecad-mcp"], env: { KEY: "val" } }, }, }); const result = resolveServers({ dispatchMcpJson: dispatchConfig, opencodeJson: null }); expect(result.servers.length).toBe(1); expect(result.servers[0].id).toBe("freecad"); expect(result.servers[0].command).toEqual(["uvx", "freecad-mcp"]); expect(result.servers[0].env).toEqual({ KEY: "val" }); expect(result.servers[0].configSource).toBe(".dispatch/mcp.json"); expect(result.shadowed).toBe(false); }); it("falls back to opencode.json mcp key", () => { const opencodeConfig = JSON.stringify({ mcp: { chrome: { command: "npx", args: ["chrome-devtools-mcp@latest"] }, }, }); const result = resolveServers({ dispatchMcpJson: null, opencodeJson: opencodeConfig }); expect(result.servers.length).toBe(1); expect(result.servers[0].id).toBe("chrome"); expect(result.servers[0].command).toEqual(["npx", "chrome-devtools-mcp@latest"]); expect(result.servers[0].configSource).toBe("opencode.json"); expect(result.shadowed).toBe(false); }); it("shadow warning when both present", () => { const dispatchConfig = JSON.stringify({ servers: { freecad: { command: "uvx", args: ["freecad-mcp"] }, }, }); const opencodeConfig = JSON.stringify({ mcp: { chrome: { command: "npx", args: ["chrome-devtools-mcp@latest"] }, }, }); const result = resolveServers({ dispatchMcpJson: dispatchConfig, opencodeJson: opencodeConfig, }); expect(result.servers.length).toBe(1); expect(result.servers[0].id).toBe("freecad"); expect(result.shadowed).toBe(true); }); it("empty when neither present", () => { const result = resolveServers({ dispatchMcpJson: null, opencodeJson: null }); expect(result.servers.length).toBe(0); expect(result.shadowed).toBe(false); }); it("empty when dispatch has no servers key", () => { const result = resolveServers({ dispatchMcpJson: JSON.stringify({}), opencodeJson: null, }); expect(result.servers.length).toBe(0); expect(result.shadowed).toBe(false); }); it("handles malformed JSON gracefully", () => { const result = resolveServers({ dispatchMcpJson: "not valid json", opencodeJson: "{ also bad", }); expect(result.servers.length).toBe(0); expect(result.shadowed).toBe(false); }); it("server without args", () => { const dispatchConfig = JSON.stringify({ servers: { simple: { command: "my-server" }, }, }); const result = resolveServers({ dispatchMcpJson: dispatchConfig, opencodeJson: null }); expect(result.servers.length).toBe(1); expect(result.servers[0].command).toEqual(["my-server"]); }); it("multiple servers from dispatch", () => { const dispatchConfig = JSON.stringify({ servers: { a: { command: "server-a" }, b: { command: "server-b", args: ["--port", "3000"] }, }, }); const result = resolveServers({ dispatchMcpJson: dispatchConfig, opencodeJson: null }); expect(result.servers.length).toBe(2); const ids = result.servers.map((s) => s.id).sort(); expect(ids).toEqual(["a", "b"]); }); });