UNPKG

enhanced-thinking-mcp

Version:

Enhanced sequential thinking MCP server for advanced reasoning and problem-solving with Cursor AI

592 lines (584 loc) 25.7 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import chalk from 'chalk'; import { env, exit } from 'process'; import { join } from 'path'; import { homedir } from 'os'; import { LLMEnhancer } from './llm-integration.js'; import { ThinkingDatabase } from './database.js'; class EnhancedThinkingServer { thoughtHistory = []; branches = {}; sessionStart; disableThoughtLogging; llmEnhancer; database; currentSessionId = null; constructor() { this.disableThoughtLogging = (env.DISABLE_THOUGHT_LOGGING || "").toLowerCase() === "true"; this.sessionStart = Date.now(); this.llmEnhancer = new LLMEnhancer(); // Use fixed path in user's home directory for central database const centralDbPath = join(homedir(), '.enhanced-thinking-sessions.json'); const dashboardUrl = env.DASHBOARD_URL || 'https://enhanced-thinking-dashboard.vercel.app'; this.database = new ThinkingDatabase(centralDbPath, dashboardUrl); if (!this.disableThoughtLogging) { console.error(`💾 Central database: ${centralDbPath}`); } } generateSessionId() { return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } validateThoughtData(input) { const data = input; if (!data.thought || typeof data.thought !== 'string') { throw new Error('Invalid thought: must be a string'); } if (!data.thoughtNumber || typeof data.thoughtNumber !== 'number') { throw new Error('Invalid thoughtNumber: must be a number'); } if (!data.totalThoughts || typeof data.totalThoughts !== 'number') { throw new Error('Invalid totalThoughts: must be a number'); } if (typeof data.nextThoughtNeeded !== 'boolean') { throw new Error('Invalid nextThoughtNeeded: must be a boolean'); } return { thought: data.thought, thoughtNumber: data.thoughtNumber, totalThoughts: data.totalThoughts, nextThoughtNeeded: data.nextThoughtNeeded, isRevision: data.isRevision, revisesThought: data.revisesThought, branchFromThought: data.branchFromThought, branchId: data.branchId, needsMoreThoughts: data.needsMoreThoughts, confidence: data.confidence, tags: data.tags, timestamp: Date.now(), }; } calculateQualityScore(thought) { // Enhanced quality scoring algorithm let score = 0; // Length and structure (20 points) const wordCount = thought.split(/\s+/).length; if (wordCount >= 10 && wordCount <= 100) score += 20; else if (wordCount >= 5) score += 10; // Question marks indicate exploratory thinking (15 points) const questionCount = (thought.match(/\?/g) || []).length; score += Math.min(questionCount * 5, 15); // Keywords indicating analysis (25 points) const analysisKeywords = ['because', 'therefore', 'however', 'although', 'consider', 'analyze', 'examine', 'evaluate']; const keywordCount = analysisKeywords.filter(keyword => thought.toLowerCase().includes(keyword)).length; score += Math.min(keywordCount * 5, 25); // Structure indicators (20 points) const structureIndicators = ['first', 'second', 'then', 'next', 'finally', 'step', 'phase']; const structureCount = structureIndicators.filter(indicator => thought.toLowerCase().includes(indicator)).length; score += Math.min(structureCount * 4, 20); // Hypothesis/solution language (20 points) const solutionKeywords = ['solution', 'approach', 'strategy', 'hypothesis', 'conclusion', 'answer']; const solutionCount = solutionKeywords.filter(keyword => thought.toLowerCase().includes(keyword)).length; score += Math.min(solutionCount * 4, 20); return Math.min(score, 100); } generateProgressBar(current, total) { const percentage = (current / total) * 100; const filled = Math.round(percentage / 10); const empty = 10 - filled; const bar = '█'.repeat(filled) + '░'.repeat(empty); return `${bar} ${percentage.toFixed(1)}%`; } async generateSummary() { if (this.thoughtHistory.length === 0) return "No thoughts processed yet."; const analytics = this.calculateAnalytics(); const keyInsights = await this.extractKeyInsights(); return ` 🧠 THINKING SESSION SUMMARY ${chalk.cyan('─'.repeat(50))} 📊 Analytics: • Total Thoughts: ${analytics.totalThoughts} • Average Quality: ${analytics.averageQuality.toFixed(1)}/100 • Branches Created: ${analytics.totalBranches} • Session Duration: ${(analytics.sessionDuration / 1000 / 60).toFixed(1)} min • Revisions Made: ${analytics.revisionCount} • LLM Enhancements: ${analytics.llmEnhancementsUsed} 💡 Key Insights: ${keyInsights.map(insight => ` • ${insight}`).join('\n')} 🎯 Final Confidence: ${analytics.confidenceProgression[analytics.confidenceProgression.length - 1] || 'N/A'}% ${chalk.cyan('─'.repeat(50))} `; } calculateAnalytics() { const totalThoughts = this.thoughtHistory.length; const averageQuality = totalThoughts > 0 ? this.thoughtHistory.reduce((sum, t) => sum + (t.qualityScore || 0), 0) / totalThoughts : 0; const totalBranches = Object.keys(this.branches).length; const sessionDuration = Date.now() - this.sessionStart; const revisionCount = this.thoughtHistory.filter(t => t.isRevision).length; const llmEnhancementsUsed = this.thoughtHistory.filter(t => t.enhancedThought).length; const confidenceProgression = this.thoughtHistory .filter(t => t.confidence !== undefined) .map(t => t.confidence); return { totalThoughts, averageQuality, totalBranches, sessionDuration, revisionCount, confidenceProgression, llmEnhancementsUsed }; } async extractKeyInsights() { const insights = []; // Try LLM-powered insights first if (this.llmEnhancer.isEnabled() && this.thoughtHistory.length > 2) { try { const llmInsights = await this.llmEnhancer.generateInsights(this.thoughtHistory.map(t => ({ thought: t.thought, qualityScore: t.qualityScore }))); if (llmInsights.length > 0) { insights.push(...llmInsights); } } catch (error) { console.error("🤖 LLM: Failed to generate insights:", error); } } // Fallback to traditional insights if (insights.length === 0) { // Find high-quality thoughts const highQualityThoughts = this.thoughtHistory .filter(t => (t.qualityScore || 0) >= 80) .slice(-3); highQualityThoughts.forEach((thought, index) => { const preview = thought.thought.substring(0, 60) + (thought.thought.length > 60 ? '...' : ''); insights.push(`High-quality insight #${index + 1}: "${preview}"`); }); // Identify solution patterns const solutionThoughts = this.thoughtHistory.filter(t => t.thought.toLowerCase().includes('solution') || t.thought.toLowerCase().includes('conclusion') || t.thought.toLowerCase().includes('answer')); if (solutionThoughts.length > 0) { insights.push(`${solutionThoughts.length} solution-oriented thoughts identified`); } // Branch analysis if (Object.keys(this.branches).length > 0) { insights.push(`Explored ${Object.keys(this.branches).length} alternative reasoning paths`); } // LLM enhancement info const enhancedCount = this.thoughtHistory.filter(t => t.enhancedThought).length; if (enhancedCount > 0) { insights.push(`${enhancedCount} thoughts enhanced by AI for improved clarity`); } } return insights.length > 0 ? insights : ["Session completed with systematic thinking approach"]; } formatThought(thoughtData) { const { thoughtNumber, totalThoughts, thought, isRevision, revisesThought, branchFromThought, branchId, qualityScore, confidence, enhancedThought, llmImprovements } = thoughtData; let prefix = ''; let context = ''; if (isRevision) { prefix = chalk.yellow('🔄 Revision'); context = ` (revising thought ${revisesThought})`; } else if (branchFromThought) { prefix = chalk.green('🌿 Branch'); context = ` (from thought ${branchFromThought}, ID: ${branchId})`; } else { prefix = chalk.blue('💭 Thought'); context = ''; } const progress = this.generateProgressBar(thoughtNumber, totalThoughts); const quality = qualityScore ? chalk.magenta(`Q:${qualityScore}/100`) : ''; const conf = confidence ? chalk.cyan(`C:${confidence}%`) : ''; const aiEnhanced = enhancedThought ? chalk.green('🤖AI') : ''; const metrics = [quality, conf, aiEnhanced].filter(Boolean).join(' '); const header = `${prefix} ${thoughtNumber}/${totalThoughts}${context} ${metrics}`; const progressLine = `${chalk.gray('Progress:')} ${progress}`; const displayThought = enhancedThought || thought; const maxWidth = Math.max(header.length, displayThought.length, progressLine.length) + 4; const border = '─'.repeat(maxWidth); let output = ` ┌${border}┐ │ ${header.padEnd(maxWidth - 2)} │ │ ${progressLine.padEnd(maxWidth - 2)} │ ├${border}┤ │ ${displayThought.padEnd(maxWidth - 2)} │`; if (llmImprovements && llmImprovements.length > 0) { output += `\n├${border}┤`; llmImprovements.forEach(improvement => { output += `\n│ ${chalk.green('✨')} ${improvement.padEnd(maxWidth - 4)} │`; }); } output += `\n└${border}┘`; return output; } async processThought(input) { try { const validatedInput = this.validateThoughtData(input); if (validatedInput.thoughtNumber > validatedInput.totalThoughts) { validatedInput.totalThoughts = validatedInput.thoughtNumber; } // Create new session if this is the first thought if (validatedInput.thoughtNumber === 1 && !this.currentSessionId) { this.currentSessionId = this.generateSessionId(); await this.database.createSession(this.currentSessionId); console.error(`💾 New thinking session: ${this.currentSessionId}`); } // Calculate quality score validatedInput.qualityScore = this.calculateQualityScore(validatedInput.thought); // Try LLM enhancement if enabled if (this.llmEnhancer.isEnabled()) { try { const enhancement = await this.llmEnhancer.enhanceThought({ thought: validatedInput.thought, quality_score: validatedInput.qualityScore, confidence: validatedInput.confidence, previous_thoughts: this.thoughtHistory.slice(-3).map(t => t.thought) }); if (enhancement) { validatedInput.enhancedThought = enhancement.enhanced_thought; validatedInput.llmImprovements = enhancement.reasoning_improvements; // Boost confidence if LLM provided improvements if (validatedInput.confidence && enhancement.confidence_boost > 0) { validatedInput.confidence = Math.min(100, validatedInput.confidence + enhancement.confidence_boost); } } } catch (error) { console.error("🤖 LLM: Enhancement failed, continuing with original thought"); } } this.thoughtHistory.push(validatedInput); // Save thought to database if (this.currentSessionId) { await this.database.saveThought(this.currentSessionId, validatedInput); } if (validatedInput.branchFromThought && validatedInput.branchId) { if (!this.branches[validatedInput.branchId]) { this.branches[validatedInput.branchId] = []; } this.branches[validatedInput.branchId].push(validatedInput); } if (!this.disableThoughtLogging) { const formattedThought = this.formatThought(validatedInput); console.error(formattedThought); // Show summary if this is the final thought if (!validatedInput.nextThoughtNeeded) { const summary = await this.generateSummary(); console.error(summary); // Complete session in database if (this.currentSessionId) { const analytics = this.calculateAnalytics(); const insights = await this.extractKeyInsights(); await this.database.completeSession(this.currentSessionId, analytics, insights); console.error(`💾 Session ${this.currentSessionId} completed and saved`); } } } const analytics = this.calculateAnalytics(); return { content: [{ type: "text", text: JSON.stringify({ thoughtNumber: validatedInput.thoughtNumber, totalThoughts: validatedInput.totalThoughts, nextThoughtNeeded: validatedInput.nextThoughtNeeded, qualityScore: validatedInput.qualityScore, confidence: validatedInput.confidence, enhancedThought: validatedInput.enhancedThought, llmImprovements: validatedInput.llmImprovements, branches: Object.keys(this.branches), thoughtHistoryLength: this.thoughtHistory.length, analytics: analytics, isComplete: !validatedInput.nextThoughtNeeded, sessionId: this.currentSessionId, summary: !validatedInput.nextThoughtNeeded ? await this.generateSummary() : undefined }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: JSON.stringify({ error: error instanceof Error ? error.message : String(error), status: 'failed' }, null, 2) }], isError: true }; } } resetSession() { this.thoughtHistory = []; this.branches = {}; this.sessionStart = Date.now(); this.currentSessionId = null; return { content: [{ type: "text", text: JSON.stringify({ message: "Thinking session reset successfully", status: "reset", timestamp: new Date().toISOString(), llmEnabled: this.llmEnhancer.isEnabled() }, null, 2) }] }; } async getAnalytics() { const analytics = this.calculateAnalytics(); const insights = await this.extractKeyInsights(); return { content: [{ type: "text", text: JSON.stringify({ analytics, insights, llmEnabled: this.llmEnhancer.isEnabled(), currentSessionId: this.currentSessionId, thoughtHistory: this.thoughtHistory.map(t => ({ number: t.thoughtNumber, quality: t.qualityScore, confidence: t.confidence, isRevision: t.isRevision, timestamp: t.timestamp, enhanced: !!t.enhancedThought })) }, null, 2) }] }; } } const ENHANCED_THINKING_TOOL = { name: "enhancedthinking", description: `🧠 Enhanced Sequential Thinking Tool - Advanced reasoning and problem-solving with quality analytics This enhanced version provides structured, step-by-step thinking with: ✨ Real-time quality scoring of thoughts 📊 Progress tracking with visual indicators 🎯 Confidence level monitoring 🌿 Advanced branch management 📈 Session analytics and insights 📝 Automatic summarization 🤖 LLM-powered thought enhancement (when API keys provided) Perfect for: • Complex problem decomposition • Strategic planning and analysis • Research and investigation • Creative brainstorming with structure • Decision-making processes • Learning and knowledge synthesis Enhanced Features: - Quality scoring algorithm evaluates thought depth and structure - Visual progress bars show completion status - Confidence tracking shows certainty progression - Branch visualization for alternative reasoning paths - Session analytics with key insights extraction - Auto-generated summaries of thinking sessions - Optional AI enhancement with OpenAI integration Parameters: - thought: Your current thinking step (analyzed for quality) - nextThoughtNeeded: Whether more thinking is required - thoughtNumber: Current step number (progress tracking) - totalThoughts: Estimated total (dynamically adjustable) - confidence: Your certainty level 0-100% (optional) - tags: Keywords for categorization (optional) - isRevision: Mark as revision of previous thought - revisesThought: Which thought number to revise - branchFromThought: Create alternative reasoning branch - branchId: Identifier for reasoning branch Usage Tips: 1. Start with initial thought estimate, adjust as needed 2. Use confidence levels to track certainty progression 3. Branch when exploring alternatives 4. Revise when new insights emerge 5. Set nextThoughtNeeded=false when satisfied with solution 6. Set OPENAI_API_KEY environment variable for AI enhancements`, inputSchema: { type: "object", properties: { thought: { type: "string", description: "Your current thinking step (will be analyzed for quality and structure)" }, nextThoughtNeeded: { type: "boolean", description: "Whether another thought step is needed" }, thoughtNumber: { type: "integer", description: "Current thought number (for progress tracking)", minimum: 1 }, totalThoughts: { type: "integer", description: "Estimated total thoughts needed (adjustable)", minimum: 1 }, confidence: { type: "integer", description: "Your confidence level in this thought (0-100%)", minimum: 0, maximum: 100 }, tags: { type: "array", items: { type: "string" }, description: "Keywords or categories for this thought" }, isRevision: { type: "boolean", description: "Whether this revises previous thinking" }, revisesThought: { type: "integer", description: "Which thought number is being revised", minimum: 1 }, branchFromThought: { type: "integer", description: "Create branch from this thought number", minimum: 1 }, branchId: { type: "string", description: "Identifier for this reasoning branch" }, needsMoreThoughts: { type: "boolean", description: "Flag if more thoughts are needed beyond estimate" } }, required: ["thought", "nextThoughtNeeded", "thoughtNumber", "totalThoughts"] } }; // Backward compatibility tool - original sequential thinking interface const SEQUENTIAL_THINKING_TOOL = { name: "sequentialthinking", description: `Original Sequential Thinking tool for backward compatibility. This provides the same interface as @modelcontextprotocol/server-sequential-thinking but with enhanced quality scoring and analytics under the hood. Use 'enhancedthinking' tool for full feature access including confidence tracking, quality scoring, and advanced analytics.`, inputSchema: { type: "object", properties: { thought: { type: "string", description: "Your current thinking step" }, nextThoughtNeeded: { type: "boolean", description: "Whether another thought step is needed" }, thoughtNumber: { type: "integer", description: "Current thought number", minimum: 1 }, totalThoughts: { type: "integer", description: "Estimated total thoughts needed", minimum: 1 }, isRevision: { type: "boolean", description: "Whether this revises previous thinking" }, revisesThought: { type: "integer", description: "Which thought is being reconsidered", minimum: 1 }, branchFromThought: { type: "integer", description: "Branching point thought number", minimum: 1 }, branchId: { type: "string", description: "Branch identifier" }, needsMoreThoughts: { type: "boolean", description: "If more thoughts are needed" } }, required: ["thought", "nextThoughtNeeded", "thoughtNumber", "totalThoughts"] } }; const SESSION_TOOLS = [ { name: "reset_thinking_session", description: "Reset the current thinking session, clearing all thoughts and starting fresh", inputSchema: { type: "object", properties: {}, required: [] } }, { name: "get_thinking_analytics", description: "Get detailed analytics about the current thinking session including quality metrics, insights, and progress", inputSchema: { type: "object", properties: {}, required: [] } } ]; const server = new Server({ name: "enhanced-thinking-server", version: "1.0.0", }, { capabilities: { tools: {}, }, }); const thinkingServer = new EnhancedThinkingServer(); server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ENHANCED_THINKING_TOOL, SEQUENTIAL_THINKING_TOOL, ...SESSION_TOOLS], })); server.setRequestHandler(CallToolRequestSchema, async (request) => { switch (request.params.name) { case "enhancedthinking": return await thinkingServer.processThought(request.params.arguments); case "sequentialthinking": return await thinkingServer.processThought(request.params.arguments); case "reset_thinking_session": return thinkingServer.resetSession(); case "get_thinking_analytics": return await thinkingServer.getAnalytics(); default: return { content: [{ type: "text", text: `Unknown tool: ${request.params.name}` }], isError: true }; } }); async function runServer() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("🧠 Enhanced Thinking MCP Server v1.0.0 running on stdio"); console.error("✨ Features: Quality scoring, Progress tracking, Analytics, Summarization"); console.error("🤖 LLM Integration: " + (new LLMEnhancer().isEnabled() ? "ENABLED (OpenAI)" : "Disabled (set OPENAI_API_KEY to enable)")); } runServer().catch((error) => { console.error("Fatal error running server:", error); exit(1); }); //# sourceMappingURL=index.js.map