Skip to main content
Glama
mcp-tools.test.ts37.2 kB
/** * MCP Tools End-to-End Tests * * Comprehensive end-to-end tests for MCP tools testing complete workflows, * tool chaining, error handling, concurrent operations, and performance under load. * * Requirements: All requirements */ import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { CognitiveMCPServer } from "../../server/mcp-server.js"; import type { MCPResponse } from "../../server/types.js"; import { randomString, sleep, withTimeout } from "../utils/test-helpers.js"; // Shared test state let server: CognitiveMCPServer; let testUserId: string; let testSessionId: string; /** * Helper function to invoke MCP tool */ async function invokeTool(toolName: string, params: Record<string, unknown>): Promise<MCPResponse> { const tool = server.toolRegistry.getTool(toolName); if (!tool) { throw new Error(`Tool not found: ${toolName}`); } return await tool.handler(params); } describe("MCP Tools End-to-End Tests", () => { beforeEach(async () => { // Create fresh server instance server = new CognitiveMCPServer(); // Initialize server with timeout await withTimeout(() => server.initialize(), 10000); // Clean database before each test to avoid dimension mismatches // Drop and recreate tables to ensure correct vector dimensions if (server["databaseManager"]) { try { const client = await server["databaseManager"].getConnection(); try { // Drop tables in correct order (respecting foreign keys) await client.query("DROP TABLE IF EXISTS memory_embeddings CASCADE"); await client.query("DROP TABLE IF EXISTS memory_connections CASCADE"); await client.query("DROP TABLE IF EXISTS memories CASCADE"); // Recreate memories table with all required columns await client.query(` CREATE TABLE IF NOT EXISTS memories ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL, session_id TEXT NOT NULL, content TEXT NOT NULL, primary_sector TEXT NOT NULL, strength REAL NOT NULL DEFAULT 1.0, salience REAL NOT NULL DEFAULT 0.5, importance REAL NOT NULL DEFAULT 0.5, decay_rate REAL NOT NULL DEFAULT 0.1, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), last_accessed TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), access_count INTEGER NOT NULL DEFAULT 0, metadata JSONB, search_vector tsvector ) `); // Create function and trigger for search_vector await client.query(` CREATE OR REPLACE FUNCTION memories_search_vector_update() RETURNS trigger AS $$ BEGIN NEW.search_vector := to_tsvector('english', COALESCE(NEW.content, '')); RETURN NEW; END; $$ LANGUAGE plpgsql `); await client.query(` DROP TRIGGER IF EXISTS memories_search_vector_trigger ON memories `); await client.query(` CREATE TRIGGER memories_search_vector_trigger BEFORE INSERT OR UPDATE OF content ON memories FOR EACH ROW EXECUTE FUNCTION memories_search_vector_update() `); // Create GIN index for full-text search await client.query(` CREATE INDEX IF NOT EXISTS idx_memories_search_vector ON memories USING GIN(search_vector) `); // Recreate memory_embeddings table with correct dimension and composite primary key const embeddingDimension = parseInt(process.env.EMBEDDING_DIMENSION ?? "768", 10); await client.query(` CREATE TABLE IF NOT EXISTS memory_embeddings ( memory_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE, sector TEXT NOT NULL, embedding vector(${embeddingDimension}), dimension INTEGER NOT NULL, model TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), PRIMARY KEY (memory_id, sector) ) `); // Recreate memory_connections table await client.query(` CREATE TABLE IF NOT EXISTS memory_connections ( id TEXT PRIMARY KEY, source_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE, target_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE, connection_type TEXT NOT NULL, strength REAL NOT NULL DEFAULT 1.0, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ) `); // Recreate memory_metadata table await client.query(` CREATE TABLE IF NOT EXISTS memory_metadata ( memory_id TEXT PRIMARY KEY REFERENCES memories(id) ON DELETE CASCADE, keywords TEXT[] NOT NULL DEFAULT '{}', tags TEXT[] NOT NULL DEFAULT '{}', category TEXT, context TEXT, importance REAL DEFAULT 0.5, is_atomic BOOLEAN DEFAULT TRUE, parent_id TEXT REFERENCES memories(id), CONSTRAINT valid_importance CHECK (importance >= 0 AND importance <= 1) ) `); // Recreate memory_links table (used by waypoint graph) await client.query(` CREATE TABLE IF NOT EXISTS memory_links ( source_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE, target_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE, link_type TEXT NOT NULL, weight REAL DEFAULT 0.5, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, traversal_count INTEGER DEFAULT 0, PRIMARY KEY (source_id, target_id), CONSTRAINT valid_weight CHECK (weight >= 0 AND weight <= 1), CONSTRAINT no_self_links CHECK (source_id != target_id) ) `); } finally { client.release(); } } catch (error) { console.error("Database setup error:", error); throw error; } } // Generate unique test identifiers testUserId = `test-user-${randomString(8)}`; testSessionId = `test-session-${randomString(8)}`; }); afterEach(async () => { // Cleanup server if (server.isInitialized) { await server.shutdown(); } }); describe("Complete Memory Workflow", () => { it("should handle store → retrieve → update → delete workflow", async () => { // Store memory const storeResponse = await invokeTool("remember", { content: "User prefers dark mode for better readability", userId: testUserId, sessionId: testSessionId, primarySector: "semantic", metadata: { keywords: ["dark", "mode", "preference"], tags: ["ui", "settings"], category: "preferences", importance: 0.8, }, }); if (!storeResponse.success) { console.error("Store memory failed:", storeResponse.error); } expect(storeResponse.success).toBe(true); expect(storeResponse.data).toBeDefined(); const memoryId = (storeResponse.data as any).memoryId; expect(memoryId).toBeDefined(); expect((storeResponse.data as any).embeddingsGenerated).toBe(5); expect((storeResponse.data as any).linksCreated).toBeGreaterThanOrEqual(0); // Retrieve memory const retrieveResponse = await invokeTool("recall", { userId: testUserId, text: "dark mode", limit: 10, }); expect(retrieveResponse.success).toBe(true); expect((retrieveResponse.data as any).memories).toHaveLength(1); expect((retrieveResponse.data as any).memories[0].id).toBe(memoryId); expect((retrieveResponse.data as any).memories[0].content).toContain("dark mode"); // Update memory const updateResponse = await invokeTool("update_memory", { memoryId, userId: testUserId, content: "User strongly prefers dark mode for all interfaces", strength: 0.95, metadata: { importance: 0.9, }, }); if (!updateResponse.success) { console.error("Update memory failed:", updateResponse.error); } expect(updateResponse.success).toBe(true); expect((updateResponse.data as any).embeddingsRegenerated).toBe(true); expect((updateResponse.data as any).strength).toBe(0.95); // Delete memory (soft delete) const softDeleteResponse = await invokeTool("forget", { memoryId, userId: testUserId, soft: true, }); expect(softDeleteResponse.success).toBe(true); expect((softDeleteResponse.data as any).deletionType).toBe("soft"); // Hard delete const hardDeleteResponse = await invokeTool("forget", { memoryId, userId: testUserId, soft: false, }); expect(hardDeleteResponse.success).toBe(true); expect((hardDeleteResponse.data as any).deletionType).toBe("hard"); }); it("should handle bulk memory operations with search", async () => { // Store multiple memories const memories = [ { content: "Machine learning algorithms for classification", keywords: ["machine", "learning", "classification"], tags: ["ai", "ml"], }, { content: "Deep learning neural networks for image recognition", keywords: ["deep", "learning", "neural", "networks"], tags: ["ai", "deep-learning"], }, { content: "Natural language processing for text analysis", keywords: ["nlp", "text", "analysis"], tags: ["ai", "nlp"], }, ]; const memoryIds: string[] = []; for (const mem of memories) { const response = await invokeTool("remember", { content: mem.content, userId: testUserId, sessionId: testSessionId, primarySector: "semantic", metadata: { keywords: mem.keywords, tags: mem.tags, category: "technology", }, }); expect(response.success).toBe(true); memoryIds.push((response.data as any).memoryId); } // Search with text query const searchResponse = await invokeTool("search", { userId: testUserId, text: "learning", limit: 10, }); expect(searchResponse.success).toBe(true); expect((searchResponse.data as any).memories.length).toBeGreaterThan(0); // Search with metadata filters const tagSearchResponse = await invokeTool("search", { userId: testUserId, metadata: { tags: ["deep-learning"], }, limit: 10, }); expect(tagSearchResponse.success).toBe(true); expect((tagSearchResponse.data as any).memories.length).toBeGreaterThan(0); expect((tagSearchResponse.data as any).memories[0].metadata.tags).toContain("deep-learning"); }); }); describe("Complete Reasoning Workflow", () => { it("should handle think → assess confidence → detect bias workflow", async () => { // Think about a problem const thinkResponse = await invokeTool("think", { problem: "Should we migrate our monolithic application to microservices?", mode: "analytical", context: { evidence: [ "Current system handles 10k requests/sec", "Team has 5 developers", "Budget is limited", ], }, }); expect(thinkResponse.success).toBe(true); expect((thinkResponse.data as any).reasoning).toBeDefined(); expect((thinkResponse.data as any).conclusion).toBeDefined(); // Assess confidence in the reasoning // Note: reasoning is an array of strings, so we join them for the confidence assessment const reasoningText = Array.isArray((thinkResponse.data as any).reasoning) ? (thinkResponse.data as any).reasoning.join(" ") : (thinkResponse.data as any).reasoning; const confidenceResponse = await invokeTool("assess_confidence", { reasoning: reasoningText, evidence: [ "Current system handles 10k requests/sec", "Team has 5 developers", "Budget is limited", ], }); expect(confidenceResponse.success).toBe(true); expect((confidenceResponse.data as any).overallConfidence).toBeGreaterThanOrEqual(0); expect((confidenceResponse.data as any).overallConfidence).toBeLessThanOrEqual(1); expect((confidenceResponse.data as any).factors).toBeDefined(); // Detect biases in the reasoning const biasResponse = await invokeTool("detect_bias", { reasoning: reasoningText, context: "System migration decision", }); expect(biasResponse.success).toBe(true); expect((biasResponse.data as any).biases).toBeDefined(); expect(Array.isArray((biasResponse.data as any).biases)).toBe(true); }); it("should handle decompose → think parallel → analyze workflow", async () => { // Decompose problem const decomposeResponse = await invokeTool("breakdown", { problem: "Design a scalable e-commerce platform", maxDepth: 2, }); expect(decomposeResponse.success).toBe(true); expect((decomposeResponse.data as any).subProblems).toBeDefined(); expect((decomposeResponse.data as any).subProblems.length).toBeGreaterThan(0); // Think in parallel on the problem const parallelResponse = await invokeTool("ponder", { problem: "Design a scalable e-commerce platform", context: { constraints: ["Budget: $100k", "Timeline: 6 months"], goals: ["Handle 100k users", "99.9% uptime"], }, }); expect(parallelResponse.success).toBe(true); expect((parallelResponse.data as any).conclusion).toBeDefined(); expect((parallelResponse.data as any).insights).toBeDefined(); expect((parallelResponse.data as any).recommendations).toBeDefined(); expect((parallelResponse.data as any).conflicts).toBeDefined(); expect((parallelResponse.data as any).confidence).toBeDefined(); expect((parallelResponse.data as any).quality).toBeDefined(); // Analyze the reasoning quality const analyzeResponse = await invokeTool("evaluate", { reasoning: (parallelResponse.data as any).conclusion, context: "Design a scalable e-commerce platform with budget and timeline constraints", }); expect(analyzeResponse.success).toBe(true); expect((analyzeResponse.data as any).quality).toBeDefined(); expect((analyzeResponse.data as any).quality.coherence).toBeGreaterThanOrEqual(0); expect((analyzeResponse.data as any).quality.coherence).toBeLessThanOrEqual(1); expect((analyzeResponse.data as any).strengths).toBeDefined(); expect((analyzeResponse.data as any).weaknesses).toBeDefined(); }); it("should handle systematic analysis with framework selection", async () => { const response = await invokeTool("analyze", { problem: "Reduce customer churn rate", context: { background: "Current churn: 15%, Industry average: 10%", constraints: ["Limited budget", "3-month timeline"], }, }); expect(response.success).toBe(true); expect((response.data as any).framework).toBeDefined(); expect((response.data as any).framework.id).toBeDefined(); expect((response.data as any).framework.name).toBeDefined(); expect((response.data as any).selection).toBeDefined(); expect((response.data as any).result).toBeDefined(); expect((response.data as any).result.conclusion).toBeDefined(); }); }); describe("Tool Chaining and Composition", () => { it("should chain memory and reasoning tools", async () => { // Store context memory const storeResponse = await invokeTool("remember", { content: "Company policy: All decisions must consider environmental impact", userId: testUserId, sessionId: testSessionId, primarySector: "semantic", metadata: { keywords: ["policy", "environment", "decisions"], tags: ["policy", "sustainability"], category: "company-policy", importance: 0.9, }, }); expect(storeResponse.success).toBe(true); // Retrieve relevant context const retrieveResponse = await invokeTool("recall", { userId: testUserId, text: "company policy decisions", limit: 5, }); expect(retrieveResponse.success).toBe(true); const context = (retrieveResponse.data as any).memories.map( (m: { content: string }) => m.content ); // Think with retrieved context const thinkResponse = await invokeTool("think", { problem: "Should we switch to cheaper but less eco-friendly packaging?", mode: "critical", context: { evidence: context, constraints: ["Budget constraints", "Environmental policy"], }, }); expect(thinkResponse.success).toBe(true); expect((thinkResponse.data as any).reasoning).toBeDefined(); // Store the reasoning as a new memory const insightResponse = await invokeTool("remember", { content: `Decision insight: ${(thinkResponse.data as any).conclusion}`, userId: testUserId, sessionId: testSessionId, primarySector: "reflective", metadata: { keywords: ["decision", "packaging", "environment"], tags: ["decision", "insight"], category: "decisions", importance: 0.8, }, }); expect(insightResponse.success).toBe(true); }); it("should handle complex multi-tool workflow", async () => { // 1. Detect emotion in user input const emotionResponse = await invokeTool("detect_emotion", { text: "I'm really frustrated with the slow performance of our system!", }); expect(emotionResponse.success).toBe(true); const emotionalState = emotionResponse.data; // 2. Store emotional context await invokeTool("remember", { content: "User expressed frustration about system performance", userId: testUserId, sessionId: testSessionId, primarySector: "emotional", metadata: { keywords: ["frustration", "performance", "system"], tags: ["emotion", "feedback"], category: "user-feedback", importance: 0.7, }, }); // 3. Decompose the problem const decomposeResponse = await invokeTool("breakdown", { problem: "Improve system performance to address user frustration", maxDepth: 2, }); expect(decomposeResponse.success).toBe(true); // 4. Think about solutions with emotional awareness const thinkResponse = await invokeTool("think", { problem: "Improve system performance", mode: "creative", context: { evidence: ["Users are frustrated", "Performance is slow"], emotionalContext: emotionalState, }, }); expect(thinkResponse.success).toBe(true); // 5. Assess confidence in the solution // Note: reasoning is an array of strings, so we join them for the confidence assessment const reasoningText = Array.isArray((thinkResponse.data as any).reasoning) ? (thinkResponse.data as any).reasoning.join(" ") : (thinkResponse.data as any).reasoning; const confidenceResponse = await invokeTool("assess_confidence", { reasoning: reasoningText, evidence: ["Users are frustrated", "Performance is slow"], }); expect(confidenceResponse.success).toBe(true); // 6. Store the solution as a memory const solutionResponse = await invokeTool("remember", { content: `Solution: ${(thinkResponse.data as any).conclusion}`, userId: testUserId, sessionId: testSessionId, primarySector: "procedural", metadata: { keywords: ["solution", "performance", "improvement"], tags: ["solution", "action-item"], category: "solutions", importance: 0.9, }, }); expect(solutionResponse.success).toBe(true); }); }); describe("Error Handling Across Tool Boundaries", () => { it("should handle invalid parameters gracefully", async () => { // Missing required field const response1 = await invokeTool("remember", { content: "Test content", // Missing userId, sessionId, primarySector }); expect(response1.success).toBe(false); expect(response1.error).toBeDefined(); expect(response1.suggestion).toBeDefined(); // Invalid sector type const response2 = await invokeTool("remember", { content: "Test content", userId: testUserId, sessionId: testSessionId, primarySector: "invalid-sector", }); expect(response2.success).toBe(false); expect(response2.error).toBeDefined(); // Invalid strength value const response3 = await invokeTool("update_memory", { memoryId: "non-existent", userId: testUserId, strength: 1.5, // Out of range }); expect(response3.success).toBe(false); expect(response3.error).toBeDefined(); }); it("should handle non-existent resources gracefully", async () => { // Retrieve non-existent memory const response1 = await invokeTool("recall", { userId: "non-existent-user", text: "test", }); expect(response1.success).toBe(true); expect((response1.data as any).memories).toHaveLength(0); // Update non-existent memory const response2 = await invokeTool("update_memory", { memoryId: "non-existent-id", userId: testUserId, content: "Updated content", }); expect(response2.success).toBe(false); expect(response2.error).toContain("not found"); // Delete non-existent memory const response3 = await invokeTool("forget", { memoryId: "non-existent-id", userId: testUserId, }); expect(response3.success).toBe(false); expect(response3.error).toContain("not found"); }); it("should handle errors in tool chains gracefully", async () => { // Store a memory successfully const storeResponse = await invokeTool("remember", { content: "Test memory for error handling", userId: testUserId, sessionId: testSessionId, primarySector: "semantic", }); expect(storeResponse.success).toBe(true); const memoryId = (storeResponse.data as any).memoryId; // Try to update with invalid parameters const updateResponse = await invokeTool("update_memory", { memoryId, userId: testUserId, strength: 2.0, // Invalid value }); expect(updateResponse.success).toBe(false); // Verify original memory is unchanged const retrieveResponse = await invokeTool("recall", { userId: testUserId, text: "error handling", }); expect(retrieveResponse.success).toBe(true); expect((retrieveResponse.data as any).memories).toHaveLength(1); expect((retrieveResponse.data as any).memories[0].strength).toBe(1.0); // Original value }); }); describe("Concurrent Tool Invocations", () => { it("should handle concurrent memory operations", { timeout: 30000 }, async () => { // Store multiple memories concurrently (reduced from 10 to 5 for stability) const storePromises = Array.from({ length: 5 }, (_, i) => invokeTool("remember", { content: `Concurrent memory ${i + 1}`, userId: testUserId, sessionId: testSessionId, primarySector: "semantic", metadata: { keywords: ["concurrent", `test${i}`], tags: ["concurrent-test"], category: "test", }, }) ); const storeResponses = await Promise.all(storePromises); // Verify most succeeded (allow for some failures due to connection pool limits) const successCount = storeResponses.filter((r) => r.success).length; expect(successCount).toBeGreaterThanOrEqual(3); // At least 60% success rate expect(storeResponses.length).toBe(5); // Verify unique memory IDs for successful operations const memoryIds = storeResponses .filter((r) => r.success) .map((r) => (r.data as any).memoryId); const uniqueIds = new Set(memoryIds); expect(uniqueIds.size).toBe(successCount); // Concurrent retrieval (reduced from 5 to 3) const retrievePromises = Array.from({ length: 3 }, () => invokeTool("recall", { userId: testUserId, text: "concurrent", limit: 20, }) ); const retrieveResponses = await Promise.all(retrievePromises); // Verify most succeeded const retrieveSuccessCount = retrieveResponses.filter((r) => r.success).length; expect(retrieveSuccessCount).toBeGreaterThanOrEqual(2); // At least 66% success rate // Verify successful retrievals found memories const successfulRetrievals = retrieveResponses.filter((r) => r.success); expect(successfulRetrievals.every((r) => (r.data as any).memories.length >= 1)).toBe(true); }); it("should handle mixed concurrent operations", async () => { // Create initial memories const initialMemories = await Promise.all( Array.from({ length: 5 }, (_, i) => invokeTool("remember", { content: `Initial memory ${i + 1}`, userId: testUserId, sessionId: testSessionId, primarySector: "semantic", }) ) ); // Verify all initial stores succeeded expect(initialMemories.every((r) => r.success)).toBe(true); const memoryIds = initialMemories.map((r) => r.data?.memoryId).filter(Boolean); // Mix of operations: store, retrieve, update, search const mixedPromises = [ // Store new memories invokeTool("remember", { content: "New memory during mixed ops", userId: testUserId, sessionId: testSessionId, primarySector: "semantic", }), // Retrieve memories invokeTool("recall", { userId: testUserId, limit: 10, }), // Update existing memory invokeTool("update_memory", { memoryId: memoryIds[0], userId: testUserId, strength: 0.9, }), // Search memories invokeTool("search", { userId: testUserId, text: "memory", limit: 10, }), // Think operation invokeTool("think", { problem: "Concurrent operations test", mode: "analytical", }), ]; const mixedResponses = await Promise.all(mixedPromises); // Verify all operations succeeded expect(mixedResponses.every((r) => r.success)).toBe(true); }); }); describe("Performance Under Load", () => { it("should handle rapid sequential operations", { timeout: 60000 }, async () => { const startTime = Date.now(); const operationCount = 20; // Reduced for real embedding generation // Rapid sequential stores for (let i = 0; i < operationCount; i++) { const response = await invokeTool("remember", { content: `Rapid operation ${i + 1}`, userId: testUserId, sessionId: testSessionId, primarySector: "semantic", }); expect(response.success).toBe(true); } const duration = Date.now() - startTime; const avgTime = duration / operationCount; // Should average less than 2000ms per operation in CI environments // (accounts for embedding generation variance and CI resource constraints) expect(avgTime).toBeLessThan(2000); // Verify all memories were stored const retrieveResponse = await invokeTool("recall", { userId: testUserId, limit: 100, }); expect(retrieveResponse.success).toBe(true); expect((retrieveResponse.data as any).memories.length).toBeGreaterThanOrEqual(operationCount); }); it("should handle sustained load", { timeout: 60000 }, async () => { // Reduced batch size and count for stability const batchSize = 5; const batchCount = 3; const startTime = Date.now(); // Process in batches let totalSuccessCount = 0; for (let batch = 0; batch < batchCount; batch++) { const batchPromises = Array.from({ length: batchSize }, (_, i) => invokeTool("remember", { content: `Batch ${batch + 1} memory ${i + 1}`, userId: testUserId, sessionId: testSessionId, primarySector: "semantic", }) ); const batchResponses = await Promise.all(batchPromises); const batchSuccessCount = batchResponses.filter((r) => r.success).length; // Allow for some failures due to connection pool limits (at least 60%) expect(batchSuccessCount).toBeGreaterThanOrEqual(Math.floor(batchSize * 0.6)); totalSuccessCount += batchSuccessCount; // Longer delay between batches to allow connection pool recovery await sleep(200); } const duration = Date.now() - startTime; const avgTime = duration / Math.max(1, totalSuccessCount); // Should maintain reasonable performance (relaxed for test environment) expect(avgTime).toBeLessThan(2000); // Verify data integrity const retrieveResponse = await invokeTool("recall", { userId: testUserId, limit: 200, }); expect(retrieveResponse.success).toBe(true); expect((retrieveResponse.data as any).memories.length).toBeGreaterThanOrEqual(1); }); it("should measure reasoning performance", async () => { const problems = [ "How to improve team productivity?", "What are the best practices for code review?", "How to reduce technical debt?", "What metrics should we track?", "How to improve system reliability?", ]; const timings: number[] = []; for (const problem of problems) { const startTime = Date.now(); const response = await invokeTool("think", { problem, mode: "analytical", }); const duration = Date.now() - startTime; timings.push(duration); expect(response.success).toBe(true); } // Calculate statistics const avgTime = timings.reduce((a, b) => a + b, 0) / timings.length; const maxTime = Math.max(...timings); // Should complete in reasonable time expect(avgTime).toBeLessThan(5000); // 5 seconds average expect(maxTime).toBeLessThan(10000); // 10 seconds max }); }); describe("Real-World Scenarios", () => { it("should simulate user session workflow", async () => { // User starts session - store preferences const pref1 = await invokeTool("remember", { content: "User prefers concise responses", userId: testUserId, sessionId: testSessionId, primarySector: "semantic", metadata: { keywords: ["preference", "concise", "responses"], tags: ["user-preference"], category: "preferences", importance: 0.8, }, }); expect(pref1.success).toBe(true); // User asks a question - retrieve context const context = await invokeTool("recall", { userId: testUserId, text: "user preferences", limit: 5, }); expect(context.success).toBe(true); // System reasons about response const reasoning = await invokeTool("think", { problem: "How should I respond to this user?", mode: "analytical", context: { evidence: (context.data as any).memories.map((m: { content: string }) => m.content), }, }); expect(reasoning.success).toBe(true); // Update preference based on interaction await invokeTool("update_memory", { memoryId: (pref1.data as any).memoryId, userId: testUserId, strength: 0.95, // Reinforce preference }); // Store interaction outcome const outcome = await invokeTool("remember", { content: "User was satisfied with concise response", userId: testUserId, sessionId: testSessionId, primarySector: "episodic", metadata: { keywords: ["interaction", "satisfaction", "concise"], tags: ["outcome", "positive"], category: "interactions", importance: 0.7, }, }); expect(outcome.success).toBe(true); }); it("should simulate problem-solving workflow", async () => { // 1. Decompose complex problem const decompose = await invokeTool("breakdown", { problem: "Launch a new product successfully", maxDepth: 2, }); expect(decompose.success).toBe(true); expect((decompose.data as any).subProblems).toBeDefined(); // 2. Analyze systematically const analysis = await invokeTool("analyze", { problem: "Launch a new product successfully", context: { evidence: ["Market research completed", "Budget approved"], constraints: ["6-month timeline", "Limited team"], }, }); expect(analysis.success).toBe(true); // 3. Think in parallel for comprehensive solution const parallel = await invokeTool("ponder", { problem: "Launch a new product successfully", context: { evidence: ["Market research completed", "Budget approved"], constraints: ["6-month timeline", "Limited team"], goals: ["Market share: 5%", "Revenue: $1M"], }, }); expect(parallel.success).toBe(true); // 4. Assess confidence in the plan const confidence = await invokeTool("assess_confidence", { reasoning: (parallel.data as any).conclusion, evidence: ["Market research completed", "Budget approved"], }); expect(confidence.success).toBe(true); // 5. Store the solution const solution = await invokeTool("remember", { content: `Product launch plan: ${(parallel.data as any).conclusion}`, userId: testUserId, sessionId: testSessionId, primarySector: "procedural", metadata: { keywords: ["product", "launch", "plan"], tags: ["strategy", "action-plan"], category: "plans", importance: 0.95, }, }); expect(solution.success).toBe(true); }); it("should simulate learning workflow", async () => { // Store initial knowledge const initial = await invokeTool("remember", { content: "Machine learning requires large datasets", userId: testUserId, sessionId: testSessionId, primarySector: "semantic", metadata: { keywords: ["machine", "learning", "datasets"], tags: ["ml", "knowledge"], category: "learning", importance: 0.7, }, }); expect(initial.success).toBe(true); // Retrieve similar knowledge const similar = await invokeTool("recall", { userId: testUserId, text: "machine learning", limit: 10, }); expect(similar.success).toBe(true); // Reason about the knowledge const reasoning = await invokeTool("think", { problem: "What are the key requirements for successful ML projects?", mode: "synthetic", context: { evidence: (similar.data as any).memories.map((m: { content: string }) => m.content), }, }); expect(reasoning.success).toBe(true); // Update confidence in knowledge await invokeTool("update_memory", { memoryId: (initial.data as any).memoryId, userId: testUserId, strength: 0.9, metadata: { importance: 0.85, }, }); // Store new insight const insight = await invokeTool("remember", { content: `Insight: ${(reasoning.data as any).conclusion}`, userId: testUserId, sessionId: testSessionId, primarySector: "reflective", metadata: { keywords: ["insight", "ml", "requirements"], tags: ["learning", "insight"], category: "insights", importance: 0.8, }, }); expect(insight.success).toBe(true); }); }); });

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