Skip to main content
Glama

1MCP Server

stdio-errors.test.ts5.65 kB
import { ConfigBuilder, ProtocolValidator, TestProcessManager } from '@test/e2e/utils/index.js'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; describe('Stdio Transport Error Handling E2E', () => { let processManager: TestProcessManager; let configBuilder: ConfigBuilder; let configPath: string; beforeEach(async () => { processManager = new TestProcessManager(); configBuilder = new ConfigBuilder(); }); afterEach(async () => { await processManager.cleanup(); configBuilder.cleanup(); }); it('should handle invalid server configurations', async () => { // Test invalid command configuration configPath = configBuilder .enableStdioTransport() .addStdioServer('nonexistent-server', 'nonexistent-command', ['--invalid-arg'], ['test', 'invalid']) .writeToFile(); expect(configPath).toBeDefined(); // Test that we can still create and validate the config const config = configBuilder.build(); expect(config.servers).toHaveLength(1); expect(config.servers[0].name).toBe('nonexistent-server'); }); it('should handle process startup failures gracefully', async () => { // Test configuration validation instead of actual process startup const invalidConfig = { command: '', args: ['--invalid'], timeout: 1000, }; // Test that empty command is rejected expect(invalidConfig.command).toBe(''); expect(invalidConfig.args).toEqual(['--invalid']); // Test that process manager doesn't have the non-started process expect(processManager.isProcessRunning('never-started-process')).toBe(false); expect(processManager.getProcess('never-started-process')).toBeUndefined(); }); it('should validate error message formats', async () => { // Test various error formats const validErrors = [ { code: -32700, message: 'Parse error' }, { code: -32600, message: 'Invalid Request' }, { code: -32601, message: 'Method not found' }, { code: -32602, message: 'Invalid params' }, { code: -32603, message: 'Internal error' }, ]; validErrors.forEach((error) => { const validation = ProtocolValidator.validateError(error); expect(validation.valid).toBe(true); expect(validation.errors).toHaveLength(0); }); // Test invalid error formats const invalidErrors = [ { message: 'Missing code' }, { code: 'invalid', message: 'Non-numeric code' }, { code: -32700 }, // Missing message ]; invalidErrors.forEach((error) => { const validation = ProtocolValidator.validateError(error); expect(validation.valid).toBe(false); expect(validation.errors.length).toBeGreaterThan(0); }); }); it('should handle timeout scenarios', async () => { // Test process timeout handling const processInfo = await processManager.startProcess('sleep-process', { command: 'sleep', args: ['0.1'], // Sleep for 100ms timeout: 1000, // Reasonable timeout startupTimeout: 2000, // Reasonable startup timeout }); expect(processInfo.pid).toBeGreaterThan(0); expect(processManager.isProcessRunning('sleep-process')).toBe(true); // Wait for process to complete naturally await new Promise((resolve) => setTimeout(resolve, 200)); // Process should have completed by now expect(processManager.isProcessRunning('sleep-process')).toBe(false); }); it('should handle malformed JSON-RPC requests', async () => { // Test malformed JSON-RPC validation const malformedRequests = [ { jsonrpc: '1.0', id: 1, method: 'test' }, // Wrong version { jsonrpc: '2.0', id: 1 }, // Missing method { jsonrpc: '2.0', id: 1, method: 123 }, // Method is not a string { jsonrpc: '2.0', id: 1, method: 'test', params: 'invalid' }, // Params not an object ]; malformedRequests.forEach((request) => { const validation = ProtocolValidator.validateRequest(request); expect(validation.valid).toBe(false); expect(validation.errors.length).toBeGreaterThan(0); }); // Test some requests that should be valid const validRequests = [ { jsonrpc: '2.0', id: 1, method: 'test' }, { jsonrpc: '2.0', method: 'notification' }, // Notification without id { jsonrpc: '2.0', id: 1, method: 'test', params: {} }, ]; validRequests.forEach((request) => { const validation = ProtocolValidator.validateRequest(request); expect(validation.valid).toBe(true); }); }); it('should handle configuration cleanup on errors', async () => { // Test that configs are properly cleaned up even when errors occur const tempConfigPath = configBuilder .enableStdioTransport() .addStdioServer('temp-server', 'echo', ['test'], ['temp']) .writeToFile(); expect(tempConfigPath).toBeDefined(); // Simulate error condition and cleanup configBuilder.cleanup(); // Config should be cleaned up properly expect(tempConfigPath.endsWith('.json')).toBe(true); }); it('should validate MCP error codes', async () => { // Test MCP-specific error codes and formats const mcpErrors = [ { code: -32000, message: 'Server error', data: { type: 'timeout' } }, { code: -32001, message: 'Application error', data: { details: 'Custom error' } }, { code: -32002, message: 'Transport error', data: { transport: 'stdio' } }, ]; mcpErrors.forEach((error) => { const validation = ProtocolValidator.validateError(error); expect(validation.valid).toBe(true); expect(validation.errors).toHaveLength(0); }); }); });

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/1mcp-app/agent'

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