Skip to main content
Glama
ResponseFormattingIntegration.test.ts14.8 kB
/** * Integration tests for response formatting and error handling in the MCP server */ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { CognitiveMCPServer } from "../../server/CognitiveMCPServer.js"; import { ProcessingMode, ReasoningType, ReasoningTypeValue, } from "../../types/core.js"; import { ErrorHandler } from "../../utils/ErrorHandler.js"; import { ResponseFormatter } from "../../utils/ResponseFormatter.js"; describe("Response Formatting Integration", () => { let server: CognitiveMCPServer; let originalEnv: NodeJS.ProcessEnv; beforeEach(async () => { // Save original environment originalEnv = { ...process.env }; // Set up test environment with unique temporary brain directory const testId = Math.random().toString(36).substring(7); process.env.COGNITIVE_BRAIN_DIR = `./tmp/test-brain-${testId}`; server = new CognitiveMCPServer(); await server.initialize(true); // Test mode ErrorHandler.clearErrorHistory(); }); afterEach(async () => { await server.shutdown(); ErrorHandler.clearErrorHistory(); // Restore original environment process.env = originalEnv; }); describe("Think Tool Response Formatting", () => { it("should return properly formatted successful think response", async () => { const result = await server.handleThink({ input: "What is the meaning of life?", mode: ProcessingMode.BALANCED, }); expect(result).toBeDefined(); expect(result.content).toBeDefined(); expect(result.confidence).toBeGreaterThanOrEqual(0); expect(result.confidence).toBeLessThanOrEqual(1); expect(result.reasoning_path).toBeDefined(); expect(Array.isArray(result.reasoning_path)).toBe(true); expect(result.emotional_context).toBeDefined(); expect(result.metadata).toBeDefined(); expect(result.metadata.processing_time_ms).toBeGreaterThanOrEqual(0); }); it("should handle think tool validation errors gracefully", async () => { await expect( server.handleThink({ input: "", mode: ProcessingMode.BALANCED, }) ).rejects.toThrow("❌ Parameter validation failed for 'think' tool"); }); it("should handle think tool with invalid mode gracefully", async () => { await expect( server.handleThink({ input: "test", mode: "invalid_mode" as any, }) ).rejects.toThrow("❌ Parameter validation failed for 'think' tool"); }); it("should handle think tool with invalid temperature gracefully", async () => { await expect( server.handleThink({ input: "test", temperature: -1, }) ).rejects.toThrow("❌ Parameter validation failed for 'think' tool"); }); }); describe("Remember Tool Response Formatting", () => { it("should return properly formatted successful remember response", async () => { const result = await server.handleRemember({ content: "Test memory content", type: "episodic", importance: 0.8, }); expect(result).toBeDefined(); expect(result.success).toBe(true); expect(result.memory_id).toBeDefined(); expect(typeof result.memory_id).toBe("string"); expect(result.message).toBeDefined(); expect(typeof result.message).toBe("string"); }); it("should handle remember tool validation errors gracefully", async () => { await expect( server.handleRemember({ content: "", type: "episodic", }) ).rejects.toThrow("❌ Parameter validation failed for 'remember' tool"); }); it("should handle remember tool with invalid type gracefully", async () => { await expect( server.handleRemember({ content: "test", type: "invalid" as any, }) ).rejects.toThrow("❌ Parameter validation failed for 'remember' tool"); }); it("should handle remember tool with invalid importance gracefully", async () => { await expect( server.handleRemember({ content: "test", type: "episodic", importance: 2, }) ).rejects.toThrow("❌ Parameter validation failed for 'remember' tool"); }); }); describe("Recall Tool Response Formatting", () => { it("should return properly formatted successful recall response", async () => { // First store some memories await server.handleRemember({ content: "Test memory for recall", type: "episodic", importance: 0.7, }); const result = await server.handleRecall({ cue: "test memory", type: "both", max_results: 5, }); expect(result).toBeDefined(); expect(result.memories).toBeDefined(); expect(Array.isArray(result.memories)).toBe(true); expect(result.total_found).toBeGreaterThanOrEqual(0); expect(result.search_time_ms).toBeGreaterThanOrEqual(0); }); it("should handle recall tool validation errors gracefully", async () => { await expect( server.handleRecall({ cue: "", }) ).rejects.toThrow("❌ Parameter validation failed for 'recall' tool"); }); it("should handle recall tool with invalid type gracefully", async () => { await expect( server.handleRecall({ cue: "test", type: "invalid" as any, }) ).rejects.toThrow("❌ Parameter validation failed for 'recall' tool"); }); it("should handle recall tool with invalid threshold gracefully", async () => { await expect( server.handleRecall({ cue: "test", threshold: 2, }) ).rejects.toThrow("❌ Parameter validation failed for 'recall' tool"); }); it("should handle recall tool with invalid max_results gracefully", async () => { await expect( server.handleRecall({ cue: "test", max_results: 100, }) ).rejects.toThrow("❌ Parameter validation failed for 'recall' tool"); }); }); describe("Analyze Reasoning Tool Response Formatting", () => { it("should return properly formatted successful analyze response", async () => { const reasoningSteps = [ { type: ReasoningType.LOGICAL_INFERENCE, content: "First reasoning step", confidence: 0.8, alternatives: [], }, { type: ReasoningType.PATTERN_MATCH, content: "Second reasoning step", confidence: 0.7, alternatives: [], }, ]; const result = await server.handleAnalyzeReasoning({ reasoning_steps: reasoningSteps, }); expect(result).toBeDefined(); expect(result.coherence_score).toBeGreaterThanOrEqual(0); expect(result.coherence_score).toBeLessThanOrEqual(1); expect(result.confidence_assessment).toBeDefined(); expect(typeof result.confidence_assessment).toBe("string"); expect(result.detected_biases).toBeDefined(); expect(Array.isArray(result.detected_biases)).toBe(true); expect(result.suggested_improvements).toBeDefined(); expect(Array.isArray(result.suggested_improvements)).toBe(true); expect(result.reasoning_quality).toBeDefined(); expect( result.reasoning_quality.logical_consistency ).toBeGreaterThanOrEqual(0); expect(result.reasoning_quality.evidence_support).toBeGreaterThanOrEqual( 0 ); expect(result.reasoning_quality.completeness).toBeGreaterThanOrEqual(0); }); it("should handle analyze tool validation errors gracefully", async () => { await expect( server.handleAnalyzeReasoning({ reasoning_steps: undefined as any, }) ).rejects.toThrow( "Analyze reasoning tool requires an array of reasoning steps" ); }); it("should handle analyze tool with empty steps gracefully", async () => { await expect( server.handleAnalyzeReasoning({ reasoning_steps: [], }) ).rejects.toThrow("At least one reasoning step is required"); }); it("should handle analyze tool with invalid step structure gracefully", async () => { await expect( server.handleAnalyzeReasoning({ reasoning_steps: [ { type: null as unknown as ReasoningTypeValue, // Invalid type content: "test", confidence: 0.5, alternatives: [], }, ], }) ).rejects.toThrow("Reasoning step 0 requires a valid type string"); }); }); describe("Error Response Formatting", () => { it("should format validation errors consistently", async () => { try { await server.handleThink({ input: "", mode: ProcessingMode.BALANCED, }); } catch (error) { expect(error).toBeInstanceOf(Error); expect((error as Error).message).toContain( "❌ Parameter validation failed for 'think' tool" ); } }); it("should handle component failures gracefully", async () => { // Mock a component failure const originalThink = server.getCognitiveOrchestrator().think; server.getCognitiveOrchestrator().think = vi .fn() .mockRejectedValue(new Error("Simulated component failure")); try { await server.handleThink({ input: "test input", mode: ProcessingMode.BALANCED, }); } catch (error) { expect(error).toBeInstanceOf(Error); expect((error as Error).message).toContain("Think processing failed"); } // Restore original method server.getCognitiveOrchestrator().think = originalThink; }); it("should provide meaningful error messages for different error types", async () => { const testCases = [ { input: { input: "", mode: ProcessingMode.BALANCED }, expectedError: "❌ parameter validation failed for 'think' tool", }, { input: { input: "test", temperature: -1 }, expectedError: "❌ parameter validation failed for 'think' tool", }, { input: { input: "test", max_depth: 0 }, expectedError: "❌ parameter validation failed for 'think' tool", }, ]; for (const testCase of testCases) { try { await server.handleThink(testCase.input as any); expect.fail("Should have thrown an error"); } catch (error) { expect((error as Error).message.toLowerCase()).toContain( testCase.expectedError.toLowerCase() ); } } }); }); describe("Response Structure Validation", () => { it("should validate response structure for all tools", async () => { // Test think response structure const thinkResult = await server.handleThink({ input: "test input", mode: ProcessingMode.BALANCED, }); const thinkFormatted = ResponseFormatter.formatThinkResponse( thinkResult, 100 ); expect(ResponseFormatter.validateResponse(thinkFormatted)).toBe(true); // Test remember response structure const rememberResult = await server.handleRemember({ content: "test content", type: "episodic", }); const rememberFormatted = ResponseFormatter.formatRememberResponse( rememberResult, 100 ); expect(ResponseFormatter.validateResponse(rememberFormatted)).toBe(true); // Test recall response structure const recallResult = await server.handleRecall({ cue: "test cue", }); const recallFormatted = ResponseFormatter.formatRecallResponse(recallResult); expect(ResponseFormatter.validateResponse(recallFormatted)).toBe(true); // Test analyze response structure const analyzeResult = await server.handleAnalyzeReasoning({ reasoning_steps: [ { type: ReasoningType.LOGICAL_INFERENCE, content: "test step", confidence: 0.8, alternatives: [], }, ], }); const analyzeFormatted = ResponseFormatter.formatAnalyzeResponse( analyzeResult, 100 ); expect(ResponseFormatter.validateResponse(analyzeFormatted)).toBe(true); }); it("should handle malformed responses gracefully", () => { const malformedResponse = { success: true, // Missing data field metadata: { timestamp: Date.now(), processing_time_ms: 100, tool_name: "test", version: "1.0.0", }, } as any; expect(ResponseFormatter.validateResponse(malformedResponse)).toBe(false); }); }); describe("Performance and Timing", () => { it("should track processing times accurately", async () => { const startTime = Date.now(); const result = await server.handleThink({ input: "Performance test input", mode: ProcessingMode.BALANCED, }); const endTime = Date.now(); const actualTime = endTime - startTime; expect(result.metadata.processing_time_ms).toBeGreaterThanOrEqual(0); expect(result.metadata.processing_time_ms).toBeLessThanOrEqual( actualTime + 100 ); // Allow some margin }); it("should handle timeout scenarios gracefully", async () => { // This test would require mocking a long-running operation // For now, we'll test that the timeout mechanism exists const result = await server.handleThink({ input: "Quick test", mode: ProcessingMode.BALANCED, }); expect(result.metadata.processing_time_ms).toBeLessThan(30000); // Should be well under timeout }); }); describe("Graceful Degradation", () => { it("should continue processing with component failures when possible", async () => { // This would require more sophisticated mocking of component failures // For now, we'll test that the error handling infrastructure is in place const stats = ErrorHandler.getErrorStatistics(); expect(typeof stats).toBe("object"); }); it("should provide fallback responses when appropriate", async () => { // Test that fallback mechanisms are available const fallbackResponse = ResponseFormatter.createFallbackResponse( "test_tool", "Test error", "req_123" ); expect(fallbackResponse.success).toBe(false); expect(fallbackResponse.error?.code).toBe("FORMATTING_ERROR"); expect(fallbackResponse.metadata.tool_name).toBe("test_tool"); }); }); });

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/keyurgolani/ThoughtMcp'

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