54 lines
2.4 KiB
TypeScript
54 lines
2.4 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import {
|
|
__clearMcpRegistryForTests,
|
|
createMcpExternalToolsProvider,
|
|
listMcpToolsForChatbot,
|
|
registerMcpToolForChatbot,
|
|
unregisterMcpToolForChatbot,
|
|
} from "./mcp-registry.server";
|
|
|
|
describe("mcp-registry", () => {
|
|
beforeEach(() => {
|
|
__clearMcpRegistryForTests();
|
|
});
|
|
|
|
it("registers, lists, and unregisters tools", () => {
|
|
registerMcpToolForChatbot({ toolName: "ping", description: "ping" });
|
|
registerMcpToolForChatbot({ toolName: "stat", description: "stat" });
|
|
expect(listMcpToolsForChatbot().map((t) => t.toolName)).toEqual(["ping", "stat"]);
|
|
unregisterMcpToolForChatbot("ping");
|
|
expect(listMcpToolsForChatbot().map((t) => t.toolName)).toEqual(["stat"]);
|
|
});
|
|
|
|
it("ExternalToolsProvider.list returns the registered tools (tenant-aware boundary)", async () => {
|
|
registerMcpToolForChatbot({ toolName: "ping", description: "ping" });
|
|
const provider = createMcpExternalToolsProvider();
|
|
const tools = await provider.list("tenant-a");
|
|
expect(tools).toEqual([{ toolName: "ping", description: "ping" }]);
|
|
});
|
|
|
|
it("ExternalToolsProvider.invoke forwards tenant + user to the tool invoker", async () => {
|
|
const invoke = vi.fn(async (inputs, ctx) => ({ ok: true, ctx, inputs }));
|
|
registerMcpToolForChatbot({ toolName: "ping", description: "ping", invoke });
|
|
const provider = createMcpExternalToolsProvider();
|
|
const out = await provider.invoke({ tenantId: "tenant-a", userId: "u1", toolName: "ping", inputs: { hi: 1 } });
|
|
expect(invoke).toHaveBeenCalledOnce();
|
|
expect(invoke).toHaveBeenCalledWith({ hi: 1 }, { tenantId: "tenant-a", userId: "u1" });
|
|
expect(out).toMatchObject({ ok: true });
|
|
});
|
|
|
|
it("invoke throws when the tool is not registered (no LLM-driven impersonation)", async () => {
|
|
const provider = createMcpExternalToolsProvider();
|
|
await expect(
|
|
provider.invoke({ tenantId: "tenant-a", userId: "u1", toolName: "unknown", inputs: {} }),
|
|
).rejects.toThrow(/not registered/);
|
|
});
|
|
|
|
it("invoke returns a structured not-invocable payload for read-only tools", async () => {
|
|
registerMcpToolForChatbot({ toolName: "ping", description: "ping" });
|
|
const provider = createMcpExternalToolsProvider();
|
|
const out = await provider.invoke({ tenantId: "tenant-a", userId: "u1", toolName: "ping", inputs: {} });
|
|
expect(out).toMatchObject({ status: "not-invocable", toolName: "ping" });
|
|
});
|
|
});
|