├── .gitignore ├── package.json ├── LICENSE ├── .github └── workflows │ ├── claude.yml │ └── claude-code-review.yml ├── test.js ├── test-tool.js ├── README.md ├── CLAUDE.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules/ 3 | 4 | # Build output 5 | dist/ 6 | 7 | # IDE files 8 | .vscode/ 9 | .idea/ 10 | *.iml 11 | 12 | # OS files 13 | .DS_Store 14 | Thumbs.db 15 | 16 | # Logs 17 | *.log 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | # Environment variables 23 | .env 24 | .env.local 25 | .env.*.local 26 | 27 | # Optional npm cache directory 28 | .npm 29 | 30 | # Optional eslint cache 31 | .eslintcache 32 | 33 | # Optional REPL history 34 | .node_repl_history 35 | 36 | # Output of 'npm pack' 37 | *.tgz 38 | 39 | # Yarn Integrity file 40 | .yarn-integrity -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mcp-server-rat-node", 3 | "version": "0.1.0", 4 | "description": "Retrieval Augmented Thinking MCP Server - Node.js implementation", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "start": "node index.js", 9 | "build": "chmod +x index.js", 10 | "test": "node test.js", 11 | "postinstall": "chmod +x index.js || true", 12 | "verify": "npx mcp-server-rat-node --help 2>/dev/null && echo 'Installation successful!' || echo 'Installation needs permission fix - run: chmod +x $(npm bin -g)/mcp-server-rat-node'" 13 | }, 14 | "bin": { 15 | "mcp-server-rat-node": "./index.js" 16 | }, 17 | "keywords": ["mcp", "thinking", "reasoning", "ai"], 18 | "author": "User", 19 | "license": "MIT", 20 | "dependencies": { 21 | "@modelcontextprotocol/sdk": "^1.12.3" 22 | } 23 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLEMENTED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /.github/workflows/claude.yml: -------------------------------------------------------------------------------- 1 | name: Claude Code 2 | 3 | on: 4 | issue_comment: 5 | types: [created] 6 | pull_request_review_comment: 7 | types: [created] 8 | issues: 9 | types: [opened, assigned] 10 | pull_request_review: 11 | types: [submitted] 12 | 13 | jobs: 14 | claude: 15 | if: | 16 | (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || 17 | (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || 18 | (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || 19 | (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) 20 | runs-on: ubuntu-latest 21 | permissions: 22 | contents: read 23 | pull-requests: read 24 | issues: read 25 | id-token: write 26 | actions: read # Required for Claude to read CI results on PRs 27 | steps: 28 | - name: Checkout repository 29 | uses: actions/checkout@v4 30 | with: 31 | fetch-depth: 1 32 | 33 | - name: Run Claude Code 34 | id: claude 35 | uses: anthropics/claude-code-action@beta 36 | with: 37 | claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} 38 | 39 | # This is an optional setting that allows Claude to read CI results on PRs 40 | additional_permissions: | 41 | actions: read 42 | 43 | # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4.1) 44 | # model: "claude-opus-4-1-20250805" 45 | 46 | # Optional: Customize the trigger phrase (default: @claude) 47 | # trigger_phrase: "/claude" 48 | 49 | # Optional: Trigger when specific user is assigned to an issue 50 | # assignee_trigger: "claude-bot" 51 | 52 | # Optional: Allow Claude to run specific commands 53 | # allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)" 54 | 55 | # Optional: Add custom instructions for Claude to customize its behavior for your project 56 | # custom_instructions: | 57 | # Follow our coding standards 58 | # Ensure all new code has tests 59 | # Use TypeScript for new files 60 | 61 | # Optional: Custom environment variables for Claude 62 | # claude_env: | 63 | # NODE_ENV: test 64 | 65 | -------------------------------------------------------------------------------- /.github/workflows/claude-code-review.yml: -------------------------------------------------------------------------------- 1 | name: Claude Code Review 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize] 6 | # Optional: Only run on specific file changes 7 | # paths: 8 | # - "src/**/*.ts" 9 | # - "src/**/*.tsx" 10 | # - "src/**/*.js" 11 | # - "src/**/*.jsx" 12 | 13 | jobs: 14 | claude-review: 15 | # Optional: Filter by PR author 16 | # if: | 17 | # github.event.pull_request.user.login == 'external-contributor' || 18 | # github.event.pull_request.user.login == 'new-developer' || 19 | # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' 20 | 21 | runs-on: ubuntu-latest 22 | permissions: 23 | contents: read 24 | pull-requests: read 25 | issues: read 26 | id-token: write 27 | 28 | steps: 29 | - name: Checkout repository 30 | uses: actions/checkout@v4 31 | with: 32 | fetch-depth: 1 33 | 34 | - name: Run Claude Code Review 35 | id: claude-review 36 | uses: anthropics/claude-code-action@beta 37 | with: 38 | claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} 39 | 40 | # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4.1) 41 | # model: "claude-opus-4-1-20250805" 42 | 43 | # Direct prompt for automated review (no @claude mention needed) 44 | direct_prompt: | 45 | Please review this pull request and provide feedback on: 46 | - Code quality and best practices 47 | - Potential bugs or issues 48 | - Performance considerations 49 | - Security concerns 50 | - Test coverage 51 | 52 | Be constructive and helpful in your feedback. 53 | 54 | # Optional: Use sticky comments to make Claude reuse the same comment on subsequent pushes to the same PR 55 | # use_sticky_comment: true 56 | 57 | # Optional: Customize review based on file types 58 | # direct_prompt: | 59 | # Review this PR focusing on: 60 | # - For TypeScript files: Type safety and proper interface usage 61 | # - For API endpoints: Security, input validation, and error handling 62 | # - For React components: Performance, accessibility, and best practices 63 | # - For tests: Coverage, edge cases, and test quality 64 | 65 | # Optional: Different prompts for different authors 66 | # direct_prompt: | 67 | # ${{ github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' && 68 | # 'Welcome! Please review this PR from a first-time contributor. Be encouraging and provide detailed explanations for any suggestions.' || 69 | # 'Please provide a thorough code review focusing on our coding standards and best practices.' }} 70 | 71 | # Optional: Add specific tools for running tests or linting 72 | # allowed_tools: "Bash(npm run test),Bash(npm run lint),Bash(npm run typecheck)" 73 | 74 | # Optional: Skip review for certain conditions 75 | # if: | 76 | # !contains(github.event.pull_request.title, '[skip-review]') && 77 | # !contains(github.event.pull_request.title, '[WIP]') 78 | 79 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { spawn } from 'child_process'; 4 | 5 | function testMCPServer() { 6 | return new Promise((resolve, reject) => { 7 | const server = spawn('node', ['index.js'], { 8 | stdio: ['pipe', 'pipe', 'pipe'] 9 | }); 10 | 11 | let output = ''; 12 | let errorOutput = ''; 13 | 14 | server.stdout.on('data', (data) => { 15 | output += data.toString(); 16 | }); 17 | 18 | server.stderr.on('data', (data) => { 19 | errorOutput += data.toString(); 20 | }); 21 | 22 | // Send initialize request 23 | const initRequest = { 24 | jsonrpc: "2.0", 25 | id: 1, 26 | method: "initialize", 27 | params: { 28 | protocolVersion: "2024-11-05", 29 | capabilities: {}, 30 | clientInfo: { name: "test-client", version: "1.0.0" } 31 | } 32 | }; 33 | 34 | server.stdin.write(JSON.stringify(initRequest) + '\n'); 35 | 36 | // Send initialized notification 37 | setTimeout(() => { 38 | const initialized = { 39 | jsonrpc: "2.0", 40 | method: "notifications/initialized" 41 | }; 42 | server.stdin.write(JSON.stringify(initialized) + '\n'); 43 | 44 | // Send tools/list request 45 | const toolsRequest = { 46 | jsonrpc: "2.0", 47 | id: 2, 48 | method: "tools/list", 49 | params: {} 50 | }; 51 | server.stdin.write(JSON.stringify(toolsRequest) + '\n'); 52 | 53 | // Wait for response 54 | setTimeout(() => { 55 | server.kill(); 56 | 57 | console.log('=== Server Output ==='); 58 | console.log(output); 59 | console.log('=== Server Errors ==='); 60 | console.log(errorOutput); 61 | 62 | // Check if we got valid responses 63 | const lines = output.split('\n').filter(line => line.trim()); 64 | let hasInitResponse = false; 65 | let hasToolsResponse = false; 66 | 67 | for (const line of lines) { 68 | try { 69 | const parsed = JSON.parse(line); 70 | if (parsed.id === 1 && parsed.result) { 71 | hasInitResponse = true; 72 | console.log('✅ Initialize response received'); 73 | } 74 | if (parsed.id === 2 && parsed.result && parsed.result.tools) { 75 | hasToolsResponse = true; 76 | console.log('✅ Tools response received'); 77 | console.log(` Found ${parsed.result.tools.length} tools`); 78 | } 79 | } catch (e) { 80 | // Ignore non-JSON lines 81 | } 82 | } 83 | 84 | if (hasInitResponse && hasToolsResponse) { 85 | console.log('✅ SUCCESS: Node.js MCP server is working correctly!'); 86 | resolve(true); 87 | } else { 88 | console.log('❌ FAILED: Server did not respond correctly'); 89 | resolve(false); 90 | } 91 | }, 1000); 92 | }, 100); 93 | 94 | server.on('error', (err) => { 95 | console.error('Server error:', err); 96 | reject(err); 97 | }); 98 | }); 99 | } 100 | 101 | testMCPServer().then(success => { 102 | console.log(`\nTest ${success ? 'PASSED' : 'FAILED'}`); 103 | process.exit(success ? 0 : 1); 104 | }).catch(err => { 105 | console.error('Test error:', err); 106 | process.exit(1); 107 | }); 108 | -------------------------------------------------------------------------------- /test-tool.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { spawn } from 'child_process'; 4 | 5 | function testToolExecution() { 6 | return new Promise((resolve, reject) => { 7 | const server = spawn('node', ['index.js'], { 8 | stdio: ['pipe', 'pipe', 'pipe'] 9 | }); 10 | 11 | let output = ''; 12 | let errorOutput = ''; 13 | 14 | server.stdout.on('data', (data) => { 15 | output += data.toString(); 16 | }); 17 | 18 | server.stderr.on('data', (data) => { 19 | errorOutput += data.toString(); 20 | }); 21 | 22 | // Send initialize request 23 | const initRequest = { 24 | jsonrpc: "2.0", 25 | id: 1, 26 | method: "initialize", 27 | params: { 28 | protocolVersion: "2024-11-05", 29 | capabilities: {}, 30 | clientInfo: { name: "test-client", version: "1.0.0" } 31 | } 32 | }; 33 | 34 | server.stdin.write(JSON.stringify(initRequest) + '\n'); 35 | 36 | setTimeout(() => { 37 | // Send initialized notification 38 | const initialized = { 39 | jsonrpc: "2.0", 40 | method: "notifications/initialized" 41 | }; 42 | server.stdin.write(JSON.stringify(initialized) + '\n'); 43 | 44 | // Test tool call 45 | const toolRequest = { 46 | jsonrpc: "2.0", 47 | id: 2, 48 | method: "tools/call", 49 | params: { 50 | name: "rat", 51 | arguments: { 52 | thought: "This is a test thought to verify the Node.js server functionality. It demonstrates reasoning because we need to validate the metrics system works correctly.", 53 | nextThoughtNeeded: false, 54 | thoughtNumber: 1, 55 | totalThoughts: 1 56 | } 57 | } 58 | }; 59 | 60 | server.stdin.write(JSON.stringify(toolRequest) + '\n'); 61 | 62 | // Wait for response 63 | setTimeout(() => { 64 | server.kill(); 65 | 66 | console.log('=== Tool Execution Test ==='); 67 | 68 | const lines = output.split('\n').filter(line => line.trim()); 69 | let toolExecuted = false; 70 | 71 | for (const line of lines) { 72 | try { 73 | const parsed = JSON.parse(line); 74 | if (parsed.id === 2 && parsed.result && parsed.result.content) { 75 | const resultText = parsed.result.content[0].text; 76 | const resultData = JSON.parse(resultText); 77 | 78 | console.log('✅ Tool executed successfully!'); 79 | console.log(` Metrics - Quality: ${resultData.metrics.quality.toFixed(3)}`); 80 | console.log(` Metrics - Complexity: ${resultData.metrics.complexity.toFixed(3)}`); 81 | console.log(` Metrics - Impact: ${resultData.metrics.impact.toFixed(3)}`); 82 | console.log(` Total thoughts processed: ${resultData.analytics.total_thoughts}`); 83 | 84 | toolExecuted = true; 85 | break; 86 | } 87 | } catch (e) { 88 | // Ignore parsing errors 89 | } 90 | } 91 | 92 | if (toolExecuted) { 93 | console.log('✅ SUCCESS: Tool execution test passed'); 94 | resolve(true); 95 | } else { 96 | console.log('❌ FAILED: Tool execution failed'); 97 | console.log('Output:', output); 98 | console.log('Errors:', errorOutput); 99 | resolve(false); 100 | } 101 | }, 1000); 102 | }, 100); 103 | 104 | server.on('error', (err) => { 105 | console.error('Server error:', err); 106 | reject(err); 107 | }); 108 | }); 109 | } 110 | 111 | testToolExecution().then(success => { 112 | console.log(`\nTool test ${success ? 'PASSED' : 'FAILED'}`); 113 | process.exit(success ? 0 : 1); 114 | }).catch(err => { 115 | console.error('Test error:', err); 116 | process.exit(1); 117 | }); 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RAT MCP Server (Node.js) 2 | 3 | Retrieval Augmented Thinking MCP Server - A reasoning tool that processes structured thoughts with metrics, branching, and revision capabilities. 4 | 5 | ## Installation 6 | 7 | ### Simple 3-Step Process 8 | ```bash 9 | git clone https://github.com/stat-guy/retrieval-augmented-thinking.git 10 | cd retrieval-augmented-thinking 11 | npm install -g . 12 | ``` 13 | 14 | ### Verify Installation 15 | Test that the installation worked: 16 | ```bash 17 | npx mcp-server-rat-node --help 18 | ``` 19 | 20 | **Success indicator:** If you see `RAT MCP Server (Node.js) running on stdio`, your installation is ready! 21 | 22 | ## Claude Desktop Configuration 23 | 24 | Add to your Claude Desktop configuration file: 25 | 26 | **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` 27 | **Windows**: `%APPDATA%/Claude/claude_desktop_config.json` 28 | 29 | ```json 30 | { 31 | "mcpServers": { 32 | "retrieval-augmented-thinking": { 33 | "command": "npx", 34 | "args": ["mcp-server-rat-node"] 35 | } 36 | } 37 | } 38 | ``` 39 | 40 | After adding the configuration, restart Claude Desktop to load the RAT server. 41 | 42 | ## Usage 43 | 44 | The server provides a single `rat` tool for processing structured thoughts: 45 | 46 | ```javascript 47 | // Basic usage 48 | { 49 | "thought": "I need to analyze this problem step by step...", 50 | "nextThoughtNeeded": true, 51 | "thoughtNumber": 1, 52 | "totalThoughts": 3 53 | } 54 | 55 | // With revision 56 | { 57 | "thought": "Let me reconsider my previous analysis...", 58 | "nextThoughtNeeded": false, 59 | "thoughtNumber": 2, 60 | "totalThoughts": 3, 61 | "isRevision": true, 62 | "revisesThought": 1 63 | } 64 | 65 | // With branching 66 | { 67 | "thought": "Alternative approach: what if we consider...", 68 | "nextThoughtNeeded": true, 69 | "thoughtNumber": 2, 70 | "totalThoughts": 4, 71 | "branchFromThought": 1, 72 | "branchId": "alt-path-1" 73 | } 74 | ``` 75 | 76 | ## Tool Parameters 77 | 78 | ### Required 79 | - `thought` (string): The thought content to process 80 | - `nextThoughtNeeded` (boolean): Whether another thought is needed to continue 81 | - `thoughtNumber` (integer): Current thought number in the sequence 82 | - `totalThoughts` (integer): Total expected thoughts (adjustable) 83 | 84 | ### Optional 85 | - `isRevision` (boolean): Whether this revises a previous thought 86 | - `revisesThought` (integer): The thought number being revised 87 | - `branchFromThought` (integer): Thought number to branch from 88 | - `branchId` (string): Unique identifier for this branch 89 | - `needsMoreThoughts` (boolean): Extend beyond totalThoughts if needed 90 | 91 | ## Response Format 92 | 93 | ```json 94 | { 95 | "thought_number": 1, 96 | "total_thoughts": 3, 97 | "metrics": { 98 | "complexity": 0.342, 99 | "depth": 0.521, 100 | "quality": 0.643, 101 | "impact": 0.289, 102 | "confidence": 0.758 103 | }, 104 | "analytics": { 105 | "total_thoughts": 5, 106 | "average_quality": 0.612, 107 | "chain_effectiveness": 0.145 108 | }, 109 | "next_thought_needed": true, 110 | "visual_output": "┌─ 💭 Thought 1/3 ─────────────────┐\\n│ Analysis shows clear patterns... │\\n├─ Metrics ──────────────────────┤\\n│ Quality: 0.64 | Impact: 0.29... │\\n└─────────────────────────────────┘" 111 | } 112 | ``` 113 | 114 | ## Troubleshooting 115 | 116 | ### If Installation Fails 117 | The installation process includes automatic permission fixes. If you encounter issues: 118 | 119 | 1. **Ensure you have Node.js and npm installed** 120 | 2. **Try the alternative installation method:** 121 | ```bash 122 | npm install -g git+https://github.com/stat-guy/retrieval-augmented-thinking.git 123 | ``` 124 | 3. **For rare permission issues:** 125 | ```bash 126 | chmod +x $(npm bin -g)/mcp-server-rat-node 127 | ``` 128 | 129 | ### Verification Steps 130 | Before configuring Claude Desktop, always verify: 131 | ```bash 132 | npx mcp-server-rat-node --help 133 | ``` 134 | 135 | If this shows "RAT MCP Server (Node.js) running on stdio", you're ready to configure Claude Desktop. 136 | 137 | ## Testing 138 | 139 | Run the test suite: 140 | ```bash 141 | npm test 142 | ``` 143 | 144 | Test tool execution: 145 | ```bash 146 | node test-tool.js 147 | ``` 148 | 149 | ## License 150 | 151 | This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository. -------------------------------------------------------------------------------- /CLAUDE.md: -------------------------------------------------------------------------------- 1 | # RAT (Retrieval Augmented Thinking) MCP Tool 2 | 3 | ## Tool Name 4 | `rat` 5 | 6 | ## Description 7 | A context-aware reasoning system that orchestrates structured thought processes through dynamic trajectories. Implements iterative hypothesis generation and validation cycles while preserving context coherence across non-linear reasoning paths. 8 | 9 | ## Installation 10 | 11 | ### Simple 3-Step Process 12 | ```bash 13 | git clone https://github.com/stat-guy/retrieval-augmented-thinking.git 14 | cd retrieval-augmented-thinking 15 | npm install -g . 16 | ``` 17 | 18 | ### Verify Installation 19 | Test before configuring Claude Desktop: 20 | ```bash 21 | npx mcp-server-rat-node --help 22 | ``` 23 | 24 | **Success indicator:** If you see `RAT MCP Server (Node.js) running on stdio`, installation is complete! 25 | 26 | ## Claude Desktop Configuration 27 | Add to `claude_desktop_config.json`: 28 | ```json 29 | { 30 | "mcpServers": { 31 | "rat": { 32 | "command": "npx", 33 | "args": ["mcp-server-rat-node"] 34 | } 35 | } 36 | } 37 | ``` 38 | 39 | Restart Claude Desktop after adding the configuration. 40 | 41 | ## Parameters 42 | 43 | ### Required Parameters 44 | - **`thought`** (string): Structured reasoning step content 45 | - Primary analysis chains 46 | - Hypothesis formulation/validation 47 | - Branch exploration paths 48 | - Revision proposals 49 | - Context preservation markers 50 | - Verification checkpoints 51 | 52 | - **`nextThoughtNeeded`** (boolean): Signal for continuation of reasoning chain 53 | - `true`: Continue to next thought 54 | - `false`: Complete current reasoning trajectory 55 | 56 | - **`thoughtNumber`** (integer, min: 1): Position in current reasoning trajectory 57 | - Sequential numbering starting from 1 58 | - Must be ≤ `totalThoughts` unless `needsMoreThoughts` is true 59 | 60 | - **`totalThoughts`** (integer, min: 1): Dynamic scope indicator (adjustable) 61 | - Initial estimation of reasoning steps needed 62 | - Can be expanded via `needsMoreThoughts` 63 | 64 | ### Optional Parameters 65 | - **`isRevision`** (boolean, default: false): Marks recursive refinement steps 66 | - **`revisesThought`** (integer): References target thought number for refinement 67 | - **`branchFromThought`** (integer): Indicates parallel exploration paths source 68 | - **`branchId`** (string): Context identifier for parallel reasoning chains 69 | - **`needsMoreThoughts`** (boolean, default: false): Signals scope expansion requirement 70 | 71 | ## Response Structure 72 | ```typescript 73 | { 74 | thought_number: number, 75 | total_thoughts: number, 76 | metrics: { 77 | complexity: number, // 0.0-1.0: Structural complexity score 78 | depth: number, // 0.0-1.0: Content depth analysis 79 | quality: number, // 0.0-1.0: Overall thought quality 80 | impact: number, // 0.0-1.0: Reasoning impact score 81 | confidence: number // 0.0-1.0: Certainty assessment 82 | }, 83 | analytics: { 84 | total_thoughts: number, 85 | average_quality: number, 86 | chain_effectiveness: number 87 | }, 88 | next_thought_needed: boolean, 89 | visual_output: string // Formatted display with metrics 90 | } 91 | ``` 92 | 93 | ## Usage Patterns 94 | 95 | ### Sequential Analysis 96 | ```json 97 | { 98 | "thought": "First, I need to establish the core problem parameters.", 99 | "nextThoughtNeeded": true, 100 | "thoughtNumber": 1, 101 | "totalThoughts": 5 102 | } 103 | ``` 104 | 105 | ### Hypothesis Validation 106 | ```json 107 | { 108 | "thought": "Testing hypothesis: The root cause is data inconsistency.", 109 | "nextThoughtNeeded": true, 110 | "thoughtNumber": 3, 111 | "totalThoughts": 5 112 | } 113 | ``` 114 | 115 | ### Revision with Refinement 116 | ```json 117 | { 118 | "thought": "Upon further analysis, the initial assumption was incomplete...", 119 | "nextThoughtNeeded": true, 120 | "thoughtNumber": 4, 121 | "totalThoughts": 5, 122 | "isRevision": true, 123 | "revisesThought": 2 124 | } 125 | ``` 126 | 127 | ### Branch Exploration 128 | ```json 129 | { 130 | "thought": "Alternative approach: Consider the performance implications...", 131 | "nextThoughtNeeded": true, 132 | "thoughtNumber": 3, 133 | "totalThoughts": 4, 134 | "branchFromThought": 2, 135 | "branchId": "performance_analysis" 136 | } 137 | ``` 138 | 139 | ### Scope Extension 140 | ```json 141 | { 142 | "thought": "This requires deeper investigation beyond initial scope.", 143 | "nextThoughtNeeded": true, 144 | "thoughtNumber": 5, 145 | "totalThoughts": 5, 146 | "needsMoreThoughts": true 147 | } 148 | ``` 149 | 150 | ## Execution Protocol 151 | 1. **Initialize** with scope estimation (`totalThoughts`) 152 | 2. **Generate** structured reasoning steps sequentially 153 | 3. **Validate** hypotheses through verification cycles 154 | 4. **Maintain** context coherence across branches 155 | 5. **Implement** revisions through recursive refinement 156 | 6. **Signal** completion when validation succeeds 157 | 158 | ## Best Practices for AI Assistants 159 | - Start with realistic `totalThoughts` estimate (3-7 for most problems) 160 | - Use `isRevision` when refining earlier thoughts 161 | - Create branches for parallel analysis paths 162 | - Extend scope with `needsMoreThoughts` when complexity emerges 163 | - Always provide substantive `thought` content 164 | - Set `nextThoughtNeeded: false` only when reasoning is complete 165 | 166 | ## Error Prevention 167 | - Ensure `thought` content is non-empty and meaningful 168 | - Keep `thoughtNumber` ≤ `totalThoughts` unless extending scope 169 | - When using `isRevision: true`, always specify `revisesThought` 170 | - When branching, provide both `branchFromThought` and `branchId` 171 | - Use descriptive, analytical language in thought content 172 | 173 | ## Installation Notes 174 | The installation process includes automatic permission fixes via postinstall scripts. Most users will only need the simple 3-step process. Manual chmod commands are rarely needed as the system handles permissions automatically. -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { Server } from "@modelcontextprotocol/sdk/server/index.js"; 4 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 5 | import { 6 | CallToolRequestSchema, 7 | ListToolsRequestSchema, 8 | ToolSchema, 9 | } from "@modelcontextprotocol/sdk/types.js"; 10 | 11 | // Data structures matching the original Python implementation 12 | class ThoughtMetrics { 13 | constructor() { 14 | this.complexity = 0; 15 | this.depth = 0; 16 | this.quality = 0; 17 | this.impact = 0; 18 | this.confidence = 0; 19 | } 20 | } 21 | 22 | class ThoughtData { 23 | constructor(data) { 24 | this.content = data.thought || ""; 25 | this.thought_number = data.thoughtNumber || 1; 26 | this.total_thoughts = data.totalThoughts || 1; 27 | this.next_thought_needed = data.nextThoughtNeeded || false; 28 | this.is_revision = data.isRevision || false; 29 | this.revises_thought = data.revisesThought || null; 30 | this.branch_from_thought = data.branchFromThought || null; 31 | this.branch_id = data.branchId || null; 32 | this.needs_more_thoughts = data.needsMoreThoughts || false; 33 | this.timestamp = Date.now(); 34 | this.metrics = new ThoughtMetrics(); 35 | this.processed = false; 36 | } 37 | } 38 | 39 | class Analytics { 40 | constructor() { 41 | this.total_thoughts = 0; 42 | this.total_revisions = 0; 43 | this.total_branches = 0; 44 | this.chain_effectiveness = 0; 45 | this.revision_impact = 0; 46 | this.branch_success_rate = 0; 47 | this.average_quality = 0; 48 | this.quality_trend = []; 49 | this.session_start = Date.now(); 50 | this.last_update = Date.now(); 51 | } 52 | 53 | updateMetrics(thought) { 54 | this.total_thoughts += 1; 55 | this.last_update = Date.now(); 56 | 57 | if (thought.is_revision) { 58 | this.total_revisions += 1; 59 | } 60 | 61 | if (thought.branch_id) { 62 | this.total_branches += 1; 63 | } 64 | 65 | // Update quality tracking 66 | const currentQuality = thought.metrics.quality; 67 | this.quality_trend.push(currentQuality); 68 | 69 | // Keep only last 20 quality scores 70 | if (this.quality_trend.length > 20) { 71 | this.quality_trend = this.quality_trend.slice(-20); 72 | } 73 | 74 | // Recalculate average quality 75 | if (this.quality_trend.length > 0) { 76 | this.average_quality = this.quality_trend.reduce((a, b) => a + b) / this.quality_trend.length; 77 | } 78 | 79 | // Update effectiveness metrics 80 | this._calculateEffectiveness(); 81 | } 82 | 83 | _calculateEffectiveness() { 84 | if (this.total_thoughts > 0) { 85 | // Chain effectiveness based on quality trend 86 | if (this.quality_trend.length >= 2) { 87 | const recent = this.quality_trend.slice(-5); 88 | const early = this.quality_trend.slice(0, 5); 89 | const recentAvg = recent.reduce((a, b) => a + b) / recent.length; 90 | const earlyAvg = early.reduce((a, b) => a + b) / early.length; 91 | this.chain_effectiveness = earlyAvg > 0 ? Math.max(0, (recentAvg - earlyAvg) / earlyAvg) : 0; 92 | } 93 | 94 | // Revision impact 95 | if (this.total_thoughts > 0) { 96 | this.revision_impact = Math.min(1.0, this.total_revisions / this.total_thoughts * 2); 97 | } 98 | 99 | // Branch success rate (placeholder) 100 | if (this.total_branches > 0) { 101 | this.branch_success_rate = 0.7; 102 | } 103 | } 104 | } 105 | } 106 | 107 | class ThoughtProcessor { 108 | constructor() { 109 | this.processed_count = 0; 110 | this.reasoning_keywords = [ 111 | 'because', 'therefore', 'thus', 'hence', 'consequently', 112 | 'since', 'given', 'assuming', 'implies', 'suggests', 113 | 'indicates', 'demonstrates', 'proves', 'shows', 'reveals' 114 | ]; 115 | this.impact_keywords = [ 116 | 'important', 'critical', 'significant', 'key', 'essential', 117 | 'fundamental', 'crucial', 'vital', 'major', 'primary' 118 | ]; 119 | } 120 | 121 | async processThought(thoughtData) { 122 | // Validate 123 | this._validateThought(thoughtData); 124 | 125 | // Sanitize content 126 | thoughtData.content = this._sanitizeContent(thoughtData.content); 127 | 128 | // Calculate metrics 129 | thoughtData.metrics = this._calculateMetrics(thoughtData); 130 | 131 | // Mark as processed 132 | thoughtData.processed = true; 133 | thoughtData.timestamp = Date.now(); 134 | this.processed_count++; 135 | 136 | return thoughtData; 137 | } 138 | 139 | _validateThought(thought) { 140 | if (!thought.content || !thought.content.trim()) { 141 | throw new Error("Thought content cannot be empty"); 142 | } 143 | 144 | if (thought.thought_number < 1) { 145 | throw new Error("Thought number must be positive"); 146 | } 147 | 148 | if (thought.total_thoughts < 1) { 149 | throw new Error("Total thoughts must be positive"); 150 | } 151 | 152 | if (thought.thought_number > thought.total_thoughts && !thought.needs_more_thoughts) { 153 | throw new Error("Thought number cannot exceed total thoughts unless extending"); 154 | } 155 | } 156 | 157 | _sanitizeContent(content) { 158 | // Remove excessive whitespace 159 | content = content.replace(/\s+/g, ' ').trim(); 160 | 161 | // Remove problematic characters 162 | content = content.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, ''); 163 | 164 | // Normalize line endings 165 | content = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n'); 166 | 167 | // Limit length 168 | if (content.length > 10000) { 169 | content = content.substring(0, 10000) + "... [truncated]"; 170 | } 171 | 172 | return content; 173 | } 174 | 175 | _calculateMetrics(thought) { 176 | const content = thought.content.toLowerCase(); 177 | 178 | // Calculate complexity 179 | const complexity = this._calculateComplexity(thought.content); 180 | 181 | // Calculate depth 182 | const depth = this._calculateDepth(thought.content); 183 | 184 | // Calculate impact 185 | const impact = this._calculateImpact(content); 186 | 187 | // Calculate quality 188 | const quality = this._calculateQuality(complexity, depth, impact, thought); 189 | 190 | // Calculate confidence 191 | const confidence = this._calculateConfidence(content, complexity, depth); 192 | 193 | thought.metrics.complexity = Math.round(complexity * 1000) / 1000; 194 | thought.metrics.depth = Math.round(depth * 1000) / 1000; 195 | thought.metrics.quality = Math.round(quality * 1000) / 1000; 196 | thought.metrics.impact = Math.round(impact * 1000) / 1000; 197 | thought.metrics.confidence = Math.round(confidence * 1000) / 1000; 198 | 199 | return thought.metrics; 200 | } 201 | 202 | _calculateComplexity(content) { 203 | const colons = (content.match(/:/g) || []).length; 204 | const semicolons = (content.match(/;/g) || []).length; 205 | const dashes = (content.match(/-/g) || []).length; 206 | const parentheses = (content.match(/[()]/g) || []).length; 207 | const questions = (content.match(/\?/g) || []).length; 208 | 209 | const sentences = content.split(/[.!?]+/).filter(s => s.trim()).length; 210 | 211 | const punctuationScore = (colons * 0.3 + semicolons * 0.2 + dashes * 0.1 + 212 | parentheses * 0.05 + questions * 0.2); 213 | const sentenceComplexity = sentences * 0.1; 214 | 215 | return Math.min(1.0, (punctuationScore + sentenceComplexity) / 10); 216 | } 217 | 218 | _calculateDepth(content) { 219 | const wordCount = content.split(/\s+/).length; 220 | const charCount = content.length; 221 | 222 | const wordDepth = Math.min(1.0, wordCount / 100); 223 | const charDepth = Math.min(1.0, charCount / 500); 224 | 225 | return (wordDepth * 0.6 + charDepth * 0.4); 226 | } 227 | 228 | _calculateImpact(contentLower) { 229 | const reasoningScore = this.reasoning_keywords.filter(keyword => 230 | contentLower.includes(keyword)).length; 231 | 232 | const impactScore = this.impact_keywords.filter(keyword => 233 | contentLower.includes(keyword)).length; 234 | 235 | const structurePatterns = [ 236 | /\b(first|second|third|finally|lastly)\b/, 237 | /\b(step \d+|\d+\.|\d+\))/, 238 | /\b(therefore|thus|hence|consequently)\b/ 239 | ]; 240 | 241 | const structureScore = structurePatterns.filter(pattern => 242 | pattern.test(contentLower)).length; 243 | 244 | const totalScore = reasoningScore + impactScore + structureScore; 245 | return Math.min(1.0, totalScore / 8); 246 | } 247 | 248 | _calculateQuality(complexity, depth, impact, thought) { 249 | let baseQuality = (complexity * 0.3 + depth * 0.4 + impact * 0.3); 250 | 251 | if (thought.is_revision) { 252 | baseQuality *= 1.1; // 10% bonus for revisions 253 | } 254 | 255 | if (thought.branch_id) { 256 | baseQuality *= 1.05; // 5% bonus for branches 257 | } 258 | 259 | return Math.min(1.0, baseQuality); 260 | } 261 | 262 | _calculateConfidence(contentLower, complexity, depth) { 263 | const uncertaintyPatterns = [ 264 | /\b(maybe|perhaps|possibly|might|could be|uncertain)\b/, 265 | /\b(not sure|unclear|ambiguous)\b/ 266 | ]; 267 | 268 | const uncertaintyScore = uncertaintyPatterns.filter(pattern => 269 | pattern.test(contentLower)).length; 270 | 271 | const certaintyPatterns = [ 272 | /\b(clearly|obviously|definitely|certainly|undoubtedly)\b/, 273 | /\b(proven|established|confirmed)\b/ 274 | ]; 275 | 276 | const certaintyScore = certaintyPatterns.filter(pattern => 277 | pattern.test(contentLower)).length; 278 | 279 | const structureConfidence = (complexity + depth) / 2; 280 | const languageAdjustment = (certaintyScore - uncertaintyScore) * 0.1; 281 | 282 | return Math.max(0.0, Math.min(1.0, structureConfidence + languageAdjustment)); 283 | } 284 | } 285 | 286 | // Main server class 287 | class RatServer { 288 | constructor() { 289 | this.thought_history = []; 290 | this.analytics = new Analytics(); 291 | this.processor = new ThoughtProcessor(); 292 | } 293 | 294 | async processThought(arguments_obj) { 295 | try { 296 | // Create thought data 297 | const thoughtData = new ThoughtData(arguments_obj); 298 | 299 | // Process the thought 300 | const processedThought = await this.processor.processThought(thoughtData); 301 | 302 | // Add to history 303 | this.thought_history.push(processedThought); 304 | 305 | // Update analytics 306 | this.analytics.updateMetrics(processedThought); 307 | 308 | // Generate visual output 309 | const visualOutput = this._formatThoughtDisplay(processedThought); 310 | 311 | // Create response 312 | const responseData = { 313 | thought_number: processedThought.thought_number, 314 | total_thoughts: processedThought.total_thoughts, 315 | metrics: { 316 | complexity: processedThought.metrics.complexity, 317 | depth: processedThought.metrics.depth, 318 | quality: processedThought.metrics.quality, 319 | impact: processedThought.metrics.impact, 320 | confidence: processedThought.metrics.confidence 321 | }, 322 | analytics: { 323 | total_thoughts: this.analytics.total_thoughts, 324 | average_quality: this.analytics.average_quality, 325 | chain_effectiveness: this.analytics.chain_effectiveness 326 | }, 327 | next_thought_needed: processedThought.next_thought_needed, 328 | visual_output: visualOutput 329 | }; 330 | 331 | return { 332 | content: [{ 333 | type: "text", 334 | text: JSON.stringify(responseData, null, 2) 335 | }] 336 | }; 337 | 338 | } catch (error) { 339 | return { 340 | content: [{ 341 | type: "text", 342 | text: JSON.stringify({ 343 | error: error.message, 344 | status: 'failed' 345 | }, null, 2) 346 | }], 347 | isError: true 348 | }; 349 | } 350 | } 351 | 352 | _formatThoughtDisplay(thought) { 353 | // Create title based on thought type 354 | let title; 355 | if (thought.is_revision) { 356 | title = `💭 Revision of Thought ${thought.revises_thought}`; 357 | } else if (thought.branch_id) { 358 | title = `🌿 Branch ${thought.branch_id} from Thought ${thought.branch_from_thought}`; 359 | } else { 360 | title = `💭 Thought ${thought.thought_number}/${thought.total_thoughts}`; 361 | } 362 | 363 | // Create metrics display 364 | const metricsText = `Complexity: ${thought.metrics.complexity.toFixed(2)} | ` + 365 | `Depth: ${thought.metrics.depth.toFixed(2)} | ` + 366 | `Quality: ${thought.metrics.quality.toFixed(2)} | ` + 367 | `Impact: ${thought.metrics.impact.toFixed(2)} | ` + 368 | `Confidence: ${thought.metrics.confidence.toFixed(2)}`; 369 | 370 | // Format content 371 | const contentLines = thought.content.split('\n').map(line => line.trim()); 372 | const formattedContent = contentLines.join('\n'); 373 | 374 | // Create the display 375 | const borderLength = 60; 376 | const titleBorder = '─'.repeat(Math.max(0, borderLength - title.length - 4)); 377 | const metricsBorder = '─'.repeat(50); 378 | 379 | const displayParts = [ 380 | `┌─ ${title} ─${titleBorder}┐`, 381 | `│ ${formattedContent.substring(0, 56).padEnd(58)} │`, 382 | `├─ Metrics ─${metricsBorder}┤`, 383 | `│ ${metricsText.substring(0, 56).padEnd(58)} │`, 384 | `└${'─'.repeat(borderLength)}┘` 385 | ]; 386 | 387 | return displayParts.join('\n'); 388 | } 389 | } 390 | 391 | // Define the RAT tool 392 | const RAT_TOOL = { 393 | name: "rat", 394 | 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.", 395 | inputSchema: { 396 | type: "object", 397 | properties: { 398 | thought: { 399 | type: "string", 400 | description: "Your current thinking step" 401 | }, 402 | nextThoughtNeeded: { 403 | type: "boolean", 404 | description: "Whether another thought step is needed" 405 | }, 406 | thoughtNumber: { 407 | type: "integer", 408 | minimum: 1, 409 | description: "Current thought number" 410 | }, 411 | totalThoughts: { 412 | type: "integer", 413 | minimum: 1, 414 | description: "Estimated total thoughts needed" 415 | }, 416 | isRevision: { 417 | type: "boolean", 418 | description: "Whether this revises previous thinking" 419 | }, 420 | revisesThought: { 421 | type: "integer", 422 | minimum: 1, 423 | description: "Which thought is being reconsidered" 424 | }, 425 | branchFromThought: { 426 | type: "integer", 427 | minimum: 1, 428 | description: "Branching point thought number" 429 | }, 430 | branchId: { 431 | type: "string", 432 | description: "Branch identifier" 433 | }, 434 | needsMoreThoughts: { 435 | type: "boolean", 436 | description: "If more thoughts are needed" 437 | } 438 | }, 439 | required: ["thought", "nextThoughtNeeded", "thoughtNumber", "totalThoughts"] 440 | } 441 | }; 442 | 443 | // Create and configure server 444 | const server = new Server( 445 | { 446 | name: "mcp-server-rat-node", 447 | version: "0.1.0", 448 | }, 449 | { 450 | capabilities: { 451 | tools: {}, 452 | }, 453 | } 454 | ); 455 | 456 | const ratServer = new RatServer(); 457 | 458 | // Set up request handlers 459 | server.setRequestHandler(ListToolsRequestSchema, async () => ({ 460 | tools: [RAT_TOOL], 461 | })); 462 | 463 | server.setRequestHandler(CallToolRequestSchema, async (request) => { 464 | if (request.params.name === "rat") { 465 | return ratServer.processThought(request.params.arguments); 466 | } 467 | 468 | return { 469 | content: [{ 470 | type: "text", 471 | text: `Unknown tool: ${request.params.name}` 472 | }], 473 | isError: true 474 | }; 475 | }); 476 | 477 | // Run the server 478 | async function runServer() { 479 | const transport = new StdioServerTransport(); 480 | await server.connect(transport); 481 | console.error("RAT MCP Server (Node.js) running on stdio"); 482 | } 483 | 484 | runServer().catch((error) => { 485 | console.error("Fatal error running server:", error); 486 | process.exit(1); 487 | }); 488 | --------------------------------------------------------------------------------