openclaw / src /mcp /plugin-tools-mcp-client.test.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
5c2a829 verified
Raw History Blame Contribute Delete
3.16 kB
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();
}
});
});