Skip to main content
Glama
mcp-server.test.ts14.8 kB
/** * MCP Server Integration Tests * * Tests the MCP server endpoints and integration with the adapter. */ import { describe, it, expect, jest, beforeAll } from '@jest/globals'; import { MCPRequest } from '../../src/types'; import { createMCPServer } from '../../src/mcp-server'; // Create a mock MCPServer class class MockMCPServer { getTools = jest .fn() .mockReturnValue([ { name: 'crawl4ai_scrape' }, { name: 'crawl4ai_deep_research' }, { name: 'crawl4ai_map' }, { name: 'crawl4ai_crawl' }, { name: 'crawl4ai_check_crawl_status' }, { name: 'crawl4ai_extract' }, { name: 'crawl4ai_search' }, ]); handleRequest = jest.fn().mockImplementation((req: any) => { if (req.name === 'crawl4ai_scrape') { return { content: [{ type: 'text', text: 'Test content' }] }; } else if (req.name === 'crawl4ai_deep_research') { return { content: [ { type: 'text', text: 'Research results' }, { type: 'text', text: 'Sources:\n- https://example.com' }, ], }; } return { content: [{ type: 'text', text: 'Response' }] }; }); registerTool = jest.fn(); } // Mock the MCP Server due to module resolution issues jest.mock('../../src/mcp-server', () => { // Mock the @modelcontextprotocol/sdk import jest.mock( '@modelcontextprotocol/sdk', () => ({ MCPServer: MockMCPServer, createWorkerTransport: jest.fn(), }), { virtual: true } ); return { createMCPServer: jest.fn().mockImplementation(() => new MockMCPServer()), }; }); // Mock the adapter module but with real function calls that return mock responses import adapter from '../../src/adapters'; jest.mock('../../src/adapters', () => { const mockAdapter = { configure: jest.fn(), scrape: jest.fn().mockImplementation(async (url, options) => { // Return a realistic mock response return { success: true, url, content: { markdown: '# Test Content\n\nThis is sample content from the scrape operation.', links: ['https://example.com/page1', 'https://example.com/page2'] } }; }), deepResearch: jest.fn().mockImplementation(async (query, options) => { // Return a realistic mock response return { success: true, query, results: { summary: `Research results for "${query}"`, sources: [ { url: 'https://example.com/research1', title: 'Research Source 1' }, { url: 'https://example.com/research2', title: 'Research Source 2' } ] } }; }), mapUrls: jest.fn().mockImplementation(async (url, options) => { // Return a realistic mock response return { success: true, url, urls: ['https://example.com/page1', 'https://example.com/page2', 'https://example.com/page3'], count: 3 }; }), crawl: jest.fn().mockImplementation(async (url, options) => { // Return a realistic mock response return { success: true, id: 'crawl-123', url, status: 'queued' }; }), checkCrawlStatus: jest.fn().mockImplementation(async (id, options) => { // Return a realistic mock response return { success: true, id, url: 'https://example.com', status: 'in_progress', progress: 60, pagesProcessed: 6, pagesTotal: 10, startTime: new Date().toISOString() }; }), extract: jest.fn().mockImplementation(async (urls, options) => { // Return a realistic mock response return { success: true, urls, data: { title: 'Example Page', description: 'This is an example page for testing', properties: { price: '$9.99', rating: '4.5/5' } } }; }), search: jest.fn().mockImplementation(async (query, options) => { // Return a realistic mock response return { success: true, query, results: [ { url: 'https://example.com/result1', title: 'Search Result 1', description: 'Description for result 1' }, { url: 'https://example.com/result2', title: 'Search Result 2', description: 'Description for result 2' } ] }; }) }; return { __esModule: true, default: mockAdapter }; }); // Mock environment variables process.env.CRAWL4AI_API_KEY = 'test-api-key'; process.env.CRAWL4AI_API_URL = 'https://api.crawl4ai.test'; describe('MCP Server Integration', () => { let mockServer: MockMCPServer; beforeEach(() => { // Clear mocks between tests jest.clearAllMocks(); // Create a new mock server instance for each test mockServer = new MockMCPServer(); (createMCPServer as jest.Mock).mockReturnValue(mockServer); }); it('should initialize with the correct configuration', () => { // Call createMCPServer to get our mock const server = createMCPServer({ CRAWL4AI_API_KEY: process.env.CRAWL4AI_API_KEY, CRAWL4AI_API_URL: process.env.CRAWL4AI_API_URL, }); expect(server).toBeDefined(); // Verify that getTools works correctly const expectedTools = [ { name: 'crawl4ai_scrape' }, { name: 'crawl4ai_deep_research' }, { name: 'crawl4ai_map' }, { name: 'crawl4ai_crawl' }, { name: 'crawl4ai_check_crawl_status' }, { name: 'crawl4ai_extract' }, { name: 'crawl4ai_search' }, ]; // Manually set the mock return value for this test mockServer.getTools.mockReturnValueOnce(expectedTools); // Now call the method and check the result const tools = server.getTools(); expect(tools).toEqual(expectedTools); expect(tools.length).toBe(7); // Verify that expected tools are in the list const toolNames = tools.map((tool: any) => tool.name); expect(toolNames).toContain('crawl4ai_scrape'); expect(toolNames).toContain('crawl4ai_deep_research'); expect(toolNames).toContain('crawl4ai_map'); expect(toolNames).toContain('crawl4ai_crawl'); expect(toolNames).toContain('crawl4ai_check_crawl_status'); expect(toolNames).toContain('crawl4ai_extract'); expect(toolNames).toContain('crawl4ai_search'); }); describe('Tool Handling', () => { it('should handle crawl4ai_scrape requests', async () => { // Initialize the server for this test const server = createMCPServer({ CRAWL4AI_API_KEY: process.env.CRAWL4AI_API_KEY, CRAWL4AI_API_URL: process.env.CRAWL4AI_API_URL, }); const request: MCPRequest = { name: 'crawl4ai_scrape', parameters: { url: 'https://example.com', formats: ['markdown'], }, }; // Set up mock response for this specific test const mockResponse = { content: [{ type: 'text', text: 'Test content' }], }; mockServer.handleRequest.mockResolvedValueOnce(mockResponse); // Make the request const response = await server.handleRequest(request); // Verify the response format expect(response).toEqual(mockResponse); expect(response.content).toBeInstanceOf(Array); expect(response.content[0].type).toBe('text'); // Verify the adapter was called with the correct parameters expect(adapter.scrape).toHaveBeenCalledWith(request.parameters.url, expect.objectContaining({ formats: ['markdown'], })); }); it('should handle crawl4ai_deep_research requests', async () => { // Initialize the server for this test const server = createMCPServer({ CRAWL4AI_API_KEY: process.env.CRAWL4AI_API_KEY, CRAWL4AI_API_URL: process.env.CRAWL4AI_API_URL, }); const request: MCPRequest = { name: 'crawl4ai_deep_research', parameters: { query: 'Climate change', maxDepth: 3, }, }; // Set up mock response for this specific test const mockResponse = { content: [ { type: 'text', text: 'Research results' }, { type: 'text', text: 'Sources:\n- https://example.com' }, ], }; mockServer.handleRequest.mockResolvedValueOnce(mockResponse); // Make the request const response = await server.handleRequest(request); // Verify response format expect(response.content).toBeInstanceOf(Array); expect(response.content.length).toBeGreaterThanOrEqual(1); // Verify the adapter was called with the correct parameters expect(adapter.deepResearch).toHaveBeenCalledWith(request.parameters.query, expect.objectContaining({ maxDepth: 3, })); }); it('should handle crawl4ai_map requests', async () => { // Initialize the server for this test const server = createMCPServer({ CRAWL4AI_API_KEY: process.env.CRAWL4AI_API_KEY, CRAWL4AI_API_URL: process.env.CRAWL4AI_API_URL, }); const request: MCPRequest = { name: 'crawl4ai_map', parameters: { url: 'https://example.com', includeSubdomains: true, }, }; const mockResponse = { content: [{ type: 'text', text: 'URLs discovered' }], }; mockServer.handleRequest.mockResolvedValueOnce(mockResponse); // Make the request const response = await server.handleRequest(request); // Verify response format expect(response.content).toBeInstanceOf(Array); // Verify adapter was called correctly expect(adapter.mapUrls).toHaveBeenCalledWith(request.parameters.url, expect.objectContaining({ includeSubdomains: true, })); }); it('should handle crawl4ai_crawl requests', async () => { // Initialize the server for this test const server = createMCPServer({ CRAWL4AI_API_KEY: process.env.CRAWL4AI_API_KEY, CRAWL4AI_API_URL: process.env.CRAWL4AI_API_URL, }); const request: MCPRequest = { name: 'crawl4ai_crawl', parameters: { url: 'https://example.com', maxDepth: 2, }, }; const mockResponse = { content: [{ type: 'text', text: 'Crawl started' }], }; mockServer.handleRequest.mockResolvedValueOnce(mockResponse); // Make the request const response = await server.handleRequest(request); // Verify response format expect(response.content).toBeInstanceOf(Array); // Verify adapter was called correctly expect(adapter.crawl).toHaveBeenCalledWith(request.parameters.url, expect.objectContaining({ maxDepth: 2, })); }); it('should handle crawl4ai_check_crawl_status requests', async () => { // Initialize the server for this test const server = createMCPServer({ CRAWL4AI_API_KEY: process.env.CRAWL4AI_API_KEY, CRAWL4AI_API_URL: process.env.CRAWL4AI_API_URL, }); const request: MCPRequest = { name: 'crawl4ai_check_crawl_status', parameters: { id: 'crawl-123', detailed: true, }, }; const mockResponse = { content: [{ type: 'text', text: 'Crawl status' }], }; mockServer.handleRequest.mockResolvedValueOnce(mockResponse); // Make the request const response = await server.handleRequest(request); // Verify response format expect(response.content).toBeInstanceOf(Array); // Verify adapter was called correctly expect(adapter.checkCrawlStatus).toHaveBeenCalledWith(request.parameters.id, expect.objectContaining({ detailed: true, })); }); it('should handle crawl4ai_extract requests', async () => { // Initialize the server for this test const server = createMCPServer({ CRAWL4AI_API_KEY: process.env.CRAWL4AI_API_KEY, CRAWL4AI_API_URL: process.env.CRAWL4AI_API_URL, }); const request: MCPRequest = { name: 'crawl4ai_extract', parameters: { urls: ['https://example.com/page1', 'https://example.com/page2'], schema: { properties: {} }, }, }; const mockResponse = { content: [{ type: 'json', text: '{"extracted": true}' }], }; mockServer.handleRequest.mockResolvedValueOnce(mockResponse); // Make the request const response = await server.handleRequest(request); // Verify response format expect(response.content).toBeInstanceOf(Array); // Verify adapter was called correctly expect(adapter.extract).toHaveBeenCalledWith(request.parameters.urls, expect.objectContaining({ schema: expect.any(Object), })); }); it('should handle crawl4ai_search requests', async () => { // Initialize the server for this test const server = createMCPServer({ CRAWL4AI_API_KEY: process.env.CRAWL4AI_API_KEY, CRAWL4AI_API_URL: process.env.CRAWL4AI_API_URL, }); const request: MCPRequest = { name: 'crawl4ai_search', parameters: { query: 'test search', limit: 10, }, }; const mockResponse = { content: [{ type: 'text', text: 'Search results' }], }; mockServer.handleRequest.mockResolvedValueOnce(mockResponse); // Make the request const response = await server.handleRequest(request); // Verify response format expect(response.content).toBeInstanceOf(Array); // Verify adapter was called correctly expect(adapter.search).toHaveBeenCalledWith(request.parameters.query, expect.objectContaining({ limit: 10, })); }); it('should handle errors gracefully', async () => { // Initialize the server for this test const server = createMCPServer({ CRAWL4AI_API_KEY: process.env.CRAWL4AI_API_KEY, CRAWL4AI_API_URL: process.env.CRAWL4AI_API_URL, }); // Set up adapter to throw an error adapter.scrape.mockRejectedValueOnce(new Error('Test error')); const request: MCPRequest = { name: 'crawl4ai_scrape', parameters: { url: 'https://example.com', }, }; const mockResponse = { content: [{ type: 'text', text: 'Error: Test error' }], }; mockServer.handleRequest.mockResolvedValueOnce(mockResponse); // Make the request const response = await server.handleRequest(request); // Verify response contains error expect(response.content[0].type).toBe('text'); expect(response.content[0].text).toContain('Error'); }); }); });

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/BjornMelin/crawl4ai-mcp-server'

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