Opik MCP Server

Official
import { expect, jest, test, describe, beforeEach, afterEach } from '@jest/globals'; import { SSEServerTransport } from '../../src/transports/sse-transport.js'; import { startServerWithTransport } from '../../src/mcp-server.js'; import fetch from 'node-fetch'; import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js'; // Mock the fs module jest.mock('fs', () => ({ appendFileSync: jest.fn(), })); // Increase the timeout for integration tests jest.setTimeout(30000); // Define debug function const debug = (message: string) => { console.log(`[DEBUG] ${message}`); }; describe('MCP Server with SSE Transport Integration', () => { let transport: SSEServerTransport; // Keep the server variable for clarity even if not directly used in test // The server is needed to handle MCP requests /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ let server: any; // Using any type to avoid import issues const testPort = 4501; // Using a high port number to avoid conflicts // Use a different port for each test to avoid conflicts let currentPort: number; beforeEach(async () => { // Generate a unique port for each test currentPort = testPort + Math.floor(Math.random() * 100); debug(`Setting up test environment using port ${currentPort}`); transport = new SSEServerTransport({ port: currentPort }); // Start the server with SSE transport debug('Starting SSE transport'); await transport.start(); debug('Transport started, connecting MCP server'); server = await startServerWithTransport(transport); debug('MCP server connected to transport'); }); afterEach(async () => { debug('Cleaning up test environment'); // The server object doesn't have a disconnect method, // but the transport will handle clean up debug('Closing SSE transport'); try { await transport.close(); debug('Transport closed successfully'); } catch (err) { debug(`Error closing transport: ${err}`); } }); test('server health check should return status ok', async () => { debug(`Testing health check at http://localhost:${currentPort}/health`); const response = await fetch(`http://localhost:${currentPort}/health`); const data = (await response.json()) as { status: string }; debug(`Health check response: ${JSON.stringify(data)}`); expect(response.status).toBe(200); expect(data.status).toBe('ok'); }); test('server should respond to basic MCP requests', async () => { // Create a test message for the server info method const testMessage: JSONRPCMessage = { jsonrpc: '2.0', id: 'test-request', method: 'mcp__get_server_info', params: {}, }; debug(`Sending MCP request to http://localhost:${currentPort}/send`); debug(`Request payload: ${JSON.stringify(testMessage)}`); // Send the message to the server const response = await fetch(`http://localhost:${currentPort}/send`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(testMessage), }); // Verify the request was accepted const data = (await response.json()) as { status: string }; debug(`Response status: ${response.status}, body: ${JSON.stringify(data)}`); expect(response.status).toBe(200); expect(data.status).toBe('success'); }); test('server should handle invalid requests gracefully', async () => { // Create an invalid message (missing required fields) const invalidMessage = { // Missing jsonrpc and id fields method: 'invalid_method', }; // Send the message to the server const response = await fetch(`http://localhost:${currentPort}/send`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(invalidMessage), }); // The server should accept the message but handle errors internally // The exact behavior might vary, but we should get a successful response expect(response.status).toBe(200); }); });