Skip to main content
Glama

Retrieval-Augmented Thinking MCP Server

by stat-guy
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, ToolSchema, } from "@modelcontextprotocol/sdk/types.js"; // Data structures matching the original Python implementation class ThoughtMetrics { constructor() { this.complexity = 0; this.depth = 0; this.quality = 0; this.impact = 0; this.confidence = 0; } } class ThoughtData { constructor(data) { this.content = data.thought || ""; this.thought_number = data.thoughtNumber || 1; this.total_thoughts = data.totalThoughts || 1; this.next_thought_needed = data.nextThoughtNeeded || false; this.is_revision = data.isRevision || false; this.revises_thought = data.revisesThought || null; this.branch_from_thought = data.branchFromThought || null; this.branch_id = data.branchId || null; this.needs_more_thoughts = data.needsMoreThoughts || false; this.timestamp = Date.now(); this.metrics = new ThoughtMetrics(); this.processed = false; } } class Analytics { constructor() { this.total_thoughts = 0; this.total_revisions = 0; this.total_branches = 0; this.chain_effectiveness = 0; this.revision_impact = 0; this.branch_success_rate = 0; this.average_quality = 0; this.quality_trend = []; this.session_start = Date.now(); this.last_update = Date.now(); } updateMetrics(thought) { this.total_thoughts += 1; this.last_update = Date.now(); if (thought.is_revision) { this.total_revisions += 1; } if (thought.branch_id) { this.total_branches += 1; } // Update quality tracking const currentQuality = thought.metrics.quality; this.quality_trend.push(currentQuality); // Keep only last 20 quality scores if (this.quality_trend.length > 20) { this.quality_trend = this.quality_trend.slice(-20); } // Recalculate average quality if (this.quality_trend.length > 0) { this.average_quality = this.quality_trend.reduce((a, b) => a + b) / this.quality_trend.length; } // Update effectiveness metrics this._calculateEffectiveness(); } _calculateEffectiveness() { if (this.total_thoughts > 0) { // Chain effectiveness based on quality trend if (this.quality_trend.length >= 2) { const recent = this.quality_trend.slice(-5); const early = this.quality_trend.slice(0, 5); const recentAvg = recent.reduce((a, b) => a + b) / recent.length; const earlyAvg = early.reduce((a, b) => a + b) / early.length; this.chain_effectiveness = earlyAvg > 0 ? Math.max(0, (recentAvg - earlyAvg) / earlyAvg) : 0; } // Revision impact if (this.total_thoughts > 0) { this.revision_impact = Math.min(1.0, this.total_revisions / this.total_thoughts * 2); } // Branch success rate (placeholder) if (this.total_branches > 0) { this.branch_success_rate = 0.7; } } } } class ThoughtProcessor { constructor() { this.processed_count = 0; this.reasoning_keywords = [ 'because', 'therefore', 'thus', 'hence', 'consequently', 'since', 'given', 'assuming', 'implies', 'suggests', 'indicates', 'demonstrates', 'proves', 'shows', 'reveals' ]; this.impact_keywords = [ 'important', 'critical', 'significant', 'key', 'essential', 'fundamental', 'crucial', 'vital', 'major', 'primary' ]; } async processThought(thoughtData) { // Validate this._validateThought(thoughtData); // Sanitize content thoughtData.content = this._sanitizeContent(thoughtData.content); // Calculate metrics thoughtData.metrics = this._calculateMetrics(thoughtData); // Mark as processed thoughtData.processed = true; thoughtData.timestamp = Date.now(); this.processed_count++; return thoughtData; } _validateThought(thought) { if (!thought.content || !thought.content.trim()) { throw new Error("Thought content cannot be empty"); } if (thought.thought_number < 1) { throw new Error("Thought number must be positive"); } if (thought.total_thoughts < 1) { throw new Error("Total thoughts must be positive"); } if (thought.thought_number > thought.total_thoughts && !thought.needs_more_thoughts) { throw new Error("Thought number cannot exceed total thoughts unless extending"); } } _sanitizeContent(content) { // Remove excessive whitespace content = content.replace(/\s+/g, ' ').trim(); // Remove problematic characters content = content.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, ''); // Normalize line endings content = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n'); // Limit length if (content.length > 10000) { content = content.substring(0, 10000) + "... [truncated]"; } return content; } _calculateMetrics(thought) { const content = thought.content.toLowerCase(); // Calculate complexity const complexity = this._calculateComplexity(thought.content); // Calculate depth const depth = this._calculateDepth(thought.content); // Calculate impact const impact = this._calculateImpact(content); // Calculate quality const quality = this._calculateQuality(complexity, depth, impact, thought); // Calculate confidence const confidence = this._calculateConfidence(content, complexity, depth); thought.metrics.complexity = Math.round(complexity * 1000) / 1000; thought.metrics.depth = Math.round(depth * 1000) / 1000; thought.metrics.quality = Math.round(quality * 1000) / 1000; thought.metrics.impact = Math.round(impact * 1000) / 1000; thought.metrics.confidence = Math.round(confidence * 1000) / 1000; return thought.metrics; } _calculateComplexity(content) { const colons = (content.match(/:/g) || []).length; const semicolons = (content.match(/;/g) || []).length; const dashes = (content.match(/-/g) || []).length; const parentheses = (content.match(/[()]/g) || []).length; const questions = (content.match(/\?/g) || []).length; const sentences = content.split(/[.!?]+/).filter(s => s.trim()).length; const punctuationScore = (colons * 0.3 + semicolons * 0.2 + dashes * 0.1 + parentheses * 0.05 + questions * 0.2); const sentenceComplexity = sentences * 0.1; return Math.min(1.0, (punctuationScore + sentenceComplexity) / 10); } _calculateDepth(content) { const wordCount = content.split(/\s+/).length; const charCount = content.length; const wordDepth = Math.min(1.0, wordCount / 100); const charDepth = Math.min(1.0, charCount / 500); return (wordDepth * 0.6 + charDepth * 0.4); } _calculateImpact(contentLower) { const reasoningScore = this.reasoning_keywords.filter(keyword => contentLower.includes(keyword)).length; const impactScore = this.impact_keywords.filter(keyword => contentLower.includes(keyword)).length; const structurePatterns = [ /\b(first|second|third|finally|lastly)\b/, /\b(step \d+|\d+\.|\d+\))/, /\b(therefore|thus|hence|consequently)\b/ ]; const structureScore = structurePatterns.filter(pattern => pattern.test(contentLower)).length; const totalScore = reasoningScore + impactScore + structureScore; return Math.min(1.0, totalScore / 8); } _calculateQuality(complexity, depth, impact, thought) { let baseQuality = (complexity * 0.3 + depth * 0.4 + impact * 0.3); if (thought.is_revision) { baseQuality *= 1.1; // 10% bonus for revisions } if (thought.branch_id) { baseQuality *= 1.05; // 5% bonus for branches } return Math.min(1.0, baseQuality); } _calculateConfidence(contentLower, complexity, depth) { const uncertaintyPatterns = [ /\b(maybe|perhaps|possibly|might|could be|uncertain)\b/, /\b(not sure|unclear|ambiguous)\b/ ]; const uncertaintyScore = uncertaintyPatterns.filter(pattern => pattern.test(contentLower)).length; const certaintyPatterns = [ /\b(clearly|obviously|definitely|certainly|undoubtedly)\b/, /\b(proven|established|confirmed)\b/ ]; const certaintyScore = certaintyPatterns.filter(pattern => pattern.test(contentLower)).length; const structureConfidence = (complexity + depth) / 2; const languageAdjustment = (certaintyScore - uncertaintyScore) * 0.1; return Math.max(0.0, Math.min(1.0, structureConfidence + languageAdjustment)); } } // Main server class class RatServer { constructor() { this.thought_history = []; this.analytics = new Analytics(); this.processor = new ThoughtProcessor(); } async processThought(arguments_obj) { try { // Create thought data const thoughtData = new ThoughtData(arguments_obj); // Process the thought const processedThought = await this.processor.processThought(thoughtData); // Add to history this.thought_history.push(processedThought); // Update analytics this.analytics.updateMetrics(processedThought); // Generate visual output const visualOutput = this._formatThoughtDisplay(processedThought); // Create response const responseData = { thought_number: processedThought.thought_number, total_thoughts: processedThought.total_thoughts, metrics: { complexity: processedThought.metrics.complexity, depth: processedThought.metrics.depth, quality: processedThought.metrics.quality, impact: processedThought.metrics.impact, confidence: processedThought.metrics.confidence }, analytics: { total_thoughts: this.analytics.total_thoughts, average_quality: this.analytics.average_quality, chain_effectiveness: this.analytics.chain_effectiveness }, next_thought_needed: processedThought.next_thought_needed, visual_output: visualOutput }; return { content: [{ type: "text", text: JSON.stringify(responseData, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: JSON.stringify({ error: error.message, status: 'failed' }, null, 2) }], isError: true }; } } _formatThoughtDisplay(thought) { // Create title based on thought type let title; if (thought.is_revision) { title = `💭 Revision of Thought ${thought.revises_thought}`; } else if (thought.branch_id) { title = `🌿 Branch ${thought.branch_id} from Thought ${thought.branch_from_thought}`; } else { title = `💭 Thought ${thought.thought_number}/${thought.total_thoughts}`; } // Create metrics display const metricsText = `Complexity: ${thought.metrics.complexity.toFixed(2)} | ` + `Depth: ${thought.metrics.depth.toFixed(2)} | ` + `Quality: ${thought.metrics.quality.toFixed(2)} | ` + `Impact: ${thought.metrics.impact.toFixed(2)} | ` + `Confidence: ${thought.metrics.confidence.toFixed(2)}`; // Format content const contentLines = thought.content.split('\n').map(line => line.trim()); const formattedContent = contentLines.join('\n'); // Create the display const borderLength = 60; const titleBorder = '─'.repeat(Math.max(0, borderLength - title.length - 4)); const metricsBorder = '─'.repeat(50); const displayParts = [ `┌─ ${title} ─${titleBorder}┐`, `│ ${formattedContent.substring(0, 56).padEnd(58)} │`, `├─ Metrics ─${metricsBorder}┤`, `│ ${metricsText.substring(0, 56).padEnd(58)} │`, `└${'─'.repeat(borderLength)}┘` ]; return displayParts.join('\n'); } } // Define the RAT tool const RAT_TOOL = { name: "rat", description: "A context-aware reasoning system that orchestrates structured thought processes through dynamic trajectories.\n\nCore Capabilities:\n- Maintains adaptive thought chains with branching and revision capabilities\n- Implements iterative hypothesis generation and validation cycles\n- Preserves context coherence across non-linear reasoning paths\n- Supports dynamic scope adjustment and trajectory refinement\n\nReasoning Patterns:\n- Sequential analysis with backtracking capability\n- Parallel exploration through managed branch contexts\n- Recursive refinement via structured revision cycles\n- Hypothesis validation through multi-step verification\n\nParameters:\nthought: Structured reasoning step that supports:\n• Primary analysis chains\n• Hypothesis formulation/validation\n• Branch exploration paths\n• Revision proposals\n• Context preservation markers\n• Verification checkpoints\n\nnext_thought_needed: Signal for continuation of reasoning chain\nthought_number: Position in current reasoning trajectory\ntotal_thoughts: Dynamic scope indicator (adjustable)\nis_revision: Marks recursive refinement steps\nrevises_thought: References target of refinement\nbranch_from_thought: Indicates parallel exploration paths\nbranch_id: Context identifier for parallel chains\nneeds_more_thoughts: Signals scope expansion requirement\n\nExecution Protocol:\n1. Initialize with scope estimation\n2. Generate structured reasoning steps\n3. Validate hypotheses through verification cycles\n4. Maintain context coherence across branches\n5. Implement revisions through recursive refinement\n6. Signal completion on validation success\n\nThe system maintains solution integrity through continuous validation cycles while supporting dynamic scope adjustment and non-linear exploration paths.", 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", minimum: 1, description: "Current thought number" }, totalThoughts: { type: "integer", minimum: 1, description: "Estimated total thoughts needed" }, isRevision: { type: "boolean", description: "Whether this revises previous thinking" }, revisesThought: { type: "integer", minimum: 1, description: "Which thought is being reconsidered" }, branchFromThought: { type: "integer", minimum: 1, description: "Branching point thought number" }, branchId: { type: "string", description: "Branch identifier" }, needsMoreThoughts: { type: "boolean", description: "If more thoughts are needed" } }, required: ["thought", "nextThoughtNeeded", "thoughtNumber", "totalThoughts"] } }; // Create and configure server const server = new Server( { name: "mcp-server-rat-node", version: "0.1.0", }, { capabilities: { tools: {}, }, } ); const ratServer = new RatServer(); // Set up request handlers server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [RAT_TOOL], })); server.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name === "rat") { return ratServer.processThought(request.params.arguments); } return { content: [{ type: "text", text: `Unknown tool: ${request.params.name}` }], isError: true }; }); // Run the server async function runServer() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("RAT MCP Server (Node.js) running on stdio"); } runServer().catch((error) => { console.error("Fatal error running server:", error); process.exit(1); });

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/stat-guy/retrieval-augmented-thinking'

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