Skip to main content
Glama

1MCP Server

performance.test.ts29.8 kB
import { ConfigBuilder, ProtocolValidator, TestProcessManager } from '@test/e2e/utils/index.js'; import { join } from 'path'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; describe('Performance Infrastructure Integration E2E', () => { let processManager: TestProcessManager; let configBuilder: ConfigBuilder; let configPath: string; beforeEach(async () => { processManager = new TestProcessManager(); configBuilder = new ConfigBuilder(); const fixturesPath = join(__dirname, '../fixtures'); configPath = configBuilder .enableStdioTransport() .enableHttpTransport(3000) .enableAuth('test-client-id', 'test-client-secret') .addStdioServer('echo-1', 'node', [join(fixturesPath, 'echo-server.js')], ['test', 'echo', 'fast']) .addStdioServer('echo-2', 'node', [join(fixturesPath, 'echo-server.js')], ['test', 'echo', 'fast']) .addStdioServer('echo-3', 'node', [join(fixturesPath, 'echo-server.js')], ['test', 'echo', 'fast']) .addStdioServer( 'slow-server', 'node', [join(fixturesPath, 'slow-server.js'), '--defaultDelay=50'], ['test', 'slow'], ) .writeToFile(); }); afterEach(async () => { await processManager.cleanup(); configBuilder.cleanup(); }); it('should create valid performance testing configuration', async () => { // Test that performance configuration builds correctly expect(configPath).toBeDefined(); expect(configPath.endsWith('.json')).toBe(true); const config = configBuilder.build(); expect(config.transport?.stdio).toBe(true); expect(config.transport?.http?.port).toBe(3000); expect(config.servers).toHaveLength(4); // Verify server distribution const echoServers = config.servers.filter((s) => s.tags?.includes('echo')); const slowServers = config.servers.filter((s) => s.tags?.includes('slow')); expect(echoServers).toHaveLength(3); expect(slowServers).toHaveLength(1); }); it('should validate high-frequency request patterns', async () => { // Test high-frequency request simulation structures const requestBatch = Array.from({ length: 100 }, (_, i) => ({ id: i, method: 'echo/request', params: { requestId: i, timestamp: Date.now() }, expected_response_time: 50, // ms })); expect(requestBatch).toHaveLength(100); requestBatch.forEach((req, index) => { expect(req.id).toBe(index); expect(req.method).toBe('echo/request'); expect(req.params.requestId).toBe(index); expect(typeof req.params.timestamp).toBe('number'); expect(req.expected_response_time).toBeGreaterThan(0); }); }); it('should handle concurrent server request validation', async () => { // Test concurrent operation across multiple servers const serverNames = ['echo-1', 'echo-2', 'echo-3']; const requestsPerServer = 50; const operationPlan = serverNames.flatMap((serverName) => Array.from({ length: requestsPerServer }, (_, i) => ({ server: serverName, requestId: i, method: 'echo/request', timestamp: Date.now(), params: { server: serverName, requestId: i, concurrency_test: true, }, })), ); expect(operationPlan).toHaveLength(requestsPerServer * serverNames.length); // Verify distribution across servers const serverCounts = serverNames.reduce( (acc, name) => { acc[name] = operationPlan.filter((op) => op.server === name).length; return acc; }, {} as Record<string, number>, ); serverNames.forEach((name) => { expect(serverCounts[name]).toBe(requestsPerServer); }); }); it('should validate performance measurement structures', async () => { // Test performance metrics data structures const performanceTest = { test_name: 'stdio_throughput', start_time: Date.now(), duration: 10000, // 10 seconds request_count: 100, concurrent_connections: 10, expected_rps: 10, // requests per second timeout_threshold: 5000, }; const performanceResult = { test_name: 'stdio_throughput', total_requests: 100, successful_requests: 98, failed_requests: 2, actual_duration: 9750, actual_rps: 10.05, avg_response_time: 25, min_response_time: 15, max_response_time: 85, p95_response_time: 45, error_rate: 0.02, }; // Validate test structure expect(performanceTest.test_name).toBe('stdio_throughput'); expect(performanceTest.request_count).toBeGreaterThan(0); expect(performanceTest.expected_rps).toBeGreaterThan(0); // Validate result structure expect(performanceResult.total_requests).toBe(100); expect(performanceResult.successful_requests + performanceResult.failed_requests).toBe( performanceResult.total_requests, ); expect(performanceResult.actual_rps).toBeGreaterThan(0); expect(performanceResult.avg_response_time).toBeGreaterThan(0); expect(performanceResult.min_response_time).toBeLessThanOrEqual(performanceResult.avg_response_time); expect(performanceResult.max_response_time).toBeGreaterThanOrEqual(performanceResult.avg_response_time); expect(performanceResult.error_rate).toBeGreaterThanOrEqual(0); expect(performanceResult.error_rate).toBeLessThan(1); }); it('should handle large payload performance testing', async () => { // Test large payload handling structures const payloadSizes = [1, 10, 100, 1000]; // KB const payloadTests = payloadSizes.map((sizeKB) => ({ size_kb: sizeKB, payload: { message: `Large payload test - ${sizeKB}KB`, data: Array.from({ length: sizeKB * 10 }, (_, i) => ({ id: i, value: 'x'.repeat(100), // ~100 bytes per item })), }, expected_max_duration: 5000, // 5 seconds max expected_min_throughput: 1, // KB/s })); payloadTests.forEach((test) => { expect(test.size_kb).toBeGreaterThan(0); expect(test.payload.data).toHaveLength(test.size_kb * 10); expect(test.expected_max_duration).toBeGreaterThan(0); expect(test.expected_min_throughput).toBeGreaterThan(0); }); // Validate payload content payloadTests.forEach((test) => { const estimatedSize = JSON.stringify(test.payload).length; const expectedMinSize = test.size_kb * 1000; // Convert KB to bytes (rough estimate) expect(estimatedSize).toBeGreaterThan(expectedMinSize * 0.8); // Allow 20% variance }); }); it('should validate memory usage monitoring patterns', async () => { // Test memory monitoring structures const memoryBaseline = { rss: 50 * 1024 * 1024, // 50MB heapUsed: 30 * 1024 * 1024, // 30MB heapTotal: 40 * 1024 * 1024, // 40MB external: 5 * 1024 * 1024, // 5MB }; const memoryAfterLoad = { rss: 75 * 1024 * 1024, // 75MB heapUsed: 45 * 1024 * 1024, // 45MB heapTotal: 60 * 1024 * 1024, // 60MB external: 8 * 1024 * 1024, // 8MB }; const memoryGrowth = { rss_growth: memoryAfterLoad.rss - memoryBaseline.rss, heap_growth: memoryAfterLoad.heapUsed - memoryBaseline.heapUsed, growth_percentage: ((memoryAfterLoad.heapUsed - memoryBaseline.heapUsed) / memoryBaseline.heapUsed) * 100, }; expect(memoryBaseline.rss).toBeGreaterThan(0); expect(memoryAfterLoad.rss).toBeGreaterThan(memoryBaseline.rss); expect(memoryGrowth.rss_growth).toBeGreaterThan(0); expect(memoryGrowth.heap_growth).toBeGreaterThan(0); expect(memoryGrowth.growth_percentage).toBeGreaterThan(0); }); it('should handle timeout scenario validation', async () => { // Test timeout handling structures const timeoutTests = [ { delay: 100, timeout: 200, should_succeed: true }, { delay: 500, timeout: 1000, should_succeed: true }, { delay: 2000, timeout: 1500, should_succeed: false }, { delay: 5000, timeout: 3000, should_succeed: false }, ]; timeoutTests.forEach((test) => { expect(test.delay).toBeGreaterThan(0); expect(test.timeout).toBeGreaterThan(0); expect(typeof test.should_succeed).toBe('boolean'); if (test.should_succeed) { expect(test.delay).toBeLessThan(test.timeout); } else { expect(test.delay).toBeGreaterThan(test.timeout); } }); }); it('should validate connection pool efficiency patterns', async () => { // Test connection pool performance patterns const poolTest = { pool_size: 10, concurrent_requests: 20, sequential_requests: 20, connection_reuse: true, keep_alive: true, }; const poolResults = { sequential_duration: 2000, // ms concurrent_duration: 800, // ms connection_reuse_count: 15, new_connections_created: 5, efficiency_ratio: 800 / 2000, // concurrent vs sequential }; expect(poolTest.pool_size).toBeGreaterThan(0); expect(poolTest.concurrent_requests).toBeGreaterThan(0); expect(poolResults.concurrent_duration).toBeLessThan(poolResults.sequential_duration); expect(poolResults.efficiency_ratio).toBeLessThan(1); expect(poolResults.efficiency_ratio).toBeGreaterThan(0); expect(poolResults.connection_reuse_count + poolResults.new_connections_created).toBeLessThanOrEqual( poolTest.concurrent_requests, ); }); it('should handle startup performance validation', async () => { // Test startup performance structures const startupConfig = { server_count: 10, parallel_startup: true, startup_timeout: 15000, // 15 seconds expected_startup_time: 10000, // 10 seconds }; const startupResult = { total_servers: 10, successful_starts: 10, failed_starts: 0, actual_startup_time: 8500, average_startup_per_server: 850, parallel_efficiency: true, }; expect(startupConfig.server_count).toBe(10); expect(startupResult.successful_starts).toBe(startupConfig.server_count); expect(startupResult.failed_starts).toBe(0); expect(startupResult.actual_startup_time).toBeLessThan(startupConfig.startup_timeout); expect(startupResult.actual_startup_time).toBeLessThan(startupConfig.expected_startup_time); expect(startupResult.average_startup_per_server).toBe( startupResult.actual_startup_time / startupResult.total_servers, ); }); it('should validate resource cleanup efficiency', async () => { // Test resource cleanup performance const cleanupTest = { resource_count: 50, resource_types: ['temporary_files', 'process_handles', 'memory_allocations'], cleanup_strategy: 'graceful', max_cleanup_time: 10000, // 10 seconds }; const cleanupResult = { resources_cleaned: 50, cleanup_duration: 1250, cleanup_rate: 50 / (1250 / 1000), // resources per second memory_freed: 25 * 1024 * 1024, // 25MB handles_closed: 15, files_deleted: 10, }; expect(cleanupTest.resource_count).toBeGreaterThan(0); expect(cleanupResult.resources_cleaned).toBe(cleanupTest.resource_count); expect(cleanupResult.cleanup_duration).toBeLessThan(cleanupTest.max_cleanup_time); expect(cleanupResult.cleanup_rate).toBeGreaterThan(1); // At least 1 resource per second expect(cleanupResult.memory_freed).toBeGreaterThan(0); }); it('should handle process management performance', async () => { // Test process management performance const processTest = await processManager.startProcess('performance-test-process', { command: 'sleep', args: ['2'], timeout: 5000, }); expect(processTest.pid).toBeGreaterThan(0); expect(processManager.isProcessRunning('performance-test-process')).toBe(true); const stopStart = Date.now(); await processManager.stopProcess('performance-test-process'); const stopDuration = Date.now() - stopStart; expect(processManager.isProcessRunning('performance-test-process')).toBe(false); expect(stopDuration).toBeLessThan(5000); // Should stop quickly }); it('should validate load testing patterns', async () => { // Test load testing configuration structures const loadTest = { name: 'sustained_load_test', duration: 30000, // 30 seconds ramp_up_time: 5000, // 5 seconds steady_state_time: 20000, // 20 seconds ramp_down_time: 5000, // 5 seconds max_concurrent_users: 100, requests_per_user_per_second: 1, expected_total_requests: 2000, // Approximate }; const loadResult = { actual_duration: 30250, total_requests: 1987, successful_requests: 1965, failed_requests: 22, avg_response_time: 45, max_response_time: 1200, requests_per_second: 1987 / (30250 / 1000), error_rate: 22 / 1987, peak_concurrent_users: 98, }; expect(loadTest.duration).toBeGreaterThan(0); expect(loadTest.ramp_up_time + loadTest.steady_state_time + loadTest.ramp_down_time).toBe(loadTest.duration); expect(loadResult.total_requests).toBeGreaterThan(0); expect(loadResult.successful_requests + loadResult.failed_requests).toBe(loadResult.total_requests); expect(loadResult.error_rate).toBeLessThan(0.1); // Less than 10% error rate expect(loadResult.peak_concurrent_users).toBeLessThanOrEqual(loadTest.max_concurrent_users); }); it('should validate stress testing boundaries', async () => { // Test stress testing configuration const stressTest = { name: 'resource_exhaustion_test', memory_limit: 512 * 1024 * 1024, // 512MB cpu_limit: 0.8, // 80% connection_limit: 1000, request_rate_limit: 500, // requests per second expected_failure_point: { memory_usage: 0.9, // 90% of limit cpu_usage: 0.95, // 95% of limit active_connections: 0.8, // 80% of limit }, }; const stressResult = { peak_memory_usage: 460 * 1024 * 1024, // 460MB peak_cpu_usage: 0.85, // 85% peak_connections: 750, failure_point_reached: false, degradation_started_at: { memory_usage: 0.75, response_time_increase: 2.5, // 250% increase }, }; expect(stressTest.memory_limit).toBeGreaterThan(0); expect(stressTest.cpu_limit).toBeLessThanOrEqual(1); expect(stressResult.peak_memory_usage).toBeLessThan(stressTest.memory_limit); expect(stressResult.peak_cpu_usage).toBeLessThan(1); expect(stressResult.peak_connections).toBeLessThan(stressTest.connection_limit); }); it('should handle benchmark comparison validation', async () => { // Test benchmark comparison structures const benchmarks = { baseline: { version: '1.0.0', requests_per_second: 100, avg_response_time: 50, memory_usage: 30 * 1024 * 1024, error_rate: 0.01, }, current: { version: '1.1.0', requests_per_second: 120, avg_response_time: 45, memory_usage: 28 * 1024 * 1024, error_rate: 0.008, }, }; const comparison = { rps_improvement: (benchmarks.current.requests_per_second - benchmarks.baseline.requests_per_second) / benchmarks.baseline.requests_per_second, response_time_improvement: (benchmarks.baseline.avg_response_time - benchmarks.current.avg_response_time) / benchmarks.baseline.avg_response_time, memory_improvement: (benchmarks.baseline.memory_usage - benchmarks.current.memory_usage) / benchmarks.baseline.memory_usage, error_rate_improvement: (benchmarks.baseline.error_rate - benchmarks.current.error_rate) / benchmarks.baseline.error_rate, }; expect(comparison.rps_improvement).toBeGreaterThan(0); // Improved expect(comparison.response_time_improvement).toBeGreaterThan(0); // Improved expect(comparison.memory_improvement).toBeGreaterThan(0); // Improved expect(comparison.error_rate_improvement).toBeGreaterThan(0); // Improved }); it('should validate protocol performance patterns', async () => { // Test protocol-specific performance validation const protocolTests = [ { method: 'ping', expected_response_time: 10, payload_size: 50, }, { method: 'tools/list', expected_response_time: 100, payload_size: 1000, }, { method: 'resources/read', expected_response_time: 200, payload_size: 5000, }, ]; protocolTests.forEach((test) => { // Validate method format const validation = ProtocolValidator.validateMcpMethod(test.method); expect(validation.valid).toBe(true); expect(test.expected_response_time).toBeGreaterThan(0); expect(test.payload_size).toBeGreaterThan(0); }); // More complex methods should generally take longer expect(protocolTests[0].expected_response_time).toBeLessThan(protocolTests[1].expected_response_time); expect(protocolTests[1].expected_response_time).toBeLessThan(protocolTests[2].expected_response_time); }); it('should handle performance regression detection', async () => { // Test performance regression detection patterns const regressionTest = { test_name: 'response_time_regression', baseline_p95: 100, // ms current_p95: 150, // ms threshold_percentage: 0.2, // 20% increase is acceptable regression_detected: false, }; const regressionPercentage = (regressionTest.current_p95 - regressionTest.baseline_p95) / regressionTest.baseline_p95; regressionTest.regression_detected = regressionPercentage > regressionTest.threshold_percentage; expect(regressionPercentage).toBeGreaterThan(0.4); // 50% increase expect(regressionTest.regression_detected).toBe(true); expect(regressionTest.threshold_percentage).toBeGreaterThan(0); expect(regressionTest.threshold_percentage).toBeLessThan(1); }); it('should validate conditional logging performance optimization', async () => { // Test logging performance optimization benefits const { debugIf, isDebugEnabled } = await import('@src/logger/logger.js'); const iterationCount = 10000; const expensiveData = Array.from({ length: 1000 }, (_, i) => ({ id: i, value: 'x'.repeat(100) })); // Test traditional logger.debug() performance when debug is disabled const traditionalStart = performance.now(); for (let i = 0; i < iterationCount; i++) { // Simulate expensive operation that would happen with logger.debug() const _message = `Processing items: ${expensiveData.length} items`; const _meta = { itemIds: expensiveData.map((item) => item.id), totalSize: expensiveData.reduce((sum, item) => sum + item.value.length, 0), timestamp: Date.now(), }; // Note: We're not actually calling logger.debug() to avoid log pollution // but we're simulating the expense computation that would occur void _message; // Prevent unused variable warning void _meta; // Prevent unused variable warning } const traditionalDuration = performance.now() - traditionalStart; // Test debugIf() performance when debug is disabled const debugIfStart = performance.now(); for (let i = 0; i < iterationCount; i++) { debugIf(() => ({ message: `Processing items: ${expensiveData.length} items`, meta: { itemIds: expensiveData.map((item) => item.id), totalSize: expensiveData.reduce((sum, item) => sum + item.value.length, 0), timestamp: Date.now(), }, })); } const debugIfDuration = performance.now() - debugIfStart; // Validate performance benefits expect(debugIfDuration).toBeLessThan(traditionalDuration); expect(debugIfDuration / traditionalDuration).toBeLessThan(0.1); // At least 90% faster // Test that debug is actually disabled for this test expect(isDebugEnabled()).toBe(false); const performanceGain = ((traditionalDuration - debugIfDuration) / traditionalDuration) * 100; expect(performanceGain).toBeGreaterThan(80); // At least 80% performance improvement }); it('should validate logging error handling robustness', async () => { // Test that logging errors never crash the application const { debugIf, infoIf, warnIf } = await import('@src/logger/logger.js'); const errorScenarios = [ // Test malformed callback results { name: 'null_result', callback: () => null }, { name: 'undefined_result', callback: () => undefined }, { name: 'string_result', callback: () => 'not an object' }, { name: 'missing_message', callback: () => ({ meta: { test: true } }) }, // Test callback exceptions { name: 'throw_error', callback: () => { throw new Error('Test error'); }, }, { name: 'throw_string', callback: () => { throw 'String error'; }, }, { name: 'reference_error', callback: () => ({ message: (global as any).nonExistentVariable.toString() }) }, ]; // Test each error scenario doesn't crash the application errorScenarios.forEach((scenario) => { expect(() => { debugIf(scenario.callback as any); infoIf(scenario.callback as any); warnIf(scenario.callback as any); }).not.toThrow(); }); // Verify the functions still work correctly with valid inputs expect(() => { debugIf('Simple message'); debugIf(() => ({ message: 'Complex message', meta: { test: true } })); infoIf('Info message'); warnIf(() => ({ message: 'Warning message' })); }).not.toThrow(); }); it('should validate logging memory efficiency with high-frequency calls', async () => { // Test memory efficiency of conditional logging const { debugIf } = await import('@src/logger/logger.js'); const largeObject = Array.from({ length: 10000 }, (_, i) => ({ id: i, data: 'x'.repeat(1000), // 1KB per item = ~10MB total timestamp: Date.now(), metadata: { processed: false, retries: 0 }, })); const initialMemory = process.memoryUsage(); const iterationCount = 1000; // Perform high-frequency logging with large data const logStart = performance.now(); for (let i = 0; i < iterationCount; i++) { debugIf(() => ({ message: `Processing large dataset: iteration ${i}`, meta: { dataSize: largeObject.length, totalMemory: largeObject.reduce((sum, item) => sum + item.data.length, 0), iteration: i, sampleItems: largeObject.slice(0, 5), // Only include first 5 items }, })); } const logDuration = performance.now() - logStart; const finalMemory = process.memoryUsage(); const memoryGrowth = finalMemory.heapUsed - initialMemory.heapUsed; // Validate performance characteristics expect(logDuration).toBeLessThan(100); // Should complete quickly expect(memoryGrowth).toBeLessThan(1024 * 1024); // Less than 1MB memory growth // Verify no memory leaks by forcing garbage collection and checking again if (global.gc) { global.gc(); const afterGcMemory = process.memoryUsage(); const persistentGrowth = afterGcMemory.heapUsed - initialMemory.heapUsed; expect(persistentGrowth).toBeLessThan(512 * 1024); // Less than 512KB persistent growth } }); it('should validate structured metadata performance patterns', async () => { // Test structured metadata handling performance const { debugIf } = await import('@src/logger/logger.js'); const metadataScenarios = [ { name: 'shallow_metadata', generator: () => ({ simple: true, count: 100, timestamp: Date.now() }), }, { name: 'deep_metadata', generator: () => ({ level1: { level2: { level3: { data: Array.from({ length: 100 }, (_, i) => i), computed: Math.random() * 1000, }, }, }, }), }, { name: 'large_array_metadata', generator: () => ({ items: Array.from({ length: 1000 }, (_, i) => ({ id: i, value: Math.random() })), summary: 'Large array metadata', }), }, ]; const results = metadataScenarios.map((scenario) => { const start = performance.now(); const iterations = 1000; for (let i = 0; i < iterations; i++) { debugIf(() => ({ message: `Testing ${scenario.name} - iteration ${i}`, meta: scenario.generator(), })); } const duration = performance.now() - start; return { scenario: scenario.name, duration, averagePerCall: duration / iterations, }; }); // Validate that all scenarios complete efficiently results.forEach((result) => { expect(result.duration).toBeLessThan(50); // All scenarios under 50ms expect(result.averagePerCall).toBeLessThan(0.1); // Less than 0.1ms per call }); // Verify performance patterns are reasonable (allowing for environmental variance) const shallowResult = results.find((r) => r.scenario === 'shallow_metadata'); const deepResult = results.find((r) => r.scenario === 'deep_metadata'); const arrayResult = results.find((r) => r.scenario === 'large_array_metadata'); // Shallow metadata should be competitive with more complex scenarios // Allow for some variance due to system load, GC timing, etc. const performanceTolerance = 1.5; // 50% tolerance for performance variance expect(shallowResult!.duration).toBeLessThan(deepResult!.duration * performanceTolerance); expect(shallowResult!.duration).toBeLessThan(arrayResult!.duration * performanceTolerance); // But complex scenarios should still be slower on average const averageComplexDuration = (deepResult!.duration + arrayResult!.duration) / 2; expect(averageComplexDuration).toBeGreaterThan(shallowResult!.duration * 0.8); }); it('should validate callback purity and side effect prevention', async () => { // Test that callbacks are executed only when logging is enabled const { debugIf, isDebugEnabled } = await import('@src/logger/logger.js'); let callbackExecutionCount = 0; let sideEffectCount = 0; const iterationCount = 100; // Test with debug disabled (typical production scenario) for (let i = 0; i < iterationCount; i++) { debugIf(() => { callbackExecutionCount++; // This callback should NOT execute when debug is disabled return { message: `Callback executed: ${i}` }; }); } // Verify callbacks didn't execute when debug disabled if (!isDebugEnabled()) { expect(callbackExecutionCount).toBe(0); } // Test side effect prevention patterns const badCallback = () => { sideEffectCount++; // This is a side effect - should be avoided return { message: 'Bad pattern - has side effects' }; }; const goodCallback = () => { // No side effects, pure computation only const computedValue = Math.random() * 100; return { message: 'Good pattern - no side effects', meta: { computed: computedValue, timestamp: Date.now() }, }; }; // Both callbacks should not execute when debug is disabled for (let i = 0; i < 10; i++) { debugIf(badCallback); debugIf(goodCallback); } if (!isDebugEnabled()) { expect(sideEffectCount).toBe(0); // No side effects when debug disabled } // Validate that string messages work efficiently expect(() => { for (let i = 0; i < 1000; i++) { debugIf('Simple string message'); // Should be very fast } }).not.toThrow(); }); it('should handle logging performance under concurrent load', async () => { // Test concurrent logging performance const { debugIf } = await import('@src/logger/logger.js'); const concurrentOperations = 10; const operationsPerThread = 1000; const concurrentPromises = Array.from({ length: concurrentOperations }, async (_, threadId) => { const threadStart = performance.now(); for (let i = 0; i < operationsPerThread; i++) { debugIf(() => ({ message: `Concurrent logging from thread ${threadId}, operation ${i}`, meta: { threadId, operationId: i, timestamp: Date.now(), threadData: Array.from({ length: 10 }, (_, j) => ({ id: j, value: Math.random() })), }, })); } return performance.now() - threadStart; }); const startTime = performance.now(); const threadDurations = await Promise.all(concurrentPromises); const totalDuration = performance.now() - startTime; // Validate concurrent performance expect(totalDuration).toBeLessThan(100); // Complete in under 100ms threadDurations.forEach((duration) => { expect(duration).toBeLessThan(50); // Each thread completes quickly }); const averageThreadDuration = threadDurations.reduce((sum, d) => sum + d, 0) / threadDurations.length; expect(averageThreadDuration).toBeLessThan(25); // Average thread duration under 25ms // Verify no thread took significantly longer (no blocking) const maxDuration = Math.max(...threadDurations); const minDuration = Math.min(...threadDurations); const durationVariance = (maxDuration - minDuration) / averageThreadDuration; expect(durationVariance).toBeLessThan(2); // Less than 200% variance between threads }); });

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