UNPKG

vibe-coder-mcp

Version:

Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.

110 lines (109 loc) 5.25 kB
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { z } from 'zod'; import { registerTool, executeTool, clearRegistryForTesting } from './toolRegistry.js'; import logger from '../../logger.js'; vi.mock('../../logger.js', () => ({ default: { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn(), } })); const mockConfig = { baseUrl: 'test', apiKey: 'test', geminiModel: 'test', perplexityModel: 'test' }; const mockSuccessExecutor = vi.fn(); const mockErrorExecutor = vi.fn(); const mockThrowingExecutor = vi.fn(); const successToolSchemaShape = { message: z.string() }; const errorToolSchemaShape = { id: z.number() }; const throwingToolSchemaShape = {}; const successToolDef = { name: 'successTool', description: 'A tool that always succeeds', inputSchema: successToolSchemaShape, executor: mockSuccessExecutor, }; const errorToolDef = { name: 'errorTool', description: 'A tool that returns an error result', inputSchema: errorToolSchemaShape, executor: mockErrorExecutor, }; const throwingToolDef = { name: 'throwingTool', description: 'A tool executor that throws', inputSchema: throwingToolSchemaShape, executor: mockThrowingExecutor, }; describe('Tool Registry Integration (executeTool)', () => { beforeEach(() => { process.env.NODE_ENV = 'test'; clearRegistryForTesting(); mockSuccessExecutor.mockReset().mockResolvedValue({ content: [{ type: 'text', text: 'Success!' }], isError: false, }); mockErrorExecutor.mockReset().mockResolvedValue({ content: [{ type: 'text', text: 'Executor failed' }], isError: true, errorDetails: { type: 'MockExecutorError', message: 'Executor failed' } }); mockThrowingExecutor.mockReset().mockRejectedValue(new Error('Unexpected throw')); vi.mocked(logger.info).mockClear(); vi.mocked(logger.debug).mockClear(); vi.mocked(logger.warn).mockClear(); vi.mocked(logger.error).mockClear(); registerTool(successToolDef); registerTool(errorToolDef); registerTool(throwingToolDef); }); afterEach(() => { clearRegistryForTesting(); }); it('should execute a registered tool successfully with valid params', async () => { const params = { message: 'hello' }; const result = await executeTool('successTool', params, mockConfig); expect(result.isError).toBe(false); expect(result.content?.[0]?.text).toBe('Success!'); expect(mockSuccessExecutor).toHaveBeenCalledTimes(1); expect(mockSuccessExecutor).toHaveBeenCalledWith(params, mockConfig, undefined); expect(vi.mocked(logger.error)).not.toHaveBeenCalled(); }); it('should return error result if executor returns isError: true', async () => { const params = { id: 123 }; const result = await executeTool('errorTool', params, mockConfig); expect(result.isError).toBe(true); expect(result.content?.[0]?.text).toBe('Executor failed'); expect(result.errorDetails).toBeDefined(); expect(result.errorDetails?.type).toBe('MockExecutorError'); expect(mockErrorExecutor).toHaveBeenCalledTimes(1); expect(mockErrorExecutor).toHaveBeenCalledWith(params, mockConfig, undefined); expect(vi.mocked(logger.error)).not.toHaveBeenCalled(); }); it('should return error result if executor throws an error', async () => { const params = {}; const result = await executeTool('throwingTool', params, mockConfig); expect(result.isError).toBe(true); expect(result.content?.[0]?.text).toContain("Unexpected error in tool 'throwingTool': Unexpected throw"); expect(result.errorDetails).toBeDefined(); expect(result.errorDetails?.type).toBe('Error'); expect(mockThrowingExecutor).toHaveBeenCalledTimes(1); expect(vi.mocked(logger.error)).toHaveBeenCalledWith(expect.objectContaining({ tool: 'throwingTool' }), expect.stringContaining("Error during execution")); }); it('should return validation error result for invalid params', async () => { const invalidParams = { message: 123 }; const result = await executeTool('successTool', invalidParams, mockConfig); expect(result.isError).toBe(true); expect(result.content?.[0]?.text).toContain("Input validation failed for tool 'successTool'"); expect(result.errorDetails).toBeDefined(); expect(result.errorDetails?.type).toBe('ValidationError'); expect(mockSuccessExecutor).not.toHaveBeenCalled(); expect(vi.mocked(logger.error)).toHaveBeenCalledWith(expect.objectContaining({ tool: 'successTool' }), 'Tool parameter validation failed.'); }); it('should return error result for unregistered tool', async () => { const result = await executeTool('nonExistentTool', {}, mockConfig); expect(result.isError).toBe(true); expect(result.content?.[0]?.text).toBe('Error: Tool "nonExistentTool" not found.'); expect(vi.mocked(logger.error)).toHaveBeenCalledWith('Tool "nonExistentTool" not found in registry.'); }); });