Skip to main content
Glama
integration.test.ts10.8 kB
import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; import { describe, it, expect, beforeAll, afterAll } from '@jest/globals'; interface ToolResponse { content: Array<{ type: string; text: string }>; isError?: boolean; } // Debug logging utility const DEBUG = process.env.DEBUG_LOGS === 'true'; function debugLog(...args: any[]): void { if (DEBUG) { console.log(...args); } } describe('Sequential Thinking Server Integration', () => { let client: Client; let transport: StdioClientTransport; beforeAll(async () => { console.log('Setting up Sequential Thinking server test...'); // Set up the transport transport = new StdioClientTransport({ command: "node", args: ["dist/index.js"], env: { NODE_ENV: "test", DEBUG: "mcp:*" // Enable MCP debug logging } }); console.log('Created transport with command: node dist/index.js'); // Set up the client client = new Client( { name: "sequential-thinking-test-client", version: "1.0.0" }, { capabilities: { tools: { list: true, call: true } } } ); try { console.log('Attempting to connect to server...'); // Connect to the server with a timeout let timeoutId: NodeJS.Timeout; const connectPromise = client.connect(transport); const timeoutPromise = new Promise<void>((_, reject) => { timeoutId = setTimeout(() => reject(new Error('Connection timeout')), 5000); }); await Promise.race([connectPromise, timeoutPromise]) .finally(() => { clearTimeout(timeoutId); }); console.log('Successfully connected to server'); // Small delay to ensure server is ready await new Promise(resolve => setTimeout(resolve, 1000)); } catch (error) { console.error('Failed to connect to server:', error); throw error; } }); afterAll(async () => { try { console.log('Cleaning up...'); // First close the client if (client) { console.log('Closing client...'); await client.close(); console.log('Client closed successfully'); } // Then close the transport if (transport) { console.log('Closing transport...'); transport.close(); // Allow time for the subprocess to terminate await new Promise<void>(resolve => { setTimeout(resolve, 500); }); console.log('Transport closed successfully'); } } catch (err) { console.error('Error during cleanup:', err); } }); it('should list available tools', async () => { console.log('Testing tool listing...'); const response = await client.listTools(); debugLog('List tools response:', JSON.stringify(response, null, 2)); expect(response).toBeDefined(); expect(response).toHaveProperty('tools'); expect(Array.isArray(response.tools)).toBe(true); expect(response.tools.length).toBeGreaterThan(0); // Check for our specific tools const toolNames = response.tools.map(tool => tool.name); debugLog('Available tools:', toolNames); expect(toolNames).toContain('capture_thought'); expect(toolNames).toContain('revise_thought'); expect(toolNames).toContain('get_thinking_summary'); expect(toolNames).toContain('clear_thinking_history'); }); it('should process a thought and generate a summary', async () => { console.log('Testing sequential thinking workflow...'); // Clear any existing history first const clearResult = await client.callTool({ name: "clear_thinking_history", arguments: {} }) as ToolResponse; debugLog('Clear history response:', JSON.stringify(clearResult, null, 2)); expect(clearResult.isError).toBeFalsy(); const clearData = JSON.parse(clearResult.content[0].text); debugLog('Clear history data:', clearData); expect(clearData.status).toBe("success"); console.log('History cleared successfully'); // Submit a thought const thoughtResult = await client.callTool({ name: "capture_thought", arguments: { thought: "This is a test thought for integration testing", thought_number: 1, total_thoughts: 3, next_thought_needed: true, stage: "Problem Definition" } }) as ToolResponse; debugLog('Thought processing response:', JSON.stringify(thoughtResult, null, 2)); expect(thoughtResult.isError).toBeFalsy(); const thoughtData = JSON.parse(thoughtResult.content[0].text); debugLog('Thought processing data:', thoughtData); expect(thoughtData).toHaveProperty('thoughtAnalysis'); expect(thoughtData.thoughtAnalysis.currentThought.thoughtNumber).toBe(1); expect(thoughtData.thoughtAnalysis.currentThought.stage).toBe("Problem Definition"); console.log('Thought processed successfully'); // Get summary const summaryResult = await client.callTool({ name: "get_thinking_summary", arguments: {} }) as ToolResponse; debugLog('Summary response:', JSON.stringify(summaryResult, null, 2)); expect(summaryResult.isError).toBeFalsy(); const summaryData = JSON.parse(summaryResult.content[0].text); debugLog('Summary data:', summaryData); expect(summaryData).toHaveProperty('summary'); expect(summaryData.summary.totalThoughts).toBe(1); expect(summaryData.summary.stages).toHaveProperty('Problem Definition'); console.log('Summary generated successfully'); }); it('should handle thought sequencing and branching', async () => { // Clear history before test const clearResult = await client.callTool({ name: "clear_thinking_history", arguments: {} }); debugLog('Clear history response (branching test):', JSON.stringify(clearResult, null, 2)); // Add first thought const thought1Result = await client.callTool({ name: "capture_thought", arguments: { thought: "Initial thought", thought_number: 1, total_thoughts: 3, next_thought_needed: true, stage: "Problem Definition", score: 0.7 } }) as ToolResponse; debugLog('First thought response:', JSON.stringify(thought1Result, null, 2)); expect(thought1Result.isError).toBeFalsy(); // Add second thought in sequence const thought2Result = await client.callTool({ name: "capture_thought", arguments: { thought: "Follow-up thought", thought_number: 2, total_thoughts: 3, next_thought_needed: true, stage: "Analysis", score: 0.8 } }) as ToolResponse; debugLog('Second thought response:', JSON.stringify(thought2Result, null, 2)); expect(thought2Result.isError).toBeFalsy(); // Add a branch thought const branchResult = await client.callTool({ name: "capture_thought", arguments: { thought: "Alternative approach", thought_number: 1, total_thoughts: 2, next_thought_needed: true, stage: "Ideation", branch_from_thought: 1, branch_id: "alt-branch", score: 0.9 } }) as ToolResponse; debugLog('Branch thought response:', JSON.stringify(branchResult, null, 2)); expect(branchResult.isError).toBeFalsy(); const branchData = JSON.parse(branchResult.content[0].text); debugLog('Branch data:', branchData); expect(branchData.thoughtAnalysis.context.activeBranches).toContain("alt-branch"); // Get summary and check branches const summaryResult = await client.callTool({ name: "get_thinking_summary", arguments: {} }) as ToolResponse; debugLog('Final summary response:', JSON.stringify(summaryResult, null, 2)); const summaryData = JSON.parse(summaryResult.content[0].text); debugLog('Final summary data:', summaryData); expect(summaryData.summary.totalThoughts).toBe(3); expect(summaryData.summary.branches).toHaveProperty("alt-branch"); console.log('Branching handled successfully'); }); it('should revise an existing thought', async () => { // Clear history before test const clearResult = await client.callTool({ name: "clear_thinking_history", arguments: {} }); debugLog('Clear history response (revision test):', JSON.stringify(clearResult, null, 2)); // Add a thought to revise const originalThought = await client.callTool({ name: "capture_thought", arguments: { thought: "Initial thought that needs revision", thought_number: 1, total_thoughts: 2, next_thought_needed: true, stage: "Problem Definition", score: 0.6 } }) as ToolResponse; debugLog('Original thought response:', JSON.stringify(originalThought, null, 2)); expect(originalThought.isError).toBeFalsy(); const originalData = JSON.parse(originalThought.content[0].text); expect(originalData.thoughtAnalysis.currentThought.thoughtNumber).toBe(1); expect(originalData.thoughtAnalysis.currentThought.score).toBe(0.6); // Revise the thought const revisionResult = await client.callTool({ name: "revise_thought", arguments: { thought_id: 1, thought: "Revised and improved thought", score: 0.8, tags: ["improved", "revised"] } }) as ToolResponse; debugLog('Revision response:', JSON.stringify(revisionResult, null, 2)); expect(revisionResult.isError).toBeFalsy(); const revisionData = JSON.parse(revisionResult.content[0].text); expect(revisionData.status).toBe("success"); expect(revisionData.revision.updated).toBe(true); // Get summary to verify the revision const summaryResult = await client.callTool({ name: "get_thinking_summary", arguments: {} }) as ToolResponse; const summaryData = JSON.parse(summaryResult.content[0].text); debugLog('Summary after revision:', summaryData); expect(summaryData.summary.totalThoughts).toBe(1); // Test error handling for invalid thought ID const errorResult = await client.callTool({ name: "revise_thought", arguments: { thought_id: 999 // Non-existent thought ID } }) as ToolResponse; debugLog('Error response:', JSON.stringify(errorResult, null, 2)); expect(errorResult.isError).toBe(true); const errorData = JSON.parse(errorResult.content[0].text); expect(errorData.status).toBe("failed"); expect(errorData.error).toContain("not found"); }); });

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/Promptly-Technologies-LLC/mcp-structured-thinking'

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