File size: 3,155 Bytes
5c2a829 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
import { describe, expect, it, vi } from "vitest";
import type { AnyAgentTool } from "../agents/tools/common.js";
import { createPluginToolsMcpServer } from "./plugin-tools-serve.js";
describe("plugin tools MCP client bridge", () => {
it("lists and calls a plugin tool through a real MCP client", async () => {
const execute = vi.fn().mockResolvedValue({
content: [{ type: "text", text: "MCP fact: the codename is ORBIT-9." }],
});
const tool = {
name: "memory_search",
description: "Search memory",
parameters: {
type: "object",
properties: {
query: { type: "string" },
maxResults: { type: "number" },
},
required: ["query"],
},
execute,
} as unknown as AnyAgentTool;
const server = createPluginToolsMcpServer({
tools: [tool],
});
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
const client = new Client(
{ name: "plugin-tools-test-client", version: "0.0.0" },
{ capabilities: {} },
);
await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
try {
const listed = await client.listTools();
expect(listed.tools.map((listedTool) => listedTool.name)).toContain("memory_search");
const result = await client.callTool({
name: "memory_search",
arguments: { query: "ORBIT-9 codename", maxResults: 3 },
});
expect(execute).toHaveBeenCalledWith(
expect.stringMatching(
/^mcp-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u,
),
{ query: "ORBIT-9 codename", maxResults: 3 },
expect.any(AbortSignal),
undefined,
);
expect(JSON.stringify(result.content)).toContain("ORBIT-9");
} finally {
await client.close();
await server.close();
}
});
it("delivers resolved tool failures as MCP errors", async () => {
const content = [{ type: "text", text: "backend unavailable" }];
const tool = {
name: "memory_search",
description: "Search memory",
parameters: { type: "object", properties: {} },
execute: vi.fn().mockResolvedValue({
content,
details: { status: "failed", error: "backend unavailable" },
}),
} as unknown as AnyAgentTool;
const server = createPluginToolsMcpServer({
tools: [tool],
});
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
const client = new Client(
{ name: "plugin-tools-error-test-client", version: "0.0.0" },
{ capabilities: {} },
);
await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
try {
const result = await client.callTool({ name: "memory_search", arguments: {} });
expect(result.content).toEqual(content);
expect(result.isError).toBe(true);
} finally {
await client.close();
await server.close();
}
});
});
|