Skip to main content
Glama
CognitiveMCPServer.toolHandlers.test.ts25.4 kB
/** * Unit tests for CognitiveMCPServer tool handlers * Tests the implementation of handleThink, handleRemember, handleRecall, and handleAnalyzeReasoning */ import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { CognitiveMCPServer } from "../../server/CognitiveMCPServer.js"; import { ProcessingMode, ReasoningType } from "../../types/core.js"; import type { AnalyzeReasoningArgs, RecallArgs, RememberArgs, ThinkArgs, ThinkProbabilisticArgs, } from "../../types/mcp.js"; describe("CognitiveMCPServer Tool Handlers", () => { 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(); // Initialize without connecting to transport for testing await server.initialize(true); }); afterEach(async () => { await server.shutdown(); // Restore original environment process.env = originalEnv; }); describe("handleThink", () => { it("should process basic think request with default parameters", async () => { const args: ThinkArgs = { input: "What is the meaning of life?", }; const result = await server.handleThink(args); expect(result).toBeDefined(); expect(result.content).toBeDefined(); expect(typeof result.content).toBe("string"); expect(result.confidence).toBeGreaterThanOrEqual(0); expect(result.confidence).toBeLessThanOrEqual(1); expect(Array.isArray(result.reasoning_path)).toBe(true); expect(result.emotional_context).toBeDefined(); expect(result.metadata).toBeDefined(); expect(result.metadata.processing_time_ms).toBeGreaterThan(0); expect(result.metadata.system_mode).toBe(ProcessingMode.BALANCED); }); it("should process think request with specific mode", async () => { const args: ThinkArgs = { input: "Analyze this complex problem", mode: ProcessingMode.ANALYTICAL, enable_emotion: false, enable_metacognition: true, max_depth: 5, temperature: 0.3, }; const result = await server.handleThink(args); expect(result).toBeDefined(); expect(result.metadata.system_mode).toBe(ProcessingMode.ANALYTICAL); expect(result.metadata.temperature).toBeDefined(); }); it("should process think request with context", async () => { const args: ThinkArgs = { input: "Consider this in the context of software development", context: { domain: "software_engineering", session_id: "test_session_123", urgency: 0.8, complexity: 0.9, }, }; const result = await server.handleThink(args); expect(result).toBeDefined(); expect(result.content).toBeDefined(); }); it("should handle creative mode thinking", async () => { const args: ThinkArgs = { input: "Come up with innovative solutions", mode: ProcessingMode.CREATIVE, temperature: 1.5, }; const result = await server.handleThink(args); expect(result).toBeDefined(); expect(result.metadata.system_mode).toBe(ProcessingMode.CREATIVE); expect(result.metadata.temperature).toBe(1.5); }); it("should handle intuitive mode thinking", async () => { const args: ThinkArgs = { input: "What's your gut feeling about this?", mode: ProcessingMode.INTUITIVE, enable_emotion: true, }; const result = await server.handleThink(args); expect(result).toBeDefined(); expect(result.metadata.system_mode).toBe(ProcessingMode.INTUITIVE); }); it("should handle deliberative mode thinking", async () => { const args: ThinkArgs = { input: "Carefully analyze all aspects of this decision", mode: ProcessingMode.DELIBERATIVE, max_depth: 15, }; const result = await server.handleThink(args); expect(result).toBeDefined(); expect(result.metadata.system_mode).toBe(ProcessingMode.DELIBERATIVE); }); it("should throw error for invalid input", async () => { const args = { input: "", // Empty input should be invalid } as ThinkArgs; await expect(server.handleThink(args)).rejects.toThrow(); }); it("should handle long input text", async () => { const longInput = "A".repeat(10000); // Very long input const args: ThinkArgs = { input: longInput, }; const result = await server.handleThink(args); expect(result).toBeDefined(); expect(result.content).toBeDefined(); }); }); describe("handleRemember", () => { it("should store episodic memory", async () => { const args: RememberArgs = { content: "I had a great meeting with the team today", type: "episodic", importance: 0.8, emotional_tags: ["positive", "productive"], context: { domain: "work", session_id: "test_session", }, }; const result = await server.handleRemember(args); expect(result).toBeDefined(); expect(result.success).toBe(true); expect(result.memory_id).toBeDefined(); expect(typeof result.memory_id).toBe("string"); expect(result.message).toContain("episodic"); }); it("should store semantic memory", async () => { const args: RememberArgs = { content: "TypeScript is a superset of JavaScript", type: "semantic", importance: 0.9, context: { domain: "programming", }, }; const result = await server.handleRemember(args); expect(result).toBeDefined(); expect(result.success).toBe(true); expect(result.memory_id).toBeDefined(); expect(result.message).toContain("semantic"); }); it("should handle memory with minimal information", async () => { const args: RememberArgs = { content: "Simple fact to remember", type: "semantic", }; const result = await server.handleRemember(args); expect(result).toBeDefined(); expect(result.success).toBe(true); }); it("should handle memory with emotional tags", async () => { const args: RememberArgs = { content: "This was a challenging but rewarding experience", type: "episodic", importance: 0.7, emotional_tags: ["challenging", "rewarding", "growth"], }; const result = await server.handleRemember(args); expect(result).toBeDefined(); expect(result.success).toBe(true); }); it("should throw error for invalid memory type", async () => { const args = { content: "Some content", type: "invalid_type", // Invalid type } as unknown as RememberArgs; await expect(server.handleRemember(args)).rejects.toThrow(); }); it("should throw error for empty content", async () => { const args = { content: "", // Empty content type: "episodic", } as RememberArgs; await expect(server.handleRemember(args)).rejects.toThrow(); }); }); describe("handleRecall", () => { beforeEach(async () => { // Store some test memories first await server.handleRemember({ content: "Meeting about project planning", type: "episodic", importance: 0.8, emotional_tags: ["productive"], context: { domain: "work" }, }); await server.handleRemember({ content: "JavaScript is a programming language", type: "semantic", importance: 0.9, context: { domain: "programming" }, }); await server.handleRemember({ content: "Team lunch was enjoyable", type: "episodic", importance: 0.6, emotional_tags: ["positive", "social"], }); }); it("should recall memories with basic cue", async () => { const args: RecallArgs = { cue: "meeting", }; const result = await server.handleRecall(args); expect(result).toBeDefined(); expect(Array.isArray(result.memories)).toBe(true); expect(typeof result.total_found).toBe("number"); expect(result.search_time_ms).toBeGreaterThanOrEqual(0); }); it("should recall episodic memories only", async () => { const args: RecallArgs = { cue: "team", type: "episodic", max_results: 5, threshold: 0.3, }; const result = await server.handleRecall(args); expect(result).toBeDefined(); expect(Array.isArray(result.memories)).toBe(true); // All returned memories should be episodic (check that we have memories) expect(result.memories.length).toBeGreaterThanOrEqual(0); }); it("should recall semantic memories only", async () => { const args: RecallArgs = { cue: "programming", type: "semantic", max_results: 5, threshold: 0.2, }; const result = await server.handleRecall(args); expect(result).toBeDefined(); expect(Array.isArray(result.memories)).toBe(true); }); it("should recall both types of memories", async () => { const args: RecallArgs = { cue: "work", type: "both", max_results: 10, threshold: 0.1, }; const result = await server.handleRecall(args); expect(result).toBeDefined(); expect(Array.isArray(result.memories)).toBe(true); }); it("should respect max_results limit", async () => { const args: RecallArgs = { cue: "test", max_results: 2, }; const result = await server.handleRecall(args); expect(result).toBeDefined(); expect(result.memories.length).toBeLessThanOrEqual(2); }); it("should handle high threshold filtering", async () => { const args: RecallArgs = { cue: "nonexistent", threshold: 0.9, // Very high threshold }; const result = await server.handleRecall(args); expect(result).toBeDefined(); expect(Array.isArray(result.memories)).toBe(true); // Might return empty array due to high threshold }); it("should throw error for empty cue", async () => { const args = { cue: "", // Empty cue } as RecallArgs; await expect(server.handleRecall(args)).rejects.toThrow(); }); it("should handle context-based recall", async () => { const args: RecallArgs = { cue: "project", context: { domain: "work", session_id: "test_session", }, }; const result = await server.handleRecall(args); expect(result).toBeDefined(); expect(Array.isArray(result.memories)).toBe(true); }); }); describe("handleAnalyzeReasoning", () => { it("should analyze basic reasoning steps", async () => { const args: AnalyzeReasoningArgs = { reasoning_steps: [ { type: ReasoningType.LOGICAL_INFERENCE, content: "If all humans are mortal, and Socrates is human, then Socrates is mortal", confidence: 0.9, alternatives: [], }, { type: ReasoningType.DEDUCTIVE, content: "This follows logically from the premises", confidence: 0.8, alternatives: [ { content: "Could consider inductive reasoning instead", confidence: 0.3, reasoning: "Alternative approach", }, ], }, ], }; const result = await server.handleAnalyzeReasoning(args); expect(result).toBeDefined(); expect(typeof result.coherence_score).toBe("number"); expect(result.coherence_score).toBeGreaterThanOrEqual(0); expect(result.coherence_score).toBeLessThanOrEqual(1); expect(typeof result.confidence_assessment).toBe("string"); expect(Array.isArray(result.detected_biases)).toBe(true); expect(Array.isArray(result.suggested_improvements)).toBe(true); expect(result.reasoning_quality).toBeDefined(); expect(typeof result.reasoning_quality.logical_consistency).toBe( "number" ); expect(typeof result.reasoning_quality.evidence_support).toBe("number"); expect(typeof result.reasoning_quality.completeness).toBe("number"); }); it("should detect biases in reasoning", async () => { const args: AnalyzeReasoningArgs = { reasoning_steps: [ { type: ReasoningType.HEURISTIC, content: "This obviously confirms my initial belief and supports my view clearly", confidence: 0.95, alternatives: [], }, { type: ReasoningType.PATTERN_MATCH, content: "As expected, this is definitely the right answer without doubt", confidence: 0.98, alternatives: [], }, ], }; const result = await server.handleAnalyzeReasoning(args); expect(result).toBeDefined(); expect(result.detected_biases.length).toBeGreaterThan(0); // Should detect confirmation bias and overconfidence bias expect(result.suggested_improvements.length).toBeGreaterThan(0); }); it("should analyze reasoning with low confidence", async () => { const args: AnalyzeReasoningArgs = { reasoning_steps: [ { type: ReasoningType.PROBABILISTIC, content: "I'm not sure about this, but maybe it could be true", confidence: 0.2, alternatives: [], }, { type: ReasoningType.ANALOGICAL, content: "This might be similar to other cases, but I'm uncertain", confidence: 0.3, alternatives: [], }, ], }; const result = await server.handleAnalyzeReasoning(args); expect(result).toBeDefined(); expect(result.confidence_assessment).toContain("confidence"); expect(result.suggested_improvements.length).toBeGreaterThan(0); }); it("should analyze complex reasoning with multiple types", async () => { const args: AnalyzeReasoningArgs = { reasoning_steps: [ { type: ReasoningType.CAUSAL, content: "The increase in temperature causes ice to melt", confidence: 0.9, alternatives: [], }, { type: ReasoningType.PROBABILISTIC, content: "There's a 90% chance this will happen under these conditions", confidence: 0.8, alternatives: [ { content: "Could be 85% based on different data", confidence: 0.7, reasoning: "Alternative probability estimate", }, ], }, { type: ReasoningType.METACOGNITIVE, content: "I should consider whether my reasoning is sound", confidence: 0.7, alternatives: [], }, ], }; const result = await server.handleAnalyzeReasoning(args); expect(result).toBeDefined(); expect(result.reasoning_quality.completeness).toBeGreaterThan(0.5); }); it("should handle single reasoning step", async () => { const args: AnalyzeReasoningArgs = { reasoning_steps: [ { type: ReasoningType.LOGICAL_INFERENCE, content: "This is a simple logical conclusion", confidence: 0.7, alternatives: [], }, ], }; const result = await server.handleAnalyzeReasoning(args); expect(result).toBeDefined(); expect(result.coherence_score).toBeGreaterThanOrEqual(0); }); it("should throw error for empty reasoning steps", async () => { const args = { reasoning_steps: [], // Empty array } as AnalyzeReasoningArgs; await expect(server.handleAnalyzeReasoning(args)).rejects.toThrow(); }); it("should throw error for invalid reasoning step format", async () => { const args = { reasoning_steps: [ { // Missing required fields content: "Some content", }, ], } as AnalyzeReasoningArgs; await expect(server.handleAnalyzeReasoning(args)).rejects.toThrow(); }); it("should analyze reasoning with context", async () => { const args: AnalyzeReasoningArgs = { reasoning_steps: [ { type: ReasoningType.CONTEXTUAL, content: "In the context of software development, this approach makes sense", confidence: 0.8, alternatives: [], }, ], context: { domain: "software_engineering", session_id: "analysis_session", }, }; const result = await server.handleAnalyzeReasoning(args); expect(result).toBeDefined(); expect(result.coherence_score).toBeGreaterThanOrEqual(0); }); }); describe("Integration Tests", () => { it("should handle think -> remember -> recall workflow", async () => { // First, think about something const thinkResult = await server.handleThink({ input: "What are the benefits of TypeScript?", mode: ProcessingMode.ANALYTICAL, }); expect(thinkResult).toBeDefined(); // Remember the thought const rememberResult = await server.handleRemember({ content: thinkResult.content, type: "episodic", importance: 0.8, emotional_tags: ["learning"], }); expect(rememberResult.success).toBe(true); // Recall related memories const recallResult = await server.handleRecall({ cue: "TypeScript", type: "both", }); expect(recallResult).toBeDefined(); expect(Array.isArray(recallResult.memories)).toBe(true); }); it("should handle think -> analyze reasoning workflow", async () => { // Think about something complex const thinkResult = await server.handleThink({ input: "Should we adopt microservices architecture?", mode: ProcessingMode.DELIBERATIVE, enable_metacognition: true, }); expect(thinkResult).toBeDefined(); expect(thinkResult.reasoning_path.length).toBeGreaterThan(0); // Analyze the reasoning const analysisResult = await server.handleAnalyzeReasoning({ reasoning_steps: thinkResult.reasoning_path, }); expect(analysisResult).toBeDefined(); expect(typeof analysisResult.coherence_score).toBe("number"); }); it("should maintain consistency across multiple operations", async () => { const sessionId = "consistency_test_session"; // Multiple think operations with same session const results = await Promise.all([ server.handleThink({ input: "First thought", context: { session_id: sessionId }, }), server.handleThink({ input: "Second thought", context: { session_id: sessionId }, }), server.handleThink({ input: "Third thought", context: { session_id: sessionId }, }), ]); results.forEach((result) => { expect(result).toBeDefined(); expect(result.content).toBeDefined(); }); // Store memories from all thoughts const memoryResults = await Promise.all( results.map((result, index) => server.handleRemember({ content: result.content, type: "episodic", importance: 0.5 + index * 0.1, context: { session_id: sessionId }, }) ) ); memoryResults.forEach((result) => { expect(result.success).toBe(true); }); // Recall memories from the session const recallResult = await server.handleRecall({ cue: "thought", context: { session_id: sessionId }, }); expect(recallResult).toBeDefined(); expect(recallResult.total_found).toBeGreaterThanOrEqual(0); }); }); describe("handleThinkProbabilistic", () => { it("should process probabilistic reasoning request with basic input", async () => { const args: ThinkProbabilisticArgs = { input: "What is the probability that it will rain tomorrow given cloudy skies?", }; const result = await server.handleThinkProbabilistic(args); expect(result).toBeDefined(); expect(result.conclusion).toBeDefined(); expect(typeof result.conclusion).toBe("string"); expect(result.confidence).toBeDefined(); expect(typeof result.confidence).toBe("number"); expect(result.confidence).toBeGreaterThanOrEqual(0); expect(result.confidence).toBeLessThanOrEqual(1); expect(result.uncertainty_assessment).toBeDefined(); expect(result.belief_network).toBeDefined(); expect(result.evidence_integration).toBeDefined(); expect(Array.isArray(result.alternative_hypotheses)).toBe(true); expect(result.reasoning_chain).toBeDefined(); expect(typeof result.processing_time_ms).toBe("number"); }); it("should handle probabilistic reasoning with context", async () => { const args: ThinkProbabilisticArgs = { input: "Should I invest in this stock given the current market conditions?", context: { domain: "finance", session_id: "test-session", }, }; const result = await server.handleThinkProbabilistic(args); expect(result).toBeDefined(); expect(result.conclusion).toBeDefined(); expect(result.uncertainty_assessment).toBeDefined(); expect(result.uncertainty_assessment.epistemic_uncertainty).toBeDefined(); expect(result.uncertainty_assessment.aleatoric_uncertainty).toBeDefined(); expect(result.uncertainty_assessment.combined_uncertainty).toBeDefined(); expect( Array.isArray(result.uncertainty_assessment.confidence_interval) ).toBe(true); expect(result.uncertainty_assessment.confidence_interval).toHaveLength(2); expect( Array.isArray(result.uncertainty_assessment.uncertainty_sources) ).toBe(true); }); it("should generate multiple hypotheses for complex scenarios", async () => { const args: ThinkProbabilisticArgs = { input: "What are the possible outcomes of implementing a new software architecture?", }; const result = await server.handleThinkProbabilistic(args); expect(result).toBeDefined(); expect(Array.isArray(result.alternative_hypotheses)).toBe(true); expect(result.alternative_hypotheses.length).toBeGreaterThan(0); expect(result.belief_network.nodes.size).toBeGreaterThan(0); expect(result.reasoning_chain.steps).toBeDefined(); expect(Array.isArray(result.reasoning_chain.steps)).toBe(true); expect(result.reasoning_chain.steps.length).toBeGreaterThan(0); }); it("should handle uncertainty quantification correctly", async () => { const args: ThinkProbabilisticArgs = { input: "What is the likelihood of success for this uncertain project?", }; const result = await server.handleThinkProbabilistic(args); expect(result).toBeDefined(); expect(result.uncertainty_assessment).toBeDefined(); const uncertainty = result.uncertainty_assessment; expect(uncertainty.epistemic_uncertainty).toBeGreaterThanOrEqual(0); expect(uncertainty.epistemic_uncertainty).toBeLessThanOrEqual(1); expect(uncertainty.aleatoric_uncertainty).toBeGreaterThanOrEqual(0); expect(uncertainty.aleatoric_uncertainty).toBeLessThanOrEqual(1); expect(uncertainty.combined_uncertainty).toBeGreaterThanOrEqual(0); expect(uncertainty.combined_uncertainty).toBeLessThanOrEqual(1); expect(uncertainty.reliability_assessment).toBeGreaterThanOrEqual(0); expect(uncertainty.reliability_assessment).toBeLessThanOrEqual(1); }); it("should handle empty input gracefully", async () => { const args: ThinkProbabilisticArgs = { input: "" }; const result = await server.handleThinkProbabilistic(args); expect(result).toBeDefined(); expect(result.conclusion).toBeDefined(); expect(result.confidence).toBeGreaterThanOrEqual(0); expect(result.uncertainty_assessment).toBeDefined(); expect( result.uncertainty_assessment.combined_uncertainty ).toBeGreaterThan(0.3); // Higher uncertainty for empty input }); it("should handle edge cases gracefully", async () => { const args: ThinkProbabilisticArgs = { input: "A very short input", }; const result = await server.handleThinkProbabilistic(args); expect(result).toBeDefined(); expect(result.conclusion).toBeDefined(); expect(result.confidence).toBeGreaterThan(0); expect(result.processing_time_ms).toBeGreaterThanOrEqual(0); }); }); });

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