Skip to main content
Glama

MCPMan

by semistrict
macros.test.ts8.25 kB
import { test, expect, describe } from "./test-fixtures.js"; describe("Macro Functionality Tests", () => { test("should successfully load and execute a valid macro", async ({ client }) => { const result = await client.callTool({ name: "invoke", arguments: { calls: [ { server: "macros", tool: "addNumbers", parameters: { a: 5, b: 3 }, }, ], }, }); const content = result.content as Array<{ type: string; text: string }>; const text = content[0]?.text || ""; expect(text).toContain("result"); expect(text).toContain("8"); }); test("should derive macro name from filename (kebab-case to camelCase)", async ({ client }) => { const result = await client.callTool({ name: "list_macros", arguments: {}, }); const content = result.content as Array<{ type: string; text: string }>; const data = JSON.parse(content[0]?.text || "{}"); const macroNames = data.macros.map((m: { name: string }) => m.name); // add-numbers.ts -> addNumbers expect(macroNames).toContain("addNumbers"); }); test("should validate macro arguments with Zod schema", async ({ client }) => { // Try to call addNumbers with wrong type (string instead of number) const result = await client.callTool({ name: "invoke", arguments: { calls: [ { server: "macros", tool: "addNumbers", parameters: { a: "not a number", b: 3 }, }, ], }, }); const content = result.content as Array<{ type: string; text: string }>; const text = content[0]?.text || ""; // Should contain validation error expect(text).toContain("Error"); }); test("should handle optional parameters correctly", async ({ client }) => { // greet macro has optional 'greeting' parameter const result = await client.callTool({ name: "invoke", arguments: { calls: [ { server: "macros", tool: "greet", parameters: { name: "World" }, }, ], }, }); const content = result.content as Array<{ type: string; text: string }>; const text = content[0]?.text || ""; // Should use default greeting "Hello" expect(text).toContain("Hello"); expect(text).toContain("World"); }); test("should use custom optional parameter when provided", async ({ client }) => { const result = await client.callTool({ name: "invoke", arguments: { calls: [ { server: "macros", tool: "greet", parameters: { name: "World", greeting: "Hi" }, }, ], }, }); const content = result.content as Array<{ type: string; text: string }>; const text = content[0]?.text || ""; // Should use custom greeting expect(text).toContain("Hi"); expect(text).toContain("World"); }); test("should include macros with syntax errors in error list", async ({ client }) => { const result = await client.callTool({ name: "list_macros", arguments: {}, }); const content = result.content as Array<{ type: string; text: string }>; const data = JSON.parse(content[0]?.text || "{}"); // Should have an errors array expect(data.errors).toBeDefined(); expect(Array.isArray(data.errors)).toBe(true); // Should have at least one error for broken-syntax.ts const brokenSyntaxError = data.errors.find((e: any) => e.name === "brokenSyntax"); expect(brokenSyntaxError).toBeDefined(); expect(brokenSyntaxError.error).toBeDefined(); }); test("should include macros that don't call defineMacro in error list", async ({ client }) => { const result = await client.callTool({ name: "list_macros", arguments: {}, }); const content = result.content as Array<{ type: string; text: string }>; const data = JSON.parse(content[0]?.text || "{}"); // Should have error for no-define.ts const noDefineError = data.errors.find((e: any) => e.name === "noDefine"); expect(noDefineError).toBeDefined(); expect(noDefineError.error).toContain("did not call defineMacro"); }); test("should throw error when executing macro that has runtime error", async ({ client }) => { const result = await client.callTool({ name: "invoke", arguments: { calls: [ { server: "macros", tool: "runtimeError", parameters: { value: "test" }, }, ], }, }); const content = result.content as Array<{ type: string; text: string }>; const text = content[0]?.text || ""; // Should contain error message expect(text).toContain("Error"); expect(text).toContain("Intentional runtime error"); }); test("should list only successfully loaded macros in macros array", async ({ client }) => { const result = await client.callTool({ name: "list_macros", arguments: {}, }); const content = result.content as Array<{ type: string; text: string }>; const data = JSON.parse(content[0]?.text || "{}"); // Only successfully loaded macros should be in the macros array const macroNames = data.macros.map((m: { name: string }) => m.name); // These should be present (valid macros) expect(macroNames).toContain("addNumbers"); expect(macroNames).toContain("greet"); expect(macroNames).toContain("runtimeError"); // Loads successfully, fails at runtime // These should NOT be in macros array (they failed to load) expect(macroNames).not.toContain("brokenSyntax"); expect(macroNames).not.toContain("noDefine"); }); test("should provide informative error messages", async ({ client }) => { const result = await client.callTool({ name: "list_macros", arguments: {}, }); const content = result.content as Array<{ type: string; text: string }>; const data = JSON.parse(content[0]?.text || "{}"); // Check that errors have necessary fields for (const error of data.errors) { expect(error.name).toBeDefined(); expect(error.path).toBeDefined(); expect(error.error).toBeDefined(); expect(typeof error.name).toBe("string"); expect(typeof error.path).toBe("string"); expect(typeof error.error).toBe("string"); } }); test("should load macros from multiple roots", async ({ client }) => { const result = await client.callTool({ name: "list_macros", arguments: {}, }); const content = result.content as Array<{ type: string; text: string }>; const data = JSON.parse(content[0]?.text || "{}"); const macroNames = data.macros.map((m: { name: string }) => m.name); // addNumbers is from root1, greet is from root2 expect(macroNames).toContain("addNumbers"); expect(macroNames).toContain("greet"); // Verify they have different paths const addNumbers = data.macros.find((m: any) => m.name === "addNumbers"); const greet = data.macros.find((m: any) => m.name === "greet"); expect(addNumbers.modulePath).toContain("root1"); expect(greet.modulePath).toContain("root2"); }); test("should include description in macro definition", async ({ client }) => { const result = await client.callTool({ name: "list_macros", arguments: {}, }); const content = result.content as Array<{ type: string; text: string }>; const data = JSON.parse(content[0]?.text || "{}"); const addNumbers = data.macros.find((m: any) => m.name === "addNumbers"); expect(addNumbers.description).toBe("Add two numbers together"); }); test("should throw error when invoking non-existent macro", async ({ client }) => { const result = await client.callTool({ name: "invoke", arguments: { calls: [ { server: "macros", tool: "nonExistentMacro", parameters: {}, }, ], }, }); const content = result.content as Array<{ type: string; text: string }>; const text = content[0]?.text || ""; expect(text).toContain("Error"); expect(text).toContain("not found"); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/semistrict/mcpman'

If you have feedback or need assistance with the MCP directory API, please join our Discord server