Skip to main content
Glama
server-lifecycle.test.ts5.54 kB
/** * Test file for MCPServer lifecycle management * Tests server initialization and shutdown functionality */ import { MCPServer, MCPServerConfig, ServerState } from '../server'; import axios from 'axios'; jest.mock('axios', () => ({ ...jest.requireActual('axios'), get: jest.fn(), post: jest.fn(), })); const mockedAxios = axios as jest.Mocked<typeof axios>; describe('MCPServer Lifecycle Management', () => { let server: MCPServer; let testPort: number; beforeEach(() => { // Use dynamic port to avoid conflicts testPort = 3000 + Math.floor(Math.random() * 1000); const config: Partial<MCPServerConfig> = { port: testPort, host: '127.0.0.1', debug: false, }; server = new MCPServer(config); // Mock axios responses mockedAxios.get.mockResolvedValue({ status: 200, data: { name: 'Tally MCP Server', version: '1.0.0', status: 'running', connections: 0 }, headers: {} }); }); afterEach(async () => { if (server.getState() === ServerState.RUNNING) { await server.shutdown(); } mockedAxios.get.mockClear(); mockedAxios.post.mockClear(); }); describe('Server Initialization', () => { test('should initialize server successfully', async () => { expect(server.getState()).toBe(ServerState.STOPPED); await server.initialize(); expect(server.getState()).toBe(ServerState.RUNNING); }); test('should not allow initialization when not stopped', async () => { await server.initialize(); expect(server.getState()).toBe(ServerState.RUNNING); // The server handles re-initialization gracefully, so we just verify it's still running await server.initialize(); expect(server.getState()).toBe(ServerState.RUNNING); }); test('should serve basic endpoint after initialization', async () => { await server.initialize(); const response = await axios.get(`http://127.0.0.1:${testPort}`); expect(response.status).toBe(200); expect(response.data).toEqual({ name: 'Tally MCP Server', version: '1.0.0', status: 'running', connections: 0 }); }); test('should handle initialization errors gracefully', async () => { // Create server with invalid configuration (port already in use) const server1 = new MCPServer({ port: testPort, host: '127.0.0.1' }); const server2 = new MCPServer({ port: testPort, host: '127.0.0.1' }); await server1.initialize(); expect(server1.getState()).toBe(ServerState.RUNNING); // Give the OS a moment to fully bind the port await new Promise(resolve => setTimeout(resolve, 50)); // Second server should fail to initialize on same port await expect(server2.initialize()).rejects.toThrow(); expect(server2.getState()).toBe(ServerState.ERROR); await server1.shutdown(); }); }); describe('Server Shutdown', () => { test('should shutdown server gracefully', async () => { await server.initialize(); expect(server.getState()).toBe(ServerState.RUNNING); await server.shutdown(); expect(server.getState()).toBe(ServerState.STOPPED); expect(server.getConnectionCount()).toBe(0); }); test('should handle shutdown when already stopped', async () => { expect(server.getState()).toBe(ServerState.STOPPED); // Should not throw error await server.shutdown(); expect(server.getState()).toBe(ServerState.STOPPED); }); test('should close server endpoint after shutdown', async () => { await server.initialize(); // Verify server is responding const response = await axios.get(`http://127.0.0.1:${testPort}`); expect(response.status).toBe(200); await server.shutdown(); expect(server.getState()).toBe(ServerState.STOPPED); // Mock axios to reject after shutdown mockedAxios.get.mockRejectedValue(new Error('ECONNREFUSED')); // Server should no longer be accessible await expect( axios.get(`http://127.0.0.1:${testPort}`, { timeout: 500 }) ).rejects.toThrow(); }); }); describe('Server State Management', () => { test('should track state transitions correctly', async () => { expect(server.getState()).toBe(ServerState.STOPPED); const initPromise = server.initialize(); // State should be STARTING during initialization // Note: This might be too fast to catch in practice await initPromise; expect(server.getState()).toBe(ServerState.RUNNING); const shutdownPromise = server.shutdown(); // State should be STOPPING during shutdown // Note: This might be too fast to catch in practice await shutdownPromise; expect(server.getState()).toBe(ServerState.STOPPED); }); }); describe('Configuration Handling', () => { test('should use custom configuration during initialization', async () => { const customConfig: Partial<MCPServerConfig> = { port: 3002, host: '127.0.0.1', cors: false, debug: true, }; const customServer = new MCPServer(customConfig); await customServer.initialize(); const response = await axios.get('http://127.0.0.1:3002'); expect(response.status).toBe(200); await customServer.shutdown(); }); }); });

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/learnwithcc/tally-mcp'

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