/**
* Integration Tests: MCP Server Lifecycle
*
* Tests the MCP server initialization, request handling, and shutdown.
*/
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { setupTestMCPServer, type TestMCPServer } from '../helpers/test-server.js';
describe('MCP Server Lifecycle', () => {
let testServer: TestMCPServer;
beforeEach(async () => {
testServer = await setupTestMCPServer();
});
afterEach(async () => {
await testServer.close();
vi.restoreAllMocks();
});
describe('Server initialization', () => {
it('should create server with correct metadata', () => {
expect(testServer.server).toBeDefined();
// Server name and version are set during construction
});
it('should have tools capability enabled', async () => {
const tools = await testServer.listTools();
expect(tools).toBeDefined();
expect(Array.isArray(tools)).toBe(true);
});
it('should have resources capability enabled', async () => {
const resources = await testServer.listResources();
expect(resources).toBeDefined();
expect(Array.isArray(resources)).toBe(true);
});
it('should have prompts capability enabled', async () => {
const prompts = await testServer.listPrompts();
expect(prompts).toBeDefined();
expect(Array.isArray(prompts)).toBe(true);
});
});
describe('Request handlers', () => {
it('should handle tools/list request', async () => {
const tools = await testServer.listTools();
expect(tools.length).toBeGreaterThan(0);
expect(tools[0]).toHaveProperty('name');
expect(tools[0]).toHaveProperty('description');
expect(tools[0]).toHaveProperty('inputSchema');
});
it('should handle tools/call request for valid tool', async () => {
testServer.mockClient.mockResponse(
'POST',
'/objects/companies/records/query',
{
data: {
data: [],
next_page: null,
},
}
);
const result = await testServer.callTool('search_companies', {
query: 'test',
});
expect(result).toBeDefined();
expect(result.content).toBeDefined();
expect(Array.isArray(result.content)).toBe(true);
});
it('should handle resources/list request', async () => {
const resources = await testServer.listResources();
expect(resources.length).toBeGreaterThan(0);
expect(resources[0]).toHaveProperty('uri');
expect(resources[0]).toHaveProperty('name');
});
it('should handle prompts/list request', async () => {
const prompts = await testServer.listPrompts();
// Prompts registry is currently empty (no prompts implemented yet)
expect(Array.isArray(prompts)).toBe(true);
});
});
describe('Error handling', () => {
it('should throw McpError for unknown tool', async () => {
await expect(
testServer.callTool('nonexistent_tool', {})
).rejects.toThrow('Tool not found: nonexistent_tool');
});
it('should throw McpError for unknown resource', async () => {
await expect(
testServer.readResource('file:///nonexistent')
).rejects.toThrow('Resource not found');
});
it('should throw McpError for unknown prompt', async () => {
await expect(
testServer.getPrompt('nonexistent_prompt', {})
).rejects.toThrow('Prompt not found');
});
});
describe('Graceful shutdown', () => {
it('should close server without errors', async () => {
await expect(testServer.close()).resolves.not.toThrow();
});
it('should allow multiple close calls', async () => {
await testServer.close();
await expect(testServer.close()).resolves.not.toThrow();
});
});
});