Skip to main content
Glama
mcp.test.ts3.1 kB
import { z } from 'zod'; import { globalErrorHandler } from '@/middleware/global-error-handler'; import { type ToolResponse, runTool } from '@/utils/mcp'; const makeMockLogger = () => { const mock = { generateRequestId: jest.fn(() => '123-1'), logToolExecution: jest.fn(), debug: jest.fn(), info: jest.fn(), warn: jest.fn(), error: jest.fn(), logTeamCityRequest: jest.fn(), logLifecycle: jest.fn(), child: jest.fn(), }; mock.child.mockReturnValue(mock); return mock; }; let sharedLogger: ReturnType<typeof makeMockLogger>; jest.mock('@/utils/logger/index', () => ({ getLogger: () => { sharedLogger ??= makeMockLogger(); return sharedLogger; }, get logger() { sharedLogger ??= makeMockLogger(); return sharedLogger; }, debug: jest.fn(), info: jest.fn(), warn: jest.fn(), error: jest.fn(), })); sharedLogger ??= makeMockLogger(); jest.mock('@/middleware/error', () => ({ formatError: jest.fn((err: unknown) => ({ kind: 'zod', message: String(err) })), })); jest.mock('@/middleware/global-error-handler', () => ({ globalErrorHandler: { handleToolError: jest.fn((_err: unknown, _tool: string, _ctx?: unknown) => ({ kind: 'generic', msg: 'handled', })), }, })); describe('utils/mcp runTool', () => { it('runs tool successfully and logs execution (masks secrets)', async () => { const schema = z.object({ token: z.string(), n: z.number() }); const handler = jest.fn( async (_args: { token: string; n: number }): Promise<ToolResponse> => ({ success: true, content: [{ type: 'text', text: 'ok' }], }) ); const res = await runTool( 'echo', schema, handler, { token: 'secret', n: 2 }, { requestId: 'req-1', } ); expect(res.success).toBe(true); expect(handler).toHaveBeenCalledWith({ token: 'secret', n: 2 }); // Logger was called with masked token expect(sharedLogger.logToolExecution).toHaveBeenCalledWith( 'echo', expect.objectContaining({ token: '***', n: 2 }), { success: true, error: undefined }, expect.any(Number), expect.objectContaining({ requestId: 'req-1' }) ); }); it('returns formatted Zod error output when validation fails', async () => { const schema = z.object({ n: z.number() }); const handler = jest.fn(); const out = await runTool('sum', schema, handler, { n: 'bad' }); expect(out.success).toBe(true); // json() wrapper marks success true expect(out.content?.[0]?.text).toContain('zod'); expect(handler).not.toHaveBeenCalled(); }); it('routes generic errors through globalErrorHandler and returns json result', async () => { const schema = z.object({ x: z.string() }).nullable(); const handler = jest.fn(async () => { throw new Error('boom'); }); const out = await runTool('f', schema, handler, { x: '1' }); expect(out.success).toBe(true); expect(out.content?.[0]?.text).toContain('handled'); expect(globalErrorHandler.handleToolError).toHaveBeenCalled(); }); });

Latest Blog Posts

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/Daghis/teamcity-mcp'

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