├── .nvmrc ├── docs ├── prompts.png ├── testing.md ├── README.md ├── prompts.md ├── configuration.md └── examples.md ├── .prettierrc ├── tsconfig.json ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml ├── workflows │ ├── ci.yml │ └── release.yml └── PULL_REQUEST_TEMPLATE.md ├── test ├── README.md ├── prompt-manager.test.ts └── mcp-regression.test.ts ├── Dockerfile ├── .gitignore ├── index.ts ├── src ├── utils │ └── config.ts ├── prompts │ ├── types.ts │ ├── manager.ts │ └── templates.ts └── server.ts ├── LICENSE ├── eslint.config.js ├── CLAUDE.md ├── AGENTS.md ├── package.json ├── README.md └── CHANGELOG.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 22 -------------------------------------------------------------------------------- /docs/prompts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mettamatt/code-reasoning/HEAD/docs/prompts.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "tabWidth": 2, 5 | "trailingComma": "es5", 6 | "printWidth": 100, 7 | "bracketSpacing": true, 8 | "arrowParens": "avoid" 9 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "skipLibCheck": true, 10 | "outDir": "./dist", 11 | "rootDir": ".", 12 | "declaration": true 13 | }, 14 | "include": ["./**/*.ts"] 15 | } 16 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # CODEOWNERS file for code-reasoning 2 | # This file is used to automatically request reviews on PRs. 3 | # See: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 4 | 5 | # These owners will be the default owners for everything in the repo. 6 | * @mettamatt 7 | 8 | # Dependabot PR reviews will be assigned based on this configuration 9 | package.json @mettamatt 10 | package-lock.json @mettamatt -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # Testing in Code-Reasoning 2 | 3 | The `test/` directory houses the MCP regression harness that exercises the 4 | compiled server via the official SDK client. 5 | 6 | - `mcp-regression.test.ts` spawns `dist/index.js` through the 7 | `StdioClientTransport`, performs capability negotiation, and verifies tool and 8 | prompt flows end to end. 9 | - Run the suite with `npm run test:regression`, or include it in the default 10 | `npm test` command which runs lint plus the harness. 11 | 12 | Add new request scenarios here to grow coverage over time. 13 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22.12-alpine AS builder 2 | 3 | COPY package.json package-lock.json tsconfig.json /app/ 4 | COPY src /app/src 5 | 6 | WORKDIR /app 7 | 8 | RUN --mount=type=cache,target=/root/.npm npm install 9 | RUN npm run build 10 | 11 | FROM node:22-alpine AS release 12 | 13 | COPY --from=builder /app/dist /app/dist 14 | COPY --from=builder /app/package.json /app/package.json 15 | COPY --from=builder /app/package-lock.json /app/package-lock.json 16 | 17 | ENV NODE_ENV=production 18 | 19 | WORKDIR /app 20 | 21 | RUN npm ci --ignore-scripts --omit-dev 22 | 23 | ENTRYPOINT ["node", "dist/index.js"] 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '[BUG]' 5 | labels: 'bug' 6 | assignees: '' 7 | --- 8 | 9 | ## Describe the bug 10 | 11 | A clear and concise description of what the bug is. 12 | 13 | ## To Reproduce 14 | 15 | Steps to reproduce the behavior: 16 | 17 | 1. ... 18 | 2. ... 19 | 3. ... 20 | 21 | ## Expected behavior 22 | 23 | A clear and concise description of what you expected to happen. 24 | 25 | ## Environment 26 | 27 | - Node.js version: 28 | - npm version: 29 | - OS: 30 | - Package version: 31 | 32 | ## Additional context 33 | 34 | Add any other context about the problem here. 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules/ 3 | npm-debug.log 4 | yarn-debug.log 5 | yarn-error.log 6 | 7 | # Build output 8 | dist/ 9 | 10 | # Environment variables 11 | .env 12 | .env.local 13 | .env.development.local 14 | .env.test.local 15 | .env.production.local 16 | 17 | # Editor directories and files 18 | .idea/ 19 | .vscode/* 20 | !.vscode/extensions.json 21 | !.vscode/settings.json 22 | !.vscode/tasks.json 23 | !.vscode/launch.json 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? 29 | 30 | # OS specific 31 | .DS_Store 32 | Thumbs.db 33 | 34 | # Runtime logs and test results 35 | logs/ 36 | test-results/ 37 | test/prompt-evaluation/reports/ 38 | 39 | **/.claude/settings.local.json 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '[FEATURE]' 5 | labels: 'enhancement' 6 | assignees: '' 7 | --- 8 | 9 | ## Is your feature request related to a problem? Please describe. 10 | 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | ## Describe the solution you'd like 14 | 15 | A clear and concise description of what you want to happen. 16 | 17 | ## Describe alternatives you've considered 18 | 19 | A clear and concise description of any alternative solutions or features you've considered. 20 | 21 | ## Additional context 22 | 23 | Add any other context or screenshots about the feature request here. 24 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Code-Reasoning MCP Server Entry Point 5 | * 6 | * This is the entry point for the Code-Reasoning MCP Server, which uses sequential thinking 7 | * methodology to help solve programming problems step by step. It delegates to the main 8 | * server implementation in src/server.ts. 9 | * 10 | * Note: The server registers the "code-reasoning" tool, specializing in programming tasks 11 | * but is now referred to as "code-reasoning" in configuration and documentation. 12 | */ 13 | 14 | // Import and run the server 15 | import('./src/server.js') 16 | .then(module => { 17 | module.runServer(); 18 | }) 19 | .catch(error => { 20 | console.error('Error starting server:', error); 21 | process.exit(1); 22 | }); 23 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Check for updates to npm packages 4 | - package-ecosystem: "npm" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | # Group all minor and patch updates together 9 | groups: 10 | minor-patch: 11 | update-types: 12 | - "minor" 13 | - "patch" 14 | # Create pull requests for version updates 15 | open-pull-requests-limit: 10 16 | # Assign labels to pull requests 17 | labels: 18 | - "enhancement" 19 | # Reviewers are now managed via CODEOWNERS file 20 | 21 | # Check for updates to GitHub Actions 22 | - package-ecosystem: "github-actions" 23 | directory: "/" 24 | schedule: 25 | interval: "weekly" 26 | labels: 27 | - "enhancement" 28 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build-and-test: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: [22.x] 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v4 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | cache: 'npm' 25 | 26 | - name: Install dependencies 27 | run: npm ci 28 | 29 | - name: Lint and format check 30 | run: | 31 | npm run lint 32 | npm run format:check 33 | 34 | - name: Run regression tests 35 | run: npm run test:regression 36 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | release: 5 | types: [created] 6 | # Optionally also run on tags 7 | push: 8 | tags: 9 | - 'v*.*.*' 10 | 11 | jobs: 12 | build-and-publish: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Use Node.js 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: '22.x' 22 | registry-url: 'https://registry.npmjs.org' 23 | cache: 'npm' 24 | 25 | - name: Install dependencies 26 | run: npm ci 27 | 28 | - name: Validate and build 29 | run: npm run validate 30 | 31 | - name: Run tests 32 | run: npm run test 33 | 34 | - name: Publish to npm 35 | run: npm publish 36 | env: 37 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 38 | -------------------------------------------------------------------------------- /src/utils/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Central configuration constants for code-reasoning 3 | * 4 | * This file defines: 5 | * 1. Filesystem paths for components that need filesystem access (prompts) 6 | * 2. Default application constants 7 | * 8 | * Note: The main configuration system is in-memory only and doesn't use 9 | * filesystem persistence for configuration values. The filesystem paths 10 | * defined here are only used for prompt-related functionality. 11 | */ 12 | 13 | import path from 'path'; 14 | import os from 'os'; 15 | 16 | // Filesystem paths for prompt-related functionality 17 | export const USER_HOME = os.homedir(); 18 | export const CONFIG_DIR = path.join(USER_HOME, '.code-reasoning'); 19 | export const PROMPT_VALUES_FILE = path.join(CONFIG_DIR, 'prompt_values.json'); 20 | 21 | export interface ConfigPaths { 22 | configDir: string; 23 | promptFile: string; 24 | } 25 | 26 | export const PATHS: ConfigPaths = Object.freeze({ 27 | configDir: CONFIG_DIR, 28 | promptFile: PROMPT_VALUES_FILE, 29 | }); 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Matt Westgate 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 | IMPLIED, 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. 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | 5 | ## Related Issue 6 | 7 | 8 | 9 | ## Type of Change 10 | 11 | 12 | 13 | - [ ] Bug fix (non-breaking change which fixes an issue) 14 | - [ ] New feature (non-breaking change which adds functionality) 15 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 16 | - [ ] Documentation update 17 | 18 | ## How Has This Been Tested? 19 | 20 | 21 | 22 | - [ ] I've run the unit tests (`npm test`) 23 | - [ ] I've run additional test scenarios (please specify) 24 | 25 | ## Checklist 26 | 27 | - [ ] My code follows the style guidelines of this project 28 | - [ ] I have performed a self-review of my own code 29 | - [ ] I have commented my code, particularly in hard-to-understand areas 30 | - [ ] I have made corresponding changes to the documentation 31 | - [ ] My changes generate no new warnings 32 | - [ ] I have added tests that prove my fix is effective or that my feature works 33 | - [ ] New and existing unit tests pass locally with my changes 34 | -------------------------------------------------------------------------------- /docs/testing.md: -------------------------------------------------------------------------------- 1 | # Testing the Code-Reasoning MCP Server 2 | 3 | The project now ships a lightweight MCP regression harness alongside the existing 4 | static analysis checks. The suite exercises the published stdio entry point 5 | (`dist/index.js`) using the official SDK client so we can verify the server's 6 | MCP contract end to end. 7 | 8 | ## Quick Checks 9 | 10 | ```bash 11 | # Run the default quality gate (currently lint only) 12 | npm test 13 | 14 | # Full validation pipeline 15 | npm run validate 16 | 17 | # Target just the MCP regression suite 18 | npm run test:regression 19 | ``` 20 | 21 | - `npm test` runs ESLint and the MCP regression harness. 22 | - `npm run validate` formats sources, applies lint fixes, and rebuilds the TypeScript output. 23 | - `npm run test:regression` rebuilds the project and runs `node --test` against the 24 | compiled harness in `dist/test/mcp-regression.test.js`. 25 | 26 | ## Regression coverage 27 | 28 | The harness lives in `test/mcp-regression.test.ts` and covers: 29 | 30 | - Tool discovery via `tools/list` 31 | - Happy-path and validation-error calls to the `code-reasoning` tool 32 | - Prompt discovery, prompt rendering, and completion persistence for 33 | `bug-analysis` 34 | 35 | Feel free to extend the suite with additional request flows under the same 36 | test runner. 37 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js'; 2 | import globals from 'globals'; 3 | import tseslint from '@typescript-eslint/eslint-plugin'; 4 | import tsParser from '@typescript-eslint/parser'; 5 | import prettier from 'eslint-plugin-prettier'; 6 | 7 | export default [ 8 | // Add an initial configuration that ignores dist 9 | { 10 | ignores: ['dist/**/*'], 11 | }, 12 | js.configs.recommended, 13 | { 14 | files: ['**/*.{ts,js}'], 15 | languageOptions: { 16 | globals: { 17 | ...globals.node, 18 | ...globals.es2022, 19 | }, 20 | parser: tsParser, 21 | parserOptions: { 22 | ecmaVersion: 2022, 23 | sourceType: 'module', 24 | }, 25 | }, 26 | plugins: { 27 | '@typescript-eslint': tseslint, 28 | prettier, 29 | }, 30 | rules: { 31 | // TypeScript specific rules 32 | '@typescript-eslint/no-explicit-any': 'warn', 33 | '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], 34 | // General rules 35 | 'no-console': ['warn', { allow: ['error', 'warn', 'info', 'debug'] }], 36 | 'no-unused-vars': 'off', 37 | 'prettier/prettier': 'error', 38 | }, 39 | }, 40 | { 41 | files: ['**/test/**/*.ts'], 42 | rules: { 43 | 'no-console': 'off', 44 | }, 45 | }, 46 | ]; 47 | -------------------------------------------------------------------------------- /src/prompts/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Type definitions for MCP prompts. 3 | * 4 | * These types define the structure of prompts according to the Model Context Protocol (MCP). 5 | * Prompts are reusable templates that can be discovered and used by MCP clients. 6 | * This implementation uses the standard CompleteRequestSchema MCP protocol for providing 7 | * auto-completion of prompt arguments. 8 | */ 9 | 10 | /** 11 | * Represents an argument/parameter for a prompt. 12 | */ 13 | export interface PromptArgument { 14 | name: string; 15 | description: string; 16 | required: boolean; 17 | } 18 | 19 | /** 20 | * Represents a prompt as defined by the MCP. 21 | */ 22 | export interface Prompt { 23 | name: string; 24 | description: string; 25 | arguments?: PromptArgument[]; 26 | // The defaultValues property has been removed in favor of the standard 27 | // CompleteRequestSchema MCP protocol for argument completion 28 | } 29 | 30 | /** 31 | * Represents the content of a message in a prompt result. 32 | */ 33 | export interface PromptMessageContent { 34 | type: 'text'; 35 | text: string; 36 | } 37 | 38 | /** 39 | * Represents a message in a prompt result. 40 | */ 41 | export interface PromptMessage { 42 | role: 'user' | 'assistant'; 43 | content: PromptMessageContent; 44 | } 45 | 46 | /** 47 | * Represents the result of applying a prompt with arguments. 48 | */ 49 | export interface PromptResult { 50 | messages: PromptMessage[]; 51 | } 52 | -------------------------------------------------------------------------------- /CLAUDE.md: -------------------------------------------------------------------------------- 1 | # CLAUDE.md 2 | 3 | This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. 4 | 5 | ## Naming Convention Note 6 | 7 | This project was originally forked from the Sequential Thinking MCP Server but has been renamed to Code Reasoning MCP Server to better reflect its specialized focus on programming tasks. The tool has been renamed from "sequentialthinking" to "code-reasoning" for consistency. All configuration must use "code-reasoning" as the key - the "sequential-thinking" configuration key is not supported. The class previously named "SequentialThinkingServer" has been renamed to "CodeReasoningServer" for consistency. 8 | 9 | ## Build/Test/Lint Commands 10 | 11 | - Build: `npm run build` 12 | - Start: `npm run start`, `npm run debug` 13 | - Test: `npm run test` (runs ESLint) 14 | - Lint: `npm run lint`, `npm run lint:fix` 15 | - Format: `npm run format`, `npm run format:check` 16 | - Validation: `npm run validate` (runs format, lint:fix, and build) 17 | 18 | ## Code Style Guidelines 19 | 20 | - **Parameters**: snake_case (e.g., `thought_number`, not `thoughtNumber`) 21 | - **Imports**: ES Modules with .js extension 22 | - **Types**: Strict TypeScript with explicit types; avoid `any` where possible 23 | - **Error Handling**: Use structured logging with Logger class 24 | - **Logging**: Use logger.error/info/debug instead of console.log 25 | - **Formatting**: Prettier with singleQuotes, tabWidth: 2, printWidth: 100 26 | - **Variables**: Use descriptive names, camelCase for variables/functions 27 | 28 | Always run `npm run lint` and `npm run format` before committing changes. 29 | 30 | ## Documentation Locations 31 | 32 | - Main documentation: [README.md](./README.md) 33 | - Detailed examples: [docs/examples.md](./docs/examples.md) 34 | - Configuration options: [docs/configuration.md](./docs/configuration.md) 35 | - Prompt system: [docs/prompts.md](./docs/prompts.md) 36 | - Testing framework: [docs/testing.md](./docs/testing.md) 37 | -------------------------------------------------------------------------------- /AGENTS.md: -------------------------------------------------------------------------------- 1 | # AGENTS.md (Coding Assistant Brief) 2 | 3 | This file provides guidance to Codex CLI when working with code in this repository. 4 | 5 | ## Naming Convention Note 6 | 7 | This project was originally forked from the Sequential Thinking MCP Server but has been renamed to Code Reasoning MCP Server to better reflect its specialized focus on programming tasks. The tool has been renamed from "sequentialthinking" to "code-reasoning" for consistency. All configuration must use "code-reasoning" as the key - the "sequential-thinking" configuration key is not supported. The class previously named "SequentialThinkingServer" has been renamed to "CodeReasoningServer" for consistency. 8 | 9 | ## Build/Test/Lint Commands 10 | 11 | - Build: `npm run build` 12 | - Start: `npm run start`, `npm run debug` 13 | - Test: `npm run test` (runs ESLint) 14 | - Lint: `npm run lint`, `npm run lint:fix` 15 | - Format: `npm run format`, `npm run format:check` 16 | - Validation: `npm run validate` (runs format, lint:fix, and build) 17 | 18 | ## Code Style Guidelines 19 | 20 | - **Parameters**: snake_case (e.g., `thought_number`, not `thoughtNumber`) 21 | - **Imports**: ES Modules with .js extension 22 | - **Types**: Strict TypeScript with explicit types; avoid `any` where possible 23 | - **Error Handling**: Use structured logging with Logger class 24 | - **Logging**: Use logger.error/info/debug instead of console.log 25 | - **Formatting**: Prettier with singleQuotes, tabWidth: 2, printWidth: 100 26 | - **Variables**: Use descriptive names, camelCase for variables/functions 27 | 28 | Always run `npm run lint` and `npm run format` before committing changes. 29 | 30 | ## Documentation Locations 31 | 32 | - Main documentation: [README.md](./README.md) 33 | - Detailed examples: [docs/examples.md](./docs/examples.md) 34 | - Configuration options: [docs/configuration.md](./docs/configuration.md) 35 | - Prompt system: [docs/prompts.md](./docs/prompts.md) 36 | - Testing framework: [docs/testing.md](./docs/testing.md) 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mettamatt/code-reasoning", 3 | "version": "0.8.1", 4 | "description": "Enhanced MCP server for code reasoning using sequential thinking methodology, optimized for programming tasks", 5 | "author": "Matt Westgate", 6 | "license": "MIT", 7 | "type": "module", 8 | "keywords": [ 9 | "mcp", 10 | "model-context-protocol", 11 | "code-reasoning", 12 | "sequential-thinking", 13 | "programming", 14 | "claude", 15 | "ai", 16 | "coding-assistant", 17 | "reasoning", 18 | "problem-solving", 19 | "systematic-thinking", 20 | "code-analysis", 21 | "debugging", 22 | "anthropic", 23 | "llm-tools", 24 | "branching", 25 | "revision", 26 | "reflective-thinking" 27 | ], 28 | "repository": { 29 | "type": "git", 30 | "url": "git+https://github.com/mettamatt/code-reasoning.git" 31 | }, 32 | "bin": { 33 | "code-reasoning": "dist/index.js" 34 | }, 35 | "files": [ 36 | "dist" 37 | ], 38 | "main": "dist/index.js", 39 | "scripts": { 40 | "build": "tsc && chmod +x dist/*.js dist/**/*.js", 41 | "clean": "rm -rf dist", 42 | "clean:build": "npm run clean && npm run build", 43 | "dev": "tsc --watch", 44 | "start": "node dist/index.js", 45 | "debug": "node dist/index.js --debug", 46 | "lint": "eslint . --ext .ts", 47 | "lint:fix": "eslint . --ext .ts --fix", 48 | "format": "prettier --write \"**/*.{ts,js,json,md}\"", 49 | "format:check": "prettier --check \"**/*.{ts,js,json,md}\"", 50 | "validate": "run-s format lint:fix build", 51 | "prepare": "npm run build", 52 | "test": "npm run lint && npm run test:regression", 53 | "test:regression": "npm run build && node --test dist/test/mcp-regression.test.js" 54 | }, 55 | "dependencies": { 56 | "@modelcontextprotocol/sdk": "^1.18.1", 57 | "zod-to-json-schema": "^3.24.5" 58 | }, 59 | "devDependencies": { 60 | "@eslint/js": "^9.26.0", 61 | "@types/node": "^22.15.17", 62 | "@typescript-eslint/eslint-plugin": "^8.32.1", 63 | "@typescript-eslint/parser": "^8.32.1", 64 | "eslint": "^9.26.0", 65 | "eslint-config-prettier": "^10.1.5", 66 | "eslint-plugin-prettier": "^5.2.6", 67 | "globals": "^16.1.0", 68 | "npm-run-all": "^4.1.5", 69 | "prettier": "^3.5.3", 70 | "typescript": "^5.3.3" 71 | }, 72 | "engines": { 73 | "node": ">=22.0.0" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Code-Reasoning MCP Server Documentation 2 | 3 | This directory contains documentation for the Code-Reasoning MCP Server, a tool that enhances Claude's ability to solve complex programming tasks through structured, step-by-step thinking. 4 | 5 | ## Documentation Index 6 | 7 | - [**Configuration Guide**](./configuration.md): Detailed information about all configuration options for the Code-Reasoning MCP Server, including command-line options, integration with Claude Desktop and VS Code, and component configuration. 8 | 9 | - [**Usage Examples**](./examples.md): Practical examples showing how to use the Code-Reasoning MCP Server for various programming tasks, including basic usage, advanced features like thought branching and revision, and integration examples. 10 | 11 | - [**Prompts Guide**](./prompts.md): Information about the prompt system in the Code-Reasoning MCP Server, including available prompts, how to use them with Claude Desktop, and how to customize prompts for your own needs. 12 | 13 | - [**Testing Information**](./testing.md): Basic information about testing the Code-Reasoning MCP Server, primarily relevant for developers who are extending or modifying the server. 14 | 15 | ## Getting Started 16 | 17 | To get started with the Code-Reasoning MCP Server, follow these steps: 18 | 19 | 1. **Install the server**: 20 | 21 | ```bash 22 | # Option 1: Use with npx (recommended for most users) 23 | npx @mettamatt/code-reasoning 24 | 25 | # Option 2: Install globally 26 | npm install -g @mettamatt/code-reasoning 27 | ``` 28 | 29 | 2. **Configure Claude Desktop**: 30 | Edit your Claude Desktop configuration file to include the Code-Reasoning MCP Server: 31 | 32 | ```json 33 | { 34 | "mcpServers": { 35 | "code-reasoning": { 36 | "command": "npx", 37 | "args": ["-y", "@mettamatt/code-reasoning"] 38 | } 39 | } 40 | } 41 | ``` 42 | 43 | 3. **Use with Claude**: 44 | Ask Claude to use sequential thinking in your prompts: 45 | 46 | ``` 47 | Please analyze this code using sequential thinking to break down the solution step by step. 48 | ``` 49 | 50 | 4. **Access ready-to-use prompts**: 51 | - Click the "+" icon in the Claude Desktop chat window 52 | - Select "Code Reasoning Tool" from the available tools 53 | - Choose a prompt template and fill in the required information 54 | 55 | For more detailed information, see the specific documentation files linked above. 56 | -------------------------------------------------------------------------------- /test/prompt-manager.test.ts: -------------------------------------------------------------------------------- 1 | import test from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | import fs from 'node:fs'; 4 | import os from 'node:os'; 5 | import path from 'node:path'; 6 | import { PromptManager } from '../src/prompts/manager.js'; 7 | 8 | const createTempConfigDir = (): string => fs.mkdtempSync(path.join(os.tmpdir(), 'prompt-manager-')); 9 | 10 | test('merging stored values skips undeclared global arguments', () => { 11 | const tempDir = createTempConfigDir(); 12 | 13 | try { 14 | const manager = new PromptManager(tempDir); 15 | 16 | manager.applyPrompt('architecture-decision', { 17 | decision_context: 'Assess logging strategy', 18 | working_directory: '/tmp/example-project', 19 | }); 20 | 21 | let capturedArgs: Record | undefined; 22 | 23 | manager.registerPrompt( 24 | { 25 | name: 'custom-no-working-dir', 26 | description: 'Custom prompt without working_directory argument', 27 | arguments: [], 28 | }, 29 | args => { 30 | capturedArgs = args; 31 | return { 32 | messages: [ 33 | { 34 | role: 'user', 35 | content: { type: 'text', text: 'custom-prompt-response' }, 36 | }, 37 | ], 38 | }; 39 | } 40 | ); 41 | 42 | assert.doesNotThrow(() => manager.applyPrompt('custom-no-working-dir')); 43 | assert.ok(capturedArgs, 'expected template to capture arguments'); 44 | const recordedArgs = capturedArgs; 45 | assert.ok( 46 | !Object.prototype.hasOwnProperty.call(recordedArgs, 'working_directory'), 47 | 'expected working_directory to be omitted when undeclared' 48 | ); 49 | } finally { 50 | fs.rmSync(tempDir, { recursive: true, force: true }); 51 | } 52 | }); 53 | 54 | test('custom prompt arguments preserve literal braces', () => { 55 | const tempDir = createTempConfigDir(); 56 | 57 | try { 58 | const manager = new PromptManager(tempDir); 59 | manager.registerPrompt( 60 | { 61 | name: 'brace-sample', 62 | description: 'Prompt to verify braces survive sanitization', 63 | arguments: [ 64 | { 65 | name: 'snippet', 66 | description: 'Code snippet to inject', 67 | required: true, 68 | }, 69 | ], 70 | }, 71 | args => ({ 72 | messages: [ 73 | { 74 | role: 'user', 75 | content: { type: 'text', text: args.snippet }, 76 | }, 77 | ], 78 | }) 79 | ); 80 | 81 | const codeSample = 'function test() { return 42; }'; 82 | const result = manager.applyPrompt('brace-sample', { snippet: codeSample }); 83 | 84 | assert.equal(result.messages.length, 1, 'expected a single message'); 85 | const [message] = result.messages; 86 | assert.equal(message.content.type, 'text', 'expected text content'); 87 | assert.equal(message.content.text, codeSample, 'expected braces to remain intact'); 88 | } finally { 89 | fs.rmSync(tempDir, { recursive: true, force: true }); 90 | } 91 | }); 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Code Reasoning MCP Server 2 | 3 | A Model Context Protocol (MCP) server that enhances Claude's ability to solve complex programming tasks through structured, step-by-step thinking. 4 | 5 | 6 | Code Reasoning Server MCP server 7 | 8 | 9 | [![npm version](https://img.shields.io/npm/v/@mettamatt/code-reasoning.svg)](https://www.npmjs.com/package/@mettamatt/code-reasoning) 10 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) 11 | [![CI](https://github.com/mettamatt/code-reasoning/actions/workflows/ci.yml/badge.svg)](https://github.com/mettamatt/code-reasoning/actions/workflows/ci.yml) 12 | 13 | ## Quick Installation 14 | 15 | 1. Configure Claude Desktop by editing: 16 | - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` 17 | - Windows: `%APPDATA%\Claude\claude_desktop_config.json` 18 | - Linux: `~/.config/Claude/claude_desktop_config.json` 19 | 20 | ```json 21 | { 22 | "mcpServers": { 23 | "code-reasoning": { 24 | "command": "npx", 25 | "args": ["-y", "@mettamatt/code-reasoning"] 26 | } 27 | } 28 | } 29 | ``` 30 | 31 | 2. Configure VS Code: 32 | 33 | ```json 34 | { 35 | "mcp": { 36 | "servers": { 37 | "code-reasoning": { 38 | "command": "npx", 39 | "args": ["-y", "@mettamatt/code-reasoning"] 40 | } 41 | } 42 | } 43 | } 44 | ``` 45 | 46 | ## Usage 47 | 48 | 1. To trigger this MCP, append this to your chat messages: 49 | 50 | ``` 51 | Use sequential thinking to reason about this. 52 | ``` 53 | 54 | 2. Use ready-to-go prompts that trigger Code-Reasoning: 55 | 56 | ![Code Reasoning Prompts](./docs/prompts.png) 57 | 58 | - Click the "+" icon in the Claude Desktop chat window, or in Claude Code type `/help` to see the specific commands. 59 | - Select "Add from Code Reasoning" from the available tools 60 | - Choose a prompt template and fill in the required information 61 | - Submit the form to add the prompt to your chat message and hit return 62 | 63 | See the [Prompts Guide](./docs/prompts.md) for details on using the prompt templates. 64 | 65 | ## Command Line Options 66 | 67 | - `--debug`: Enable detailed logging 68 | - `--help` or `-h`: Show help information 69 | 70 | ## Key Features 71 | 72 | - **Programming Focus**: Optimized for coding tasks and problem-solving 73 | - **Structured Thinking**: Break down complex problems into manageable steps 74 | - **Thought Branching**: Explore multiple solution paths in parallel 75 | - **Thought Revision**: Refine earlier reasoning as understanding improves 76 | - **Safety Limits**: Automatically stops after 20 thought steps to prevent loops 77 | - **Ready-to-Use Prompts**: Pre-defined templates for common development tasks 78 | 79 | ## Documentation 80 | 81 | Detailed documentation available in the docs directory: 82 | 83 | - [Usage Examples](./docs/examples.md): Examples of sequential thinking with the MCP server 84 | - [Configuration Guide](./docs/configuration.md): All configuration options for the MCP server 85 | - [Prompts Guide](./docs/prompts.md): Using and customizing prompts with the MCP server 86 | - [Testing Framework](./docs/testing.md): Testing information 87 | 88 | ## Project Structure 89 | 90 | ``` 91 | ├── index.ts # Entry point 92 | ├── src/ # Implementation source files 93 | └── test/ # Placeholder for future test utilities 94 | ``` 95 | 96 | ## License 97 | 98 | This project is licensed under the MIT License. See the LICENSE file for details. 99 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Unreleased 4 | 5 | ## 0.8.0 (2025-09-23) 6 | 7 | ### Major Changes 8 | 9 | - Migrated from class-based `SequentialThinkingServer` to functional `McpServer`. 10 | - Simplified config: replaced `config-manager` with lightweight `buildConfig`. 11 | - Introduced MCP regression framework (147 tests) with improved docs. 12 | - Consolidated prompt handling into `PromptManager` with filtering and validation. 13 | - Upgraded to MCP SDK `v1.18.1`. 14 | - Removed custom prompt loading for security and consistency. 15 | 16 | ### Features 17 | 18 | - Structured logging with tool metadata and error handling. 19 | - Prompt argument filtering for global values. 20 | - Added tests for literal braces in templates. 21 | 22 | ### Improvements 23 | 24 | - Updated npm dependencies. 25 | - Debug logs now go to `stderr`. 26 | - Simplified entry point (removed `parseArgs` and CLI options). 27 | - Updated schema handling with `ThoughtDataInputShape`. 28 | - Docs aligned with new architecture. 29 | - Reduced bundle size (removed `chalk`). 30 | - Refined validation with dual-schema/Zod-inferred types. 31 | - Better shutdown handling with proper exit codes. 32 | 33 | ### Breaking Changes 34 | 35 | - Removed end-to-end test runner, prompt evaluation, and related infra (\~2,200 LOC). 36 | - Dropped `valueManager` (merged into `PromptManager`). 37 | - Removed custom transport handling. 38 | - Replaced `zodToJsonSchema` with direct schemas. 39 | - Eliminated CLI options and debug flag handling. 40 | - Replaced manual `ThoughtData` interface with Zod-inferred types and strict/loose schemas. 41 | 42 | ### Bug Fixes 43 | 44 | - Fixed debug logging stream (no MCP interference). 45 | - Improved prompt filtering to respect declared args. 46 | - Strengthened error handling and type safety (`CallToolResult` replaces `ServerResult`). 47 | - Removed overzealous template injection neutralization. 48 | 49 | ## 0.7.0 (2025-05-10) 50 | 51 | ### Features 52 | 53 | - Added comprehensive MCP prompts system with predefined templates 54 | - Includes architecture-decision, bug-analysis, code-review, feature-planning, and refactoring-plan prompts 55 | - The last prompt value is saved so that it can be used again but it will not show until Claude Desktop and Claude Code implement MCP CompleteRequestSchema. See https://github.com/anthropics/claude-code/issues/986 56 | - Added support for custom prompt templates via JSON files 57 | - Added Zod-based input sanitization to template processing 58 | 59 | ## 0.6.2 (2025-05-04) 60 | 61 | ### Features 62 | 63 | - Added tool annotations support to better inform clients about the tool's behavior 64 | - Updated MCP SDK version reference to 1.11.0 65 | 66 | ### Improvements 67 | 68 | - Updated ESLint ecosystem to major new versions 69 | - ESLint: 8.57.1 → 9.26.0 70 | - @typescript-eslint/parser: 7.18.0 → 8.31.1 71 | - @typescript-eslint/eslint-plugin: 7.18.0 → 8.31.1 72 | - Added ESLint v9 flat config support via eslint.config.js 73 | - Removed obsolete .eslintrc.json configuration 74 | - Added GitHub Actions CI/CD workflows and contribution templates 75 | - Added CI badge and Contributing section to README 76 | 77 | ## 0.6.1 (2025-05-02) 78 | 79 | ### Bug Fixes 80 | 81 | - Fixed "Maximum call stack size exceeded" error in FilteredStdioServerTransport by preventing recursive stdout.write calls 82 | - Improved stdout filtering mechanism to avoid circular references when filtering non-JSON output 83 | 84 | ### Improvements 85 | 86 | - Doubled default operation timeout from 30s to 60s for better handling of complex reasoning tasks 87 | 88 | ## 0.6.0 (2025-04-30) 89 | 90 | ### Features 91 | 92 | - Upgraded MCP SDK from 0.5.0 to 1.10.2 for enhanced protocol compatibility 93 | - Added support for additional protocol capabilities (resources, prompts) 94 | - Implemented custom FilteredStdioServerTransport for improved stability 95 | - Added handlers for ListResourcesRequestSchema and ListPromptsRequestSchema 96 | 97 | ### Technical Improvements 98 | 99 | - Leveraged zodToJsonSchema utility for schema generation rather than manual creation 100 | - Documented intent of empty resource and prompt handlers to prevent Claude Desktop errors 101 | - Refined JSON detection logic in FilteredStdioServerTransport to handle array literals 102 | - Simplified type aliases by using direct SDK types for better maintainability 103 | - Improved file header documentation with MCP SDK version information and clearer feature descriptions 104 | - Updated type definitions for newer SDK compatibility 105 | - Added zod-to-json-schema dependency 106 | - Reorganized server.ts with clear section headers for better code organization 107 | - Enhanced code performance with cached JSON schema and optimized validation 108 | - Improved type safety with readonly properties and Map instead of object literals 109 | 110 | ## 0.5.0 (2025-04-30) 111 | 112 | ### Features 113 | 114 | - Updated core prompt to use HYBRID_DESIGN for better reasoning performance 115 | - Added prompt evaluation system with documentation and examples 116 | - Enhanced end-to-end test framework 117 | - Increased maxThoughtLength for more complex reasoning tasks 118 | 119 | ## 0.4.0 (earlier release) 120 | 121 | Initial documented version. 122 | -------------------------------------------------------------------------------- /test/mcp-regression.test.ts: -------------------------------------------------------------------------------- 1 | import test, { before, after } from 'node:test'; 2 | import assert from 'node:assert/strict'; 3 | import fs from 'node:fs'; 4 | import path from 'node:path'; 5 | import process from 'node:process'; 6 | import type { Readable } from 'node:stream'; 7 | import { Client } from '@modelcontextprotocol/sdk/client/index.js'; 8 | import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; 9 | import type { ContentBlock, PromptMessage } from '@modelcontextprotocol/sdk/types.js'; 10 | 11 | const serverEntry = path.resolve(process.cwd(), 'dist', 'index.js'); 12 | 13 | if (!fs.existsSync(serverEntry)) { 14 | throw new Error( 15 | 'Build output not found at dist/index.js. Run "npm run build" before executing regression tests.' 16 | ); 17 | } 18 | 19 | const transport = new StdioClientTransport({ 20 | command: process.execPath, 21 | args: [serverEntry], 22 | stderr: 'pipe', 23 | }); 24 | 25 | const client = new Client({ 26 | name: 'mcp-regression-suite', 27 | version: '0.1.0', 28 | }); 29 | 30 | let serverLog = ''; 31 | 32 | const isTextContent = ( 33 | block: ContentBlock | undefined 34 | ): block is Extract => 35 | Boolean(block && block.type === 'text'); 36 | 37 | const stderrStream = transport.stderr as Readable | null; 38 | if (stderrStream) { 39 | stderrStream.on('data', chunk => { 40 | serverLog += chunk.toString(); 41 | }); 42 | } 43 | 44 | before(async () => { 45 | try { 46 | await client.connect(transport); 47 | } catch (error) { 48 | throw new Error(`Failed to connect to server. Server stderr:\n${serverLog}\n${String(error)}`); 49 | } 50 | }); 51 | 52 | after(async () => { 53 | await client.close(); 54 | await transport.close(); 55 | }); 56 | 57 | test('lists the code-reasoning tool', { concurrency: false }, async () => { 58 | const { tools } = await client.listTools(); 59 | assert.ok(Array.isArray(tools), 'tools response should be an array'); 60 | const tool = tools.find(entry => entry.name === 'code-reasoning'); 61 | assert.ok(tool, 'expected code-reasoning tool to be registered'); 62 | assert.ok(tool.description && tool.description.includes('sequential thinking')); 63 | }); 64 | 65 | test('processes a valid thought payload', { concurrency: false }, async () => { 66 | const result = await client.callTool({ 67 | name: 'code-reasoning', 68 | arguments: { 69 | thought: 'Initial exploration of the regression harness.', 70 | thought_number: 1, 71 | total_thoughts: 3, 72 | next_thought_needed: true, 73 | }, 74 | }); 75 | 76 | assert.strictEqual(result.isError, false, `Unexpected tool error: ${serverLog}`); 77 | const blocks: ContentBlock[] = Array.isArray(result.content) ? result.content : []; 78 | const textBlock = blocks.find(isTextContent); 79 | assert.ok(textBlock, 'expected text content in tool response'); 80 | const payload = JSON.parse(textBlock.text); 81 | assert.strictEqual(payload.status, 'processed'); 82 | assert.strictEqual(payload.thought_number, 1); 83 | assert.strictEqual(payload.total_thoughts, 3); 84 | assert.ok(Array.isArray(payload.branches)); 85 | }); 86 | 87 | test('returns validation guidance for invalid payloads', { concurrency: false }, async () => { 88 | const result = await client.callTool({ 89 | name: 'code-reasoning', 90 | arguments: { 91 | thought: '', 92 | thought_number: 0, 93 | total_thoughts: 0, 94 | next_thought_needed: true, 95 | }, 96 | }); 97 | 98 | assert.strictEqual(result.isError, true, 'expected tool error for invalid payload'); 99 | const blocks: ContentBlock[] = Array.isArray(result.content) ? result.content : []; 100 | const textBlock = blocks.find(isTextContent); 101 | assert.ok(textBlock, 'expected text content in error response'); 102 | const payload = JSON.parse(textBlock.text); 103 | assert.strictEqual(payload.status, 'failed'); 104 | assert.match(payload.error, /Validation Error/); 105 | assert.match(payload.guidance, /thought/); 106 | assert.ok(payload.example, 'expected example payload guidance'); 107 | }); 108 | 109 | test( 110 | 'exposes and applies bug-analysis prompt with persistence', 111 | { concurrency: false }, 112 | async () => { 113 | const { prompts } = await client.listPrompts(); 114 | assert.ok(prompts.length > 0, 'expected built-in prompts'); 115 | const prompt = prompts.find(entry => entry.name === 'bug-analysis'); 116 | assert.ok(prompt, 'expected bug-analysis prompt to be available'); 117 | 118 | const promptResult = await client.getPrompt({ 119 | name: 'bug-analysis', 120 | arguments: { 121 | bug_behavior: 'The CLI exits unexpectedly.', 122 | expected_behavior: 'The CLI should start the server.', 123 | affected_components: 'src/server.ts', 124 | working_directory: '/tmp/demo-project', 125 | }, 126 | }); 127 | 128 | assert.ok(Array.isArray(promptResult.messages), 'expected prompt messages array'); 129 | const [firstMessage] = promptResult.messages as PromptMessage[]; 130 | assert.ok(firstMessage, 'expected first prompt message'); 131 | assert.strictEqual(firstMessage.role, 'user'); 132 | assert.ok(isTextContent(firstMessage.content), 'expected text content in prompt result'); 133 | assert.match(firstMessage.content.text, /Bug Analysis Process/); 134 | 135 | const completion = await client.complete({ 136 | ref: { type: 'ref/prompt', name: 'bug-analysis' }, 137 | argument: { name: 'working_directory', value: '' }, 138 | }); 139 | 140 | assert.ok(completion.completion, 'expected completion payload'); 141 | assert.ok(Array.isArray(completion.completion.values)); 142 | assert.ok( 143 | completion.completion.values.includes('/tmp/demo-project'), 144 | 'expected stored working_directory completion' 145 | ); 146 | } 147 | ); 148 | -------------------------------------------------------------------------------- /docs/prompts.md: -------------------------------------------------------------------------------- 1 | # Code Reasoning MCP Server Prompts 2 | 3 | This document provides detailed information about the prompt system in the Code Reasoning MCP server, including available prompts, how to use them, and how the prompt value persistence works. 4 | 5 | ## Table of Contents 6 | 7 | - [Overview](#overview) 8 | - [Available Prompts](#available-prompts) 9 | - [Using Prompts with Claude Desktop](#using-prompts-with-claude-desktop) 10 | - [Working Directory Integration](#working-directory-integration) 11 | - [Prompt Value Persistence](#prompt-value-persistence) 12 | - [Filesystem Integration](#filesystem-integration) 13 | 14 | ## Overview 15 | 16 | The Code Reasoning MCP server includes a set of predefined prompts designed for various software development tasks. These prompts utilize the structured, step-by-step reasoning approach to help solve complex programming problems. 17 | 18 | Key features of the prompt system: 19 | 20 | - **Predefined Templates**: Ready-to-use prompts for common development tasks 21 | - **Persistent Values**: Argument values are saved between sessions to reduce repetitive entry 22 | - **Working Directory Support**: Automatic handling of your current project directory 23 | - **Filesystem Integration**: Easy access to files through filesystem MCP tools 24 | 25 | > **Note:** Loading additional prompts from disk is no longer supported. The server ships with the curated set documented below. 26 | 27 | ## Available Prompts 28 | 29 | The Code Reasoning MCP server includes the following predefined prompts: 30 | 31 | | Prompt Name | Description | Key Arguments | 32 | | ----------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------- | 33 | | `architecture-decision` | Framework for making and documenting architecture decisions | `decision_context`, `constraints`, `options` | 34 | | `bug-analysis` | Systematic approach to analyzing and fixing bugs | `bug_behavior`, `expected_behavior`, `affected_components`, `reproduction_steps` | 35 | | `code-review` | Comprehensive template for code review | `code`, `requirements`, `language` | 36 | | `feature-planning` | Structured approach to planning new feature implementation | `problem_statement`, `target_users`, `success_criteria`, `affected_components` | 37 | | `refactoring-plan` | Structured approach to code refactoring | `current_issues`, `goals` | 38 | 39 | All prompts also support a `working_directory` parameter that specifies the path to your current project directory. 40 | 41 | ## Using Prompts with Claude Desktop 42 | 43 | To use Code Reasoning prompts with Claude Desktop: 44 | 45 | 1. **Access the Prompts Menu**: 46 | - Click the "+" icon in the Claude Desktop chat window 47 | - Select "Code Reasoning Tool" from the available tools 48 | 49 | 2. **Select a Prompt**: 50 | - Choose one of the available prompts from the list 51 | - A dialog window will appear with fields for the prompt arguments 52 | 53 | 3. **Fill in the Arguments**: 54 | - Enter the required information in each field 55 | - Include your working directory if needed (e.g., `~/projects/my-app`) 56 | 57 | 4. **Submit the Prompt**: 58 | - Click the submit button in the dialog 59 | - The prompt with your variables will be attached to the chat message as a pasted file 60 | 61 | 5. **Send the Message**: 62 | - Click the send button to submit the prompt to Claude 63 | - Claude will use the Code Reasoning tool to provide a structured analysis 64 | 65 | ## Working Directory Integration 66 | 67 | All prompts support a `working_directory` parameter that allows you to specify your current project directory. This enables: 68 | 69 | - Clear context for Claude about your project location 70 | - Easy reference to project files and directories 71 | - Simplified file access through filesystem tools 72 | 73 | Example working directory values: 74 | 75 | - macOS/Linux: `~/projects/my-app` or `/Users/username/projects/my-app` 76 | - Windows: `C:\Users\username\projects\my-app` 77 | 78 | ## Prompt Value Persistence 79 | 80 | The Code Reasoning MCP server now includes a feature to persist prompt argument values between sessions. This significantly reduces repetitive data entry. 81 | 82 | ### How It Works 83 | 84 | 1. **Value Storage**: 85 | - When you use a prompt, the argument values are saved to a JSON file 86 | - The file is stored in the `~/.code-reasoning/` directory 87 | - Values are organized by prompt name for easy retrieval 88 | 89 | 2. **Global Values**: 90 | - Some values like `working_directory` are stored globally 91 | - These global values are shared across all prompts 92 | - This means you only need to set your working directory once 93 | 94 | 3. **Automatic Retrieval**: 95 | - When you use a prompt again, saved values are automatically retrieved 96 | - The fields in the prompt dialog will be pre-filled with the saved values 97 | - You can always override saved values by entering new ones 98 | 99 | ### Storage Location 100 | 101 | Prompt values are stored in: 102 | 103 | ``` 104 | ~/.code-reasoning/prompt_values.json 105 | ``` 106 | 107 | If you want to reset stored values, you can simply delete this file or modify it directly. 108 | 109 | ## Filesystem Integration 110 | 111 | All prompts include guidance for accessing and modifying files using filesystem tools. This allows Claude to: 112 | 113 | - Read files from your project 114 | - List directory contents 115 | - Search for specific files or code patterns 116 | - Make changes to files when needed 117 | 118 | To take advantage of this feature: 119 | 120 | 1. Make sure your working directory is correctly set 121 | 2. Use absolute paths when referencing files 122 | 3. Ensure you have filesystem MCP tools available in your Claude Desktop configuration 123 | 124 | Typical filesystem operations Claude can perform: 125 | 126 | - `read_file("/path/to/file")` 127 | - `list_directory("/path/to/directory")` 128 | - `search_code("/path/to/directory", "search pattern")` 129 | - `edit_block("/path/to/file", "old_text", "new_text")` 130 | -------------------------------------------------------------------------------- /docs/configuration.md: -------------------------------------------------------------------------------- 1 | # Code-Reasoning MCP Server Configuration 2 | 3 | This document provides detailed information about all configuration options available for the Code-Reasoning MCP Server. It covers command-line options, configuration file formats, and customization options for various components. 4 | 5 | ## Table of Contents 6 | 7 | - [Command-Line Options](#command-line-options) 8 | - [Configuration Files](#configuration-files) 9 | - [Claude Desktop Integration](#claude-desktop-integration) 10 | - [VS Code Integration](#vs-code-integration) 11 | - [Component Configuration](#component-configuration) 12 | - [Logging Configuration](#logging-configuration) 13 | - [Prompt Configuration](#prompt-configuration) 14 | - [Testing Configuration](#testing-configuration) 15 | 16 | ## Command-Line Options 17 | 18 | The Code-Reasoning MCP Server supports the following command-line options: 19 | 20 | | Option | Description | Default | Example | 21 | | -------------- | --------------------------------------------- | -------- | --------------------------------------------- | 22 | | `--debug` | Enable debug logging with more verbose output | `false` | `code-reasoning --debug` | 23 | | `--help`, `-h` | Show help information | - | `code-reasoning --help` | 24 | | `--config-dir` | Specify the configuration directory | `config` | `code-reasoning --config-dir=/path/to/config` | 25 | 26 | ### Usage Examples 27 | 28 | Basic usage: 29 | 30 | ```bash 31 | code-reasoning 32 | ``` 33 | 34 | Debug mode: 35 | 36 | ```bash 37 | code-reasoning --debug 38 | ``` 39 | 40 | Help information: 41 | 42 | ```bash 43 | code-reasoning --help 44 | ``` 45 | 46 | ## Configuration Files 47 | 48 | ### Claude Desktop Integration 49 | 50 | Claude Desktop uses a configuration file to manage MCP server settings. This file is located at: 51 | 52 | - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` 53 | - Windows: `%APPDATA%\Claude\claude_desktop_config.json` 54 | - Linux: `~/.config/Claude/claude_desktop_config.json` 55 | 56 | #### Configuration Format 57 | 58 | ```json 59 | { 60 | "mcpServers": { 61 | "code-reasoning": { 62 | "command": "code-reasoning", 63 | "args": ["--debug"] 64 | } 65 | } 66 | } 67 | ``` 68 | 69 | #### Available Options 70 | 71 | | Option | Description | Type | Required | 72 | | --------- | -------------------------------------------- | ---------------- | -------- | 73 | | `command` | The command to run the MCP server | String | Yes | 74 | | `args` | Command-line arguments to pass to the server | Array of strings | No | 75 | 76 | ### VS Code Integration 77 | 78 | VS Code integration can be configured in two ways: 79 | 80 | 1. User Settings (applies to all workspaces): 81 | - Open VS Code settings: `Ctrl+Shift+P` (or `Cmd+Shift+P` on macOS) and type `Preferences: Open Settings (JSON)` 82 | - Add MCP configuration 83 | 84 | 2. Workspace Settings (applies to current workspace only): 85 | - Create a `.vscode/mcp.json` file in your workspace 86 | 87 | #### Configuration Format (User Settings) 88 | 89 | ```json 90 | { 91 | "mcp": { 92 | "servers": { 93 | "code-reasoning": { 94 | "command": "code-reasoning", 95 | "args": ["--debug"] 96 | } 97 | } 98 | } 99 | } 100 | ``` 101 | 102 | #### Configuration Format (Workspace Settings) 103 | 104 | ```json 105 | { 106 | "servers": { 107 | "code-reasoning": { 108 | "command": "code-reasoning", 109 | "args": ["--debug"] 110 | } 111 | } 112 | } 113 | ``` 114 | 115 | #### Available Options 116 | 117 | | Option | Description | Type | Required | 118 | | --------- | -------------------------------------------- | ---------------- | -------- | 119 | | `command` | The command to run the MCP server | String | Yes | 120 | | `args` | Command-line arguments to pass to the server | Array of strings | No | 121 | 122 | ## Component Configuration 123 | 124 | ### Logging Configuration 125 | 126 | The logging system uses direct `console.error()` calls for logging. 127 | 128 | #### Logging Approach 129 | 130 | The server uses the following streamlined approach: 131 | 132 | - All logs are written to stderr using `console.error()` 133 | - Debug logs are only shown when the `--debug` flag is enabled 134 | - The LogLevel enum is still used for compatibility but with simplified implementation 135 | - No log file rotation or custom log directories are supported 136 | 137 | #### Configuration Defaults 138 | 139 | Configuration is defined in `src/utils/config.ts` using the `buildConfig` helper: 140 | 141 | ```typescript 142 | import { buildConfig } from './utils/config.js'; 143 | 144 | const config = buildConfig(debugFlag ? { debug: true } : undefined); 145 | ``` 146 | 147 | Key characteristics: 148 | 149 | - **Stateless**: `buildConfig` returns a plain object; no runtime persistence or async initialization 150 | - **Type Safe**: The `CodeReasoningConfig` interface documents every option 151 | - **Override Friendly**: Pass a partial object to override defaults (e.g., enable debug mode) 152 | 153 | ### Prompt Configuration 154 | 155 | The Code-Reasoning MCP Server includes a prompt system with the following configuration options: 156 | 157 | #### Enabling Prompts 158 | 159 | Prompt functionality is controlled through the config object returned by `buildConfig`: 160 | 161 | ```typescript 162 | // Check if prompts are enabled 163 | if (config.promptsEnabled) { 164 | promptManager = new PromptManager(CONFIG_DIR); 165 | console.error('Prompts capability enabled'); 166 | } 167 | ``` 168 | 169 | Default configuration values: 170 | 171 | ```typescript 172 | { 173 | promptsEnabled: true, // Enables prompt functionality 174 | // Other configuration values... 175 | } 176 | ``` 177 | 178 | #### Prompt Value Persistence 179 | 180 | The server automatically stores prompt argument values in a JSON file to reduce repetitive data entry: 181 | 182 | - **Storage Location**: Values are stored in `[config_dir]/prompt_values.json` 183 | - **Global Values**: Some values like `working_directory` are shared across all prompts 184 | - **Prompt-Specific Values**: Other values are stored for each specific prompt 185 | 186 | The structure of the stored values file: 187 | 188 | ```json 189 | { 190 | "global": { 191 | "working_directory": "/path/to/project" 192 | }, 193 | "prompts": { 194 | "architecture-decision": { 195 | "decision_context": "Previous value", 196 | "constraints": "Previous constraints", 197 | "options": "Previous options" 198 | } 199 | // Other prompts... 200 | } 201 | } 202 | ``` 203 | 204 | This system automatically: 205 | 206 | 1. Stores values when prompts are used 207 | 2. Retrieves values when prompts are applied 208 | 3. Merges stored values with user-provided values (user input takes precedence) 209 | 210 | See the [Prompts Guide](./prompts.md) for more details on using the prompt templates. 211 | 212 | ### Testing Configuration 213 | 214 | The Code-Reasoning MCP Server includes testing functionality for developers who are extending or modifying the server. Most users do not need to be concerned with these testing capabilities. 215 | 216 | #### Basic Testing Commands 217 | 218 | To run the default quality checks: 219 | 220 | ```bash 221 | npm test 222 | ``` 223 | 224 | This command currently runs ESLint. For a broader pass that also formats and rebuilds the project, use `npm run validate`. 225 | 226 | For more detailed information about testing, refer to the [Testing Guide](./testing.md). 227 | -------------------------------------------------------------------------------- /src/prompts/manager.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Prompt manager for MCP prompts. 3 | * 4 | * This class handles the management of prompts, including registration, 5 | * validation, and application of prompt templates. 6 | * 7 | * It implements the standard MCP CompleteRequestSchema protocol for 8 | * providing auto-completion of prompt arguments with previously stored values. 9 | */ 10 | 11 | import * as fs from 'fs'; 12 | import * as path from 'path'; 13 | import * as os from 'os'; 14 | import { Prompt, PromptResult } from './types.js'; 15 | import { CODE_REASONING_PROMPTS, PROMPT_TEMPLATES } from './templates.js'; 16 | import { CONFIG_DIR, PROMPT_VALUES_FILE } from '../utils/config.js'; 17 | 18 | interface StoredPromptValues { 19 | global: Record; 20 | prompts: Record>; 21 | } 22 | 23 | /** 24 | * Manages prompt templates and their operations. 25 | * Uses the CompleteRequestSchema MCP protocol for argument completion. 26 | */ 27 | export class PromptManager { 28 | private prompts: Record; 29 | private templates: Record) => PromptResult>; 30 | private storedValues: StoredPromptValues = { global: {}, prompts: {} }; 31 | private valuesFilePath?: string; 32 | private persistenceEnabled = false; 33 | 34 | /** 35 | * Creates a new PromptManager instance with default code reasoning prompts. 36 | * 37 | * @param configDir Optional directory for configuration files. Defaults to the centralized CONFIG_DIR. 38 | */ 39 | constructor(configDir?: string) { 40 | this.prompts = { ...CODE_REASONING_PROMPTS }; 41 | this.templates = { ...PROMPT_TEMPLATES }; 42 | 43 | // Use provided config directory or default to CONFIG_DIR 44 | const resolvedConfigDir = configDir || CONFIG_DIR; 45 | 46 | this.ensureDirectoryExists(resolvedConfigDir, 'main config directory'); 47 | 48 | console.info(`Using config directory: ${resolvedConfigDir}`); 49 | 50 | this.initializeValueStorage(resolvedConfigDir); 51 | 52 | console.info('PromptManager initialized with', Object.keys(this.prompts).length, 'prompts'); 53 | } 54 | 55 | private ensureDirectoryExists(directoryPath: string, description: string): void { 56 | try { 57 | const createdPath = fs.mkdirSync(directoryPath, { recursive: true }); 58 | if (createdPath) { 59 | console.info(`Created ${description}: ${directoryPath}`); 60 | } 61 | } catch (err) { 62 | const error = err as Error; 63 | throw new Error(`Failed to create ${description}: ${directoryPath}`, { cause: error }); 64 | } 65 | } 66 | 67 | private initializeValueStorage(configDir: string): void { 68 | const defaultPath = 69 | configDir === path.dirname(PROMPT_VALUES_FILE) 70 | ? PROMPT_VALUES_FILE 71 | : path.join(configDir, 'prompt_values.json'); 72 | 73 | const fallbackPath = path.join(os.tmpdir(), 'code-reasoning-prompt-values.json'); 74 | const candidates = [defaultPath]; 75 | if (!candidates.includes(fallbackPath)) { 76 | candidates.push(fallbackPath); 77 | } 78 | 79 | this.persistenceEnabled = false; 80 | this.valuesFilePath = undefined; 81 | 82 | const initializationErrors: Error[] = []; 83 | for (const candidate of candidates) { 84 | try { 85 | this.storedValues = this.loadStoredValues(candidate); 86 | this.valuesFilePath = candidate; 87 | this.persistenceEnabled = true; 88 | console.error(`Prompt values will be stored at: ${candidate}`); 89 | return; 90 | } catch (err) { 91 | const error = err as Error; 92 | initializationErrors.push(error); 93 | console.error(`Failed to initialize prompt values at ${candidate}:`, error); 94 | } 95 | } 96 | 97 | throw new AggregateError( 98 | initializationErrors, 99 | `Unable to initialize prompt value persistence. Tried: ${candidates.join(', ')}` 100 | ); 101 | } 102 | 103 | private loadStoredValues(filePath: string): StoredPromptValues { 104 | const defaults: StoredPromptValues = { global: {}, prompts: {} }; 105 | 106 | fs.mkdirSync(path.dirname(filePath), { recursive: true }); 107 | 108 | if (!fs.existsSync(filePath)) { 109 | fs.writeFileSync(filePath, JSON.stringify(defaults, null, 2)); 110 | return { global: {}, prompts: {} }; 111 | } 112 | 113 | const fileContent = fs.readFileSync(filePath, 'utf8'); 114 | const parsed = JSON.parse(fileContent) as Partial; 115 | 116 | const parsedGlobal = parsed.global && typeof parsed.global === 'object' ? parsed.global : {}; 117 | const parsedPrompts = 118 | parsed.prompts && typeof parsed.prompts === 'object' ? parsed.prompts : {}; 119 | 120 | const promptsCopy: Record> = {}; 121 | Object.entries(parsedPrompts).forEach(([key, value]) => { 122 | if (value && typeof value === 'object') { 123 | promptsCopy[key] = { ...(value as Record) }; 124 | } 125 | }); 126 | 127 | return { 128 | global: { ...(parsedGlobal as Record) }, 129 | prompts: promptsCopy, 130 | }; 131 | } 132 | 133 | private saveStoredValues(): void { 134 | if (!this.persistenceEnabled || !this.valuesFilePath) { 135 | throw new Error('Prompt value persistence is not configured.'); 136 | } 137 | 138 | try { 139 | fs.writeFileSync(this.valuesFilePath, JSON.stringify(this.storedValues, null, 2)); 140 | } catch (err) { 141 | const error = err as Error; 142 | throw new Error(`Error saving prompt values to ${this.valuesFilePath}: ${error.message}`, { 143 | cause: error, 144 | }); 145 | } 146 | } 147 | 148 | /** 149 | * Registers a new prompt and its template function. 150 | * 151 | * @param prompt The prompt definition 152 | * @param template The template function that applies arguments to generate a result 153 | */ 154 | registerPrompt(prompt: Prompt, template: (args: Record) => PromptResult): void { 155 | this.prompts[prompt.name] = prompt; 156 | this.templates[prompt.name] = template; 157 | console.error(`Registered prompt: ${prompt.name}`); 158 | } 159 | 160 | /** 161 | * Gets all available prompts. 162 | * 163 | * Note: Previously stored values for prompt arguments are provided through 164 | * the CompleteRequestSchema MCP protocol, not through the prompt objects. 165 | * 166 | * @returns An array of all registered prompts 167 | */ 168 | getAllPrompts(): Prompt[] { 169 | // Simply return the prompts without adding defaultValues 170 | return Object.values(this.prompts); 171 | } 172 | 173 | /** 174 | * Gets a specific prompt by name. 175 | * 176 | * @param name The name of the prompt to retrieve 177 | * @returns The prompt or undefined if not found 178 | */ 179 | getPrompt(name: string): Prompt | undefined { 180 | return this.prompts[name]; 181 | } 182 | 183 | /** 184 | * Gets stored values for a specific prompt. 185 | * This method is used by the CompleteRequestSchema handler to provide 186 | * auto-completion of prompt arguments. 187 | * 188 | * @param name The name of the prompt 189 | * @returns The stored values for the prompt 190 | */ 191 | getStoredValues(name: string): Record { 192 | const result: Record = { ...this.storedValues.global }; 193 | const promptValues = this.storedValues.prompts[name]; 194 | if (promptValues) { 195 | Object.assign(result, promptValues); 196 | } 197 | return result; 198 | } 199 | 200 | /** 201 | * Merges provided arguments with stored values, with provided args taking precedence. 202 | * This is a helper method to simplify the applyPrompt method. 203 | * 204 | * @param promptName The name of the prompt 205 | * @param args The provided arguments 206 | * @returns The merged arguments 207 | */ 208 | private mergeWithStoredValues( 209 | prompt: Prompt, 210 | args: Record 211 | ): Record { 212 | // Get stored values 213 | const storedValues = this.getStoredValues(prompt.name); 214 | 215 | const validArgNames = new Set((prompt.arguments || []).map(arg => arg.name)); 216 | 217 | const filteredStoredValues: Record = {}; 218 | Object.entries(storedValues).forEach(([key, value]) => { 219 | const isGlobalKey = Object.prototype.hasOwnProperty.call(this.storedValues.global, key); 220 | if (isGlobalKey && !validArgNames.has(key)) { 221 | return; 222 | } 223 | filteredStoredValues[key] = value; 224 | }); 225 | 226 | // Filter out empty args 227 | const filteredArgs: Record = {}; 228 | Object.entries(args).forEach(([key, value]) => { 229 | if (value.trim() !== '') { 230 | filteredArgs[key] = value; 231 | } 232 | }); 233 | 234 | // Merge stored values with filtered args (filtered args take precedence) 235 | return { ...filteredStoredValues, ...filteredArgs }; 236 | } 237 | 238 | /** 239 | * Applies a prompt with the given arguments. 240 | * Merges provided arguments with previously stored values, 241 | * with provided arguments taking precedence. 242 | * 243 | * @param name The name of the prompt to apply 244 | * @param args The arguments to apply to the prompt template 245 | * @returns The result of applying the prompt 246 | * @throws Error if the prompt doesn't exist or arguments are invalid 247 | */ 248 | applyPrompt(name: string, args: Record = {}): PromptResult { 249 | const prompt = this.getPrompt(name); 250 | if (!prompt) { 251 | throw new Error(`Prompt not found: ${name}`); 252 | } 253 | 254 | // Merge with stored values 255 | const mergedArgs = this.mergeWithStoredValues(prompt, args); 256 | 257 | // Validate arguments 258 | const validationErrors = this.validatePromptArguments(prompt, mergedArgs); 259 | if (validationErrors.length > 0) { 260 | throw new Error(`Validation errors:\n${validationErrors.join('\n')}`); 261 | } 262 | 263 | // Get the template function 264 | const templateFn = this.templates[name]; 265 | if (!templateFn) { 266 | throw new Error(`Template implementation not found for prompt: ${name}`); 267 | } 268 | 269 | // Update stored values with the new ones 270 | this.updateStoredValues(name, mergedArgs); 271 | 272 | // Apply the template with merged args 273 | return templateFn(mergedArgs); 274 | } 275 | 276 | private updateStoredValues(promptName: string, args: Record): void { 277 | if (args.working_directory && args.working_directory.trim() !== '') { 278 | this.storedValues.global.working_directory = args.working_directory; 279 | } 280 | 281 | if (!this.storedValues.prompts[promptName]) { 282 | this.storedValues.prompts[promptName] = {}; 283 | } 284 | 285 | const promptValues = this.storedValues.prompts[promptName]; 286 | const globalKeys = new Set(Object.keys(this.storedValues.global)); 287 | 288 | Object.entries(args).forEach(([key, value]) => { 289 | if (!value || value.trim() === '') { 290 | return; 291 | } 292 | if (globalKeys.has(key)) { 293 | return; 294 | } 295 | promptValues[key] = value; 296 | }); 297 | 298 | this.saveStoredValues(); 299 | } 300 | /** 301 | * Validates prompt arguments against the prompt definition. 302 | * 303 | * @param prompt The prompt to validate against 304 | * @param args The arguments to validate 305 | * @returns Array of validation error messages, empty if valid 306 | */ 307 | private validatePromptArguments(prompt: Prompt, args: Record): string[] { 308 | const errors: string[] = []; 309 | 310 | // Check for required arguments 311 | (prompt.arguments || []).forEach( 312 | (arg: { name: string; description: string; required: boolean }) => { 313 | if (arg.required && (!args[arg.name] || args[arg.name].trim() === '')) { 314 | errors.push(`Missing required argument: ${arg.name} (${arg.description})`); 315 | } 316 | } 317 | ); 318 | 319 | // Check for unknown arguments 320 | const validArgNames = new Set((prompt.arguments || []).map(arg => arg.name)); 321 | Object.keys(args).forEach(argName => { 322 | if (!validArgNames.has(argName)) { 323 | errors.push(`Unknown argument: ${argName}`); 324 | } 325 | }); 326 | 327 | return errors; 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /docs/examples.md: -------------------------------------------------------------------------------- 1 | # Code-Reasoning MCP Server Usage Examples 2 | 3 | This document provides detailed usage examples for the Code-Reasoning MCP Server. These examples demonstrate how to use the sequential thinking capabilities for programming tasks and complex problem-solving. 4 | 5 | ## Table of Contents 6 | 7 | - [Basic Usage Examples](#basic-usage-examples) 8 | - [Advanced Examples](#advanced-examples) 9 | - [Thought Branching](#thought-branching) 10 | - [Thought Revision](#thought-revision) 11 | - [Integration Examples](#integration-examples) 12 | - [Claude Desktop Integration](#claude-desktop-integration) 13 | - [VS Code Integration](#vs-code-integration) 14 | - [Debugging Examples](#debugging-examples) 15 | - [Using Logging](#using-logging) 16 | - [Example Config Files](#example-config-files) 17 | 18 | ## Basic Usage Examples 19 | 20 | ### Simple Sequential Thinking Flow 21 | 22 | This example shows a basic sequential thinking process for solving a programming problem: 23 | 24 | ```json 25 | // Thought 1 26 | { 27 | "thought": "First, let's understand the problem: we need to implement a function that finds duplicate elements in an array.", 28 | "thought_number": 1, 29 | "total_thoughts": 4, 30 | "next_thought_needed": true 31 | } 32 | 33 | // Thought 2 34 | { 35 | "thought": "There are multiple approaches we could take: using nested loops (O(n²)), using a hash table (O(n)), or sorting and then finding adjacent duplicates (O(n log n)).", 36 | "thought_number": 2, 37 | "total_thoughts": 4, 38 | "next_thought_needed": true 39 | } 40 | 41 | // Thought 3 42 | { 43 | "thought": "Let's implement the hash table approach since it's efficient in terms of time complexity (O(n)). We'll use a Set or Map to track elements we've seen.", 44 | "thought_number": 3, 45 | "total_thoughts": 4, 46 | "next_thought_needed": true 47 | } 48 | 49 | // Thought 4 50 | { 51 | "thought": "Here's the JavaScript implementation:\n\nfunction findDuplicates(arr) {\n const seen = new Set();\n const duplicates = new Set();\n \n for (const item of arr) {\n if (seen.has(item)) {\n duplicates.add(item);\n } else {\n seen.add(item);\n }\n }\n \n return Array.from(duplicates);\n}\n\nThis solution is O(n) in time complexity and handles edge cases properly.", 52 | "thought_number": 4, 53 | "total_thoughts": 4, 54 | "next_thought_needed": false 55 | } 56 | ``` 57 | 58 | ### Real-world Example: Debugging a Recursive Function 59 | 60 | This example demonstrates how to use sequential thinking to debug a recursive function with a stack overflow issue: 61 | 62 | ```json 63 | // Thought 1 64 | { 65 | "thought": "The problem is a stack overflow error in a recursive function to calculate Fibonacci numbers. Let's first understand the current implementation.", 66 | "thought_number": 1, 67 | "total_thoughts": 5, 68 | "next_thought_needed": true 69 | } 70 | 71 | // Thought 2 72 | { 73 | "thought": "Here's the problematic code:\n\nfunction fibonacci(n) {\n return fibonacci(n - 1) + fibonacci(n - 2);\n}\n\nThe issue is there's no base case, so it recurses infinitely. Also, this is extremely inefficient due to recalculating values repeatedly.", 74 | "thought_number": 2, 75 | "total_thoughts": 5, 76 | "next_thought_needed": true 77 | } 78 | 79 | // Thought 3 80 | { 81 | "thought": "Let's fix the base case issue first:\n\nfunction fibonacci(n) {\n if (n <= 0) return 0;\n if (n === 1) return 1;\n return fibonacci(n - 1) + fibonacci(n - 2);\n}\n\nThis prevents infinite recursion, but is still inefficient for large n values.", 82 | "thought_number": 3, 83 | "total_thoughts": 5, 84 | "next_thought_needed": true 85 | } 86 | 87 | // Thought 4 88 | { 89 | "thought": "To improve efficiency, we should use memoization to store previously calculated values:\n\nfunction fibonacci(n, memo = {}) {\n if (n <= 0) return 0;\n if (n === 1) return 1;\n if (memo[n]) return memo[n];\n \n memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo);\n return memo[n];\n}\n\nThis caches results to prevent redundant calculations.", 90 | "thought_number": 4, 91 | "total_thoughts": 5, 92 | "next_thought_needed": true 93 | } 94 | 95 | // Thought 5 96 | { 97 | "thought": "For even better performance, we could use an iterative approach instead of recursion:\n\nfunction fibonacci(n) {\n if (n <= 0) return 0;\n if (n === 1) return 1;\n \n let a = 0, b = 1;\n for (let i = 2; i <= n; i++) {\n const temp = a + b;\n a = b;\n b = temp;\n }\n \n return b;\n}\n\nThis iterative solution has O(n) time complexity and constant space complexity, avoiding both stack overflow and inefficiency issues.", 98 | "thought_number": 5, 99 | "total_thoughts": 5, 100 | "next_thought_needed": false 101 | } 102 | ``` 103 | 104 | ## Advanced Examples 105 | 106 | ### Thought Branching 107 | 108 | This example demonstrates how to use thought branching to explore multiple approaches to solving a programming problem: 109 | 110 | ```json 111 | // Thought 1 (Main path) 112 | { 113 | "thought": "We need to design a system that can efficiently process large batches of data. Let's consider the main approaches.", 114 | "thought_number": 1, 115 | "total_thoughts": 6, 116 | "next_thought_needed": true 117 | } 118 | 119 | // Thought 2 (Main path) 120 | { 121 | "thought": "Main Approach: We could use a streaming architecture with message queues for handling data in real-time batches.", 122 | "thought_number": 2, 123 | "total_thoughts": 6, 124 | "next_thought_needed": true 125 | } 126 | 127 | // Thought 3 (Branch from Thought 1) 128 | { 129 | "thought": "Alternative Approach: We could also consider batch processing with scheduled ETL jobs instead of real-time processing.", 130 | "thought_number": 3, 131 | "total_thoughts": 6, 132 | "branch_from_thought": 1, 133 | "branch_id": "BatchETL", 134 | "next_thought_needed": true 135 | } 136 | 137 | // Thought 3 (Main path) 138 | { 139 | "thought": "For the streaming approach, we'll need components like: data producers, message broker (Kafka/RabbitMQ), stream processors, and data storage.", 140 | "thought_number": 3, 141 | "total_thoughts": 6, 142 | "next_thought_needed": true 143 | } 144 | 145 | // Thought 4 (BatchETL branch) 146 | { 147 | "thought": "For batch ETL, we'll need: data extraction jobs, transformation pipelines, data warehousing, and orchestration tools like Airflow.", 148 | "thought_number": 4, 149 | "total_thoughts": 6, 150 | "branch_from_thought": 3, 151 | "branch_id": "BatchETL", 152 | "next_thought_needed": true 153 | } 154 | 155 | // Thought 4 (Main path) 156 | { 157 | "thought": "Main approach implementation: 1) Set up Kafka topics, 2) Implement data producers with retry logic, 3) Create stream processors with Kafka Streams, 4) Store in timeseries DB.", 158 | "thought_number": 4, 159 | "total_thoughts": 6, 160 | "next_thought_needed": true 161 | } 162 | 163 | // Thought 5 (BatchETL branch) 164 | { 165 | "thought": "The batch approach is simpler and more cost-effective for this use case. Implementing with: 1) Daily data dumps, 2) Spark processing, 3) Data warehouse loading.", 166 | "thought_number": 5, 167 | "total_thoughts": 6, 168 | "branch_from_thought": 4, 169 | "branch_id": "BatchETL", 170 | "next_thought_needed": false 171 | } 172 | 173 | // Thought 5 (Main path) 174 | { 175 | "thought": "After comparing both approaches, the streaming architecture is preferred due to real-time requirements, despite higher complexity and cost.", 176 | "thought_number": 5, 177 | "total_thoughts": 6, 178 | "next_thought_needed": false 179 | } 180 | ``` 181 | 182 | ### Thought Revision 183 | 184 | This example demonstrates how to use thought revision to correct errors in reasoning: 185 | 186 | ```json 187 | // Thought 1 188 | { 189 | "thought": "I need to implement a sort algorithm. Based on requirements, quicksort seems appropriate due to average case O(n log n) performance.", 190 | "thought_number": 1, 191 | "total_thoughts": 4, 192 | "next_thought_needed": true 193 | } 194 | 195 | // Thought 2 196 | { 197 | "thought": "Here's a basic quicksort implementation in Python:\n\ndef quicksort(arr):\n if len(arr) <= 1:\n return arr\n pivot = arr[0]\n left = [x for x in arr[1:] if x < pivot]\n right = [x for x in arr[1:] if x >= pivot]\n return quicksort(left) + [pivot] + quicksort(right)", 198 | "thought_number": 2, 199 | "total_thoughts": 4, 200 | "next_thought_needed": true 201 | } 202 | 203 | // Thought 3 (Revision of Thought 1) 204 | { 205 | "thought": "On second thought, I overlooked the fact that the data might be already partially sorted, which is quicksort's worst-case scenario (O(n²)). Also, stability is required. Mergesort would be a better choice since it guarantees O(n log n) regardless of input and is stable.", 206 | "thought_number": 3, 207 | "total_thoughts": 5, 208 | "is_revision": true, 209 | "revises_thought": 1, 210 | "next_thought_needed": true 211 | } 212 | 213 | // Thought 4 (Revision of Thought 2) 214 | { 215 | "thought": "Let's implement mergesort instead:\n\ndef mergesort(arr):\n if len(arr) <= 1:\n return arr\n \n mid = len(arr) // 2\n left = mergesort(arr[:mid])\n right = mergesort(arr[mid:])\n \n return merge(left, right)\n\ndef merge(left, right):\n result = []\n i = j = 0\n \n while i < len(left) and j < len(right):\n if left[i] <= right[j]: # Note: <= preserves stability\n result.append(left[i])\n i += 1\n else:\n result.append(right[j])\n j += 1\n \n result.extend(left[i:])\n result.extend(right[j:])\n return result", 216 | "thought_number": 4, 217 | "total_thoughts": 5, 218 | "is_revision": true, 219 | "revises_thought": 2, 220 | "next_thought_needed": true 221 | } 222 | 223 | // Thought 5 224 | { 225 | "thought": "The mergesort implementation meets all requirements: O(n log n) worst-case time complexity, stability, and works well with the expected data patterns. The trade-off is O(n) extra space, but this is acceptable given the reliability benefits.", 226 | "thought_number": 5, 227 | "total_thoughts": 5, 228 | "next_thought_needed": false 229 | } 230 | ``` 231 | 232 | ## Integration Examples 233 | 234 | ### Claude Desktop Integration 235 | 236 | To use the code-reasoning server with Claude Desktop, you'll need to configure Claude Desktop to use the server. 237 | 238 | #### Example Configuration (Basic) 239 | 240 | ```json 241 | // claude_desktop_config.json 242 | { 243 | "mcpServers": { 244 | "code-reasoning": { 245 | "command": "code-reasoning", 246 | "args": [] 247 | } 248 | } 249 | } 250 | ``` 251 | 252 | #### Example Configuration (With Debugging) 253 | 254 | ```json 255 | // claude_desktop_config.json 256 | { 257 | "mcpServers": { 258 | "code-reasoning": { 259 | "command": "code-reasoning", 260 | "args": ["--debug"] 261 | } 262 | } 263 | } 264 | ``` 265 | 266 | #### Example Prompt for Claude 267 | 268 | When using Claude Desktop with the code-reasoning server, you can use the sequential thinking capability by asking Claude to reason step by step. The current tool description is: 269 | 270 | ``` 271 | 🧠 A reflective problem-solving tool with sequential thinking. 272 | 273 | • Break down tasks into numbered thoughts that can BRANCH (🌿) or REVISE (🔄) until a conclusion is reached. 274 | • Always set 'next_thought_needed' = false when no further reasoning is needed. 275 | 276 | ✅ Recommended checklist every 3 thoughts: 277 | 1. Need to BRANCH? → set 'branch_from_thought' + 'branch_id'. 278 | 2. Need to REVISE? → set 'is_revision' + 'revises_thought'. 279 | 3. Scope changed? → bump 'total_thoughts'. 280 | 281 | ✍️ End each thought with: "What am I missing?" 282 | ``` 283 | 284 | Example prompts to use with Claude: 285 | 286 | ``` 287 | Please help me design a simple REST API for a todo application. Use code-reasoning to break down the design process into steps. 288 | ``` 289 | 290 | Or more specifically for code-related tasks: 291 | 292 | ``` 293 | Please analyze this algorithm implementation and identify any bugs or inefficiencies. Use code-reasoning to break down your analysis step by step. 294 | ``` 295 | 296 | ### VS Code Integration 297 | 298 | For VS Code integration, you can configure the MCP server in your VS Code settings. 299 | 300 | #### Example VS Code Configuration 301 | 302 | ```json 303 | // settings.json or .vscode/mcp.json 304 | { 305 | "mcp": { 306 | "servers": { 307 | "code-reasoning": { 308 | "command": "code-reasoning", 309 | "args": ["--debug"] 310 | } 311 | } 312 | } 313 | } 314 | ``` 315 | 316 | ## Debugging Examples 317 | 318 | ### Using Logging 319 | 320 | To enable detailed logging, use the `--debug` flag: 321 | 322 | ```bash 323 | code-reasoning --debug 324 | ``` 325 | 326 | #### Example Log Output 327 | 328 | ``` 329 | Starting Code-Reasoning MCP Server (streamlined v0.5.0)... { 330 | "logLevel": "INFO", 331 | "debug": true, 332 | "pid": 12345 333 | } 334 | Code Reasoning Server logic handler initialized { 335 | "config": { 336 | "maxThoughtLength": 20000, 337 | "timeoutMs": 30000, 338 | "maxThoughts": 20, 339 | "logLevel": "INFO", 340 | "debug": true 341 | } 342 | } 343 | Received ListTools request 344 | 💭 Thought 1/5 345 | --- 346 | First, let's understand the problem: we need to design a simple calculator function. 347 | --- 348 | Thought processed successfully { 349 | "thought_number": 1, 350 | "is_revision": false, 351 | "branch_id": null, 352 | "next_thought_needed": true, 353 | "processingTimeMs": 5 354 | } 355 | ``` 356 | 357 | ## Example Config Files 358 | 359 | ### Example claude_desktop_config.json 360 | 361 | ```json 362 | { 363 | "mcpServers": { 364 | "code-reasoning": { 365 | "command": "code-reasoning", 366 | "args": ["--debug"] 367 | }, 368 | "another-server": { 369 | "command": "another-command", 370 | "args": [] 371 | } 372 | }, 373 | "defaultModel": "claude-3-7-sonnet", 374 | "sessionDefaults": { 375 | "enableMultiModal": true 376 | } 377 | } 378 | ``` 379 | 380 | ### Example VS Code Settings 381 | 382 | ```json 383 | { 384 | "editor.fontFamily": "Fira Code, monospace", 385 | "editor.fontSize": 14, 386 | "mcp": { 387 | "servers": { 388 | "code-reasoning": { 389 | "command": "code-reasoning", 390 | "args": ["--debug"] 391 | } 392 | } 393 | } 394 | } 395 | ``` 396 | 397 | ### Example Workspace .vscode/mcp.json 398 | 399 | ```json 400 | { 401 | "servers": { 402 | "code-reasoning": { 403 | "command": "code-reasoning", 404 | "args": ["--debug"] 405 | } 406 | } 407 | } 408 | ``` 409 | -------------------------------------------------------------------------------- /src/prompts/templates.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Prompt templates for code reasoning. 3 | * 4 | * This file defines a set of prompt templates specifically designed for 5 | * code reasoning tasks. 6 | */ 7 | 8 | import { Prompt, PromptResult } from './types.js'; 9 | 10 | /** 11 | * Collection of code reasoning prompts. 12 | */ 13 | export const CODE_REASONING_PROMPTS: Record = { 14 | 'architecture-decision': { 15 | name: 'architecture-decision', 16 | description: 'Framework for making and documenting architecture decisions', 17 | arguments: [ 18 | { 19 | name: 'decision_context', 20 | description: 'The architectural decision that needs to be made', 21 | required: true, 22 | }, 23 | { 24 | name: 'constraints', 25 | description: 'Constraints that impact the decision', 26 | required: false, 27 | }, 28 | { 29 | name: 'options', 30 | description: 'Options being considered', 31 | required: false, 32 | }, 33 | { 34 | name: 'working_directory', 35 | description: 'Path to the current project directory', 36 | required: false, 37 | }, 38 | ], 39 | }, 40 | 'bug-analysis': { 41 | name: 'bug-analysis', 42 | description: 'Systematic approach to analyzing and fixing bugs', 43 | arguments: [ 44 | { 45 | name: 'bug_behavior', 46 | description: 'Description of the observed bug behavior', 47 | required: true, 48 | }, 49 | { 50 | name: 'expected_behavior', 51 | description: 'What should happen when working correctly', 52 | required: true, 53 | }, 54 | { 55 | name: 'affected_components', 56 | description: 57 | 'Primary components affected by the bug (file paths, function names, or module identifiers)', 58 | required: true, 59 | }, 60 | { 61 | name: 'reproduction_steps', 62 | description: 'Steps to reproduce the bug', 63 | required: false, 64 | }, 65 | { 66 | name: 'working_directory', 67 | description: 'Path to the current project directory', 68 | required: false, 69 | }, 70 | ], 71 | }, 72 | 'code-review': { 73 | name: 'code-review', 74 | description: 'Comprehensive template for code review', 75 | arguments: [ 76 | { 77 | name: 'code_path', 78 | description: 'File path or directory to review (will be accessed via filesystem tools)', 79 | required: true, 80 | }, 81 | { 82 | name: 'requirements', 83 | description: 'Requirements that the code should implement', 84 | required: false, 85 | }, 86 | { 87 | name: 'language', 88 | description: 89 | 'Programming language of the code (optional, will be inferred from file extension)', 90 | required: false, 91 | }, 92 | { 93 | name: 'working_directory', 94 | description: 'Path to the current project directory', 95 | required: false, 96 | }, 97 | ], 98 | }, 99 | 'feature-planning': { 100 | name: 'feature-planning', 101 | description: 'Structured approach to planning new feature implementation', 102 | arguments: [ 103 | { 104 | name: 'problem_statement', 105 | description: 'Clear statement of the problem this feature solves', 106 | required: true, 107 | }, 108 | { 109 | name: 'target_users', 110 | description: 'Primary users who will benefit from this feature', 111 | required: true, 112 | }, 113 | { 114 | name: 'success_criteria', 115 | description: 'How we will know the feature is successful', 116 | required: false, 117 | }, 118 | { 119 | name: 'affected_components', 120 | description: 121 | 'Existing components that will need modification (file paths, function names, or module identifiers)', 122 | required: false, 123 | }, 124 | { 125 | name: 'working_directory', 126 | description: 'Path to the current project directory', 127 | required: false, 128 | }, 129 | ], 130 | }, 131 | 'refactoring-plan': { 132 | name: 'refactoring-plan', 133 | description: 'Structured approach to code refactoring', 134 | arguments: [ 135 | { 136 | name: 'current_issues', 137 | description: 'Issues in the current code that prompted refactoring', 138 | required: true, 139 | }, 140 | { 141 | name: 'goals', 142 | description: 'Goals of the refactoring effort', 143 | required: true, 144 | }, 145 | { 146 | name: 'working_directory', 147 | description: 'Path to the current project directory', 148 | required: false, 149 | }, 150 | ], 151 | }, 152 | }; 153 | 154 | /** 155 | * Template implementation functions. 156 | * Each function takes a record of argument values and returns a prompt result. 157 | */ 158 | export const PROMPT_TEMPLATES: Record) => PromptResult> = { 159 | 'architecture-decision': args => ({ 160 | messages: [ 161 | { 162 | role: 'user', 163 | content: { 164 | type: 'text', 165 | text: `# Architecture Decision Record 166 | 167 | ${args.working_directory ? `Working Directory: ${args.working_directory}\n` : ''} 168 | 169 | Please use reflective problem-solving through sequential thinking to analyze this architectural decision. Use the code-reasoning mcp tool to break down your analysis into structured steps. 170 | 171 | Note: You can access and modify files using the filesystem tool mcp. 172 | 173 | 1. **Context** 174 | - Decision context: ${args.decision_context || 'N/A'} 175 | - Constraints: ${args.constraints || 'N/A'} 176 | - Options: ${args.options || 'N/A'} 177 | 178 | 2. **Options Considered** 179 | - What alternatives have we identified? 180 | - For each alternative: 181 | - What are its key characteristics? 182 | - What are its advantages? 183 | - What are its disadvantages? 184 | - What risks does it present? 185 | 186 | 3. **Decision Criteria** 187 | - What factors are most important for this decision? 188 | - How do we weigh different concerns (performance, maintainability, etc.)? 189 | 190 | 4. **Evaluation** 191 | - How does each option perform against our criteria? 192 | - What trade-offs does each option represent? 193 | 194 | 5. **Decision** 195 | - Which option do we select and why? 196 | - What were the key factors in this decision? 197 | 198 | 6. **Consequences** 199 | - What are the implications of this decision? 200 | - What becomes easier or harder as a result? 201 | - What new constraints does this create? 202 | - What follow-up decisions will be needed? 203 | 204 | This critical architectural decision deserves thorough analysis. Use the code-reasoning mcp tool to structure your thinking and explore different perspectives step by step.`, 205 | }, 206 | }, 207 | ], 208 | }), 209 | 'bug-analysis': args => ({ 210 | messages: [ 211 | { 212 | role: 'user', 213 | content: { 214 | type: 'text', 215 | text: `# Bug Analysis Process 216 | 217 | ${args.working_directory ? `Working Directory: ${args.working_directory}\n` : ''} 218 | 219 | Please use reflective problem-solving through sequential thinking to analyze this bug thoroughly. Use the code-reasoning mcp tool to break down your analysis into structured steps. 220 | 221 | Note: You can access and modify files using the filesystem tool mcp. 222 | 223 | 1. **Understand the reported behavior** 224 | - Bug behavior: ${args.bug_behavior || 'N/A'} 225 | - Reproduction steps: ${args.reproduction_steps || 'N/A'} 226 | 227 | 2. **Identify expected behavior** 228 | - Expected behavior: ${args.expected_behavior || 'N/A'} 229 | 230 | 3. **Isolate affected components** 231 | - Affected components: ${args.affected_components || 'N/A'} 232 | - Note: Components can be file paths (e.g., 'src/utils/parser.ts'), function names (e.g., 'parseConfig()'), or module identifiers (e.g., 'Authentication Module') 233 | - First step: Use filesystem tools to examine the identified components 234 | 235 | 4. **Form hypotheses** 236 | - What are potential root causes? List hypotheses in priority order. 237 | - Analyze affected components using relevant filesystem tools (read_file, search_code, etc.) 238 | 239 | 5. **Test hypotheses** 240 | - How can we validate each hypothesis? 241 | - What experiments or tests will help confirm the cause? 242 | - Consider suggesting specific files to modify for testing 243 | 244 | 6. **Propose fix** 245 | - Once cause is identified, what's the recommended fix? 246 | - What side effects might this fix have? 247 | - How can we verify the fix works? 248 | - Provide specific code changes if appropriate 249 | 250 | Remember to use the code-reasoning mcp tool to structure your thinking through this complex debugging task.`, 251 | }, 252 | }, 253 | ], 254 | }), 255 | 'code-review': args => ({ 256 | messages: [ 257 | { 258 | role: 'user', 259 | content: { 260 | type: 'text', 261 | text: `# Code Review Template 262 | 263 | ${args.working_directory ? `Working Directory: ${args.working_directory}\n` : ''} 264 | 265 | Please use reflective problem-solving through sequential thinking to perform this code review. Use the code-reasoning mcp tool to break down your analysis into structured steps. 266 | 267 | Note: You can access and modify files using the filesystem tool mcp. 268 | 269 | 1. **Code to Review** 270 | - File/Directory Path: ${args.code_path || 'N/A'} 271 | - Language: ${args.language || 'To be inferred from file extension'} 272 | 273 | First steps: 274 | - Use the filesystem tool to access the code (read_file, list_directory, etc.) 275 | - If reviewing a directory, identify key files to analyze first 276 | - For larger files, use search_code to find important patterns or components 277 | 278 | 2. **Requirements** 279 | ${args.requirements || 'No specific requirements provided.'} 280 | 281 | 3. **Functionality Review** 282 | - Does the code correctly implement the requirements? 283 | - Are edge cases handled appropriately? 284 | - Is error handling sufficient and appropriate? 285 | 286 | 4. **Code Quality Review** 287 | - Is the code well-structured and maintainable? 288 | - Are functions/methods single-purpose and reasonably sized? 289 | - Are variable/function names clear and descriptive? 290 | - Is there adequate documentation where needed? 291 | 292 | 5. **Performance Review** 293 | - Are there any potential performance issues? 294 | - Are algorithms and data structures appropriate? 295 | - Are there any unnecessary computations or operations? 296 | 297 | 6. **Security Review** 298 | - Are there any security vulnerabilities? 299 | - Is user input validated and sanitized? 300 | - Are sensitive operations properly secured? 301 | 302 | 7. **Testing Review** 303 | - Is test coverage adequate? 304 | - Do tests cover edge cases and error conditions? 305 | - Are tests clear and maintainable? 306 | 307 | 8. **Summary and Recommendations** 308 | - Overall assessment 309 | - Key issues to address (prioritized) 310 | - Suggestions for improvement 311 | - Specific code changes to consider 312 | 313 | For this complex code analysis, use the code-reasoning mcp tool to structure your thinking and document your review process step by step.`, 314 | }, 315 | }, 316 | ], 317 | }), 318 | 'feature-planning': args => ({ 319 | messages: [ 320 | { 321 | role: 'user', 322 | content: { 323 | type: 'text', 324 | text: `# Feature Planning Process 325 | 326 | ${args.working_directory ? `Working Directory: ${args.working_directory}\n` : ''} 327 | 328 | Please use reflective problem-solving through sequential thinking to develop this feature plan. Use the code-reasoning mcp tool to break down your planning process into structured steps. 329 | 330 | Note: You can access and modify files using the filesystem tool mcp. 331 | 332 | 1. **Feature Requirements** 333 | - Problem statement: ${args.problem_statement || 'N/A'} 334 | - Target users: ${args.target_users || 'N/A'} 335 | - Success criteria: ${args.success_criteria || 'N/A'} 336 | 337 | 2. **Architectural Considerations** 338 | - Affected components: ${args.affected_components || 'N/A'} 339 | - Note: Components can be file paths (e.g., 'src/utils/parser.ts'), function names (e.g., 'parseConfig()'), or module identifiers (e.g., 'Authentication Module') 340 | - Use filesystem tools to examine affected components and understand current implementation 341 | - What new components might be needed? 342 | - Are there any API changes required? 343 | 344 | 3. **Implementation Strategy** 345 | - Break down the feature into implementation tasks 346 | - Identify dependencies between tasks 347 | - Estimate complexity and effort based on codebase analysis 348 | - Plan an implementation sequence 349 | - Suggest specific files to modify, create, or delete 350 | 351 | 4. **Testing Strategy** 352 | - What unit tests will be needed? 353 | - What integration tests will be needed? 354 | - How will we validate user requirements are met? 355 | - Identify existing test files that should be updated 356 | 357 | 5. **Risks and Mitigations** 358 | - What technical risks exist? 359 | - What product/user risks exist? 360 | - How can we mitigate each risk? 361 | - Suggest specific risk mitigation approaches based on codebase analysis 362 | 363 | 6. **Acceptance Criteria** 364 | - Define clear criteria for when this feature is complete 365 | - Include performance and quality expectations 366 | - Specify key files/components that must pass review 367 | 368 | This complex planning task will benefit from using the code-reasoning mcp tool to structure your thinking process.`, 369 | }, 370 | }, 371 | ], 372 | }), 373 | 'refactoring-plan': args => ({ 374 | messages: [ 375 | { 376 | role: 'user', 377 | content: { 378 | type: 'text', 379 | text: `# Refactoring Plan 380 | 381 | ${args.working_directory ? `Working Directory: ${args.working_directory}\n` : ''} 382 | 383 | Please use reflective problem-solving through sequential thinking to develop this refactoring plan. Use the code-reasoning mcp tool to break down your analysis into structured steps. 384 | 385 | Note: You can access and modify files using the filesystem tool mcp. 386 | 387 | 1. **Current Code Assessment** 388 | - Current issues: ${args.current_issues || 'N/A'} 389 | - Goals: ${args.goals || 'N/A'} 390 | - What is working well and should be preserved? 391 | - What metrics indicate refactoring is needed (complexity, duplication, etc.)? 392 | 393 | 2. **Refactoring Goals** 394 | - What specific improvements are we targeting? 395 | - What measurable outcomes do we expect? 396 | 397 | 3. **Risk Analysis** 398 | - What functionality might be affected? 399 | - What are the testing implications? 400 | - What dependencies might be impacted? 401 | 402 | 4. **Refactoring Strategy** 403 | - Break down the refactoring into discrete steps 404 | - Prioritize steps for maximum impact with minimum risk 405 | - Plan for incremental testing between steps 406 | 407 | 5. **Testing Approach** 408 | - How will we verify behavior is preserved? 409 | - What regression tests are needed? 410 | - How will we validate improvements? 411 | 412 | 6. **Implementation Plan** 413 | - Sequence of changes 414 | - Estimated effort 415 | - Verification points 416 | 417 | This complex refactoring task requires careful analysis. Use the code-reasoning mcp tool to structure your thought process for developing a safe and effective approach.`, 418 | }, 419 | }, 420 | ], 421 | }), 422 | }; 423 | -------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * @fileoverview Code Reasoning MCP Server Implementation. 5 | * 6 | * This server provides a tool for reflective problem-solving in software development, 7 | * allowing decomposition of tasks into sequential, revisable, and branchable thoughts. 8 | * It adheres to the Model Context Protocol (MCP) using SDK version 1.18.1 and is designed 9 | * to integrate seamlessly with Claude Desktop or similar MCP-compliant clients. 10 | * 11 | * ## Key Features 12 | * - Processes "thoughts" in structured JSON with sequential numbering 13 | * - Supports advanced reasoning patterns through branching and revision semantics 14 | * - Branching: Explore alternative approaches from any existing thought 15 | * - Revision: Correct or update earlier thoughts when new insights emerge 16 | * - Implements MCP capabilities for tools, resources, and prompts 17 | * - Relies on the standard StdioServerTransport provided by the MCP SDK 18 | * - Provides detailed validation and error handling with helpful guidance 19 | * - Logs thought evolution to stderr for debugging and visibility 20 | * 21 | * ## Usage in Claude Desktop 22 | * - In your Claude Desktop settings, add a "tool" definition referencing this server 23 | * - Ensure the tool name is "code-reasoning" 24 | * - Configure Claude to use this tool for complex reasoning and problem-solving tasks 25 | * - Upon connecting, Claude can call the tool with arguments matching the 26 | * `ThoughtData` interface defined in this file 27 | * 28 | * ## MCP Protocol Communication 29 | * - IMPORTANT: Local MCP servers must never log to stdout (standard output) 30 | * - All logging must be directed to stderr using console.error() instead of console.log() 31 | * - The stdout channel is reserved exclusively for JSON-RPC protocol messages 32 | * - Using console.log() or console.info() will cause client-side parsing errors 33 | * 34 | * ## Example Thought Data 35 | * ```json 36 | * { 37 | * "thought": "Start investigating the root cause of bug #1234", 38 | * "thought_number": 1, 39 | * "total_thoughts": 5, 40 | * "next_thought_needed": true 41 | * } 42 | * ``` 43 | * 44 | * @version 0.7.0 45 | * @mcp-sdk-version 1.18.1 46 | */ 47 | 48 | import process from 'node:process'; 49 | import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; 50 | import { 51 | type CallToolResult, 52 | CompleteRequestSchema, 53 | GetPromptRequestSchema, 54 | ListPromptsRequestSchema, 55 | type LoggingLevel, 56 | } from '@modelcontextprotocol/sdk/types.js'; 57 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; 58 | import { z, ZodError } from 'zod'; 59 | import { PromptManager } from './prompts/manager.js'; 60 | import { CONFIG_DIR } from './utils/config.js'; 61 | 62 | /* -------------------------------------------------------------------------- */ 63 | /* CONFIGURATION */ 64 | /* -------------------------------------------------------------------------- */ 65 | 66 | // Compile-time enum -> const enum would be erased, but we keep values for logs. 67 | export enum LogLevel { 68 | ERROR = 0, 69 | WARN = 1, 70 | INFO = 2, 71 | DEBUG = 3, 72 | } 73 | 74 | const MAX_THOUGHT_LENGTH = 20000; 75 | const MAX_THOUGHTS = 20; 76 | 77 | interface CodeReasoningConfig { 78 | debug: boolean; 79 | promptsEnabled: boolean; 80 | } 81 | 82 | const DEFAULT_CONFIG: Readonly = Object.freeze({ 83 | debug: false, 84 | promptsEnabled: true, 85 | }); 86 | 87 | const createConfig = (overrides: Partial = {}): CodeReasoningConfig => ({ 88 | ...DEFAULT_CONFIG, 89 | ...overrides, 90 | }); 91 | 92 | /* -------------------------------------------------------------------------- */ 93 | /* DATA SCHEMAS */ 94 | /* -------------------------------------------------------------------------- */ 95 | 96 | const createStrictThoughtShape = () => ({ 97 | thought: z 98 | .string() 99 | .trim() 100 | .min(1, 'Thought cannot be empty.') 101 | .max(MAX_THOUGHT_LENGTH, `Thought exceeds ${MAX_THOUGHT_LENGTH} chars.`), 102 | thought_number: z.number().int().positive(), 103 | total_thoughts: z.number().int().positive(), 104 | next_thought_needed: z.boolean(), 105 | is_revision: z.boolean().optional(), 106 | revises_thought: z.number().int().positive().optional(), 107 | branch_from_thought: z.number().int().positive().optional(), 108 | branch_id: z.string().trim().min(1).optional(), 109 | needs_more_thoughts: z.boolean().optional(), 110 | }); 111 | 112 | const createLooseThoughtShape = () => ({ 113 | thought: z.string().trim(), 114 | thought_number: z.number().int(), 115 | total_thoughts: z.number().int(), 116 | next_thought_needed: z.boolean(), 117 | is_revision: z.boolean().optional(), 118 | revises_thought: z.number().int().optional(), 119 | branch_from_thought: z.number().int().optional(), 120 | branch_id: z.string().trim().optional(), 121 | needs_more_thoughts: z.boolean().optional(), 122 | }); 123 | 124 | const ThoughtDataInputShape = createLooseThoughtShape(); 125 | const StrictThoughtSchema = z.object(createStrictThoughtShape()); 126 | 127 | export type ThoughtData = z.infer; 128 | export type ValidatedThoughtData = ThoughtData; 129 | type ParsedThoughtData = z.infer>; 130 | 131 | /* -------------------------------------------------------------------------- */ 132 | /* TOOL DEF */ 133 | /* -------------------------------------------------------------------------- */ 134 | 135 | const TOOL_NAME = 'code-reasoning' as const; 136 | 137 | const createCodeReasoningToolDefinition = (serverVersion: string) => ({ 138 | title: 'Code Reasoning', 139 | description: `🧠 A detailed tool for dynamic and reflective problem-solving through sequential thinking. 140 | 141 | This tool helps you analyze problems through a flexible thinking process that can adapt and evolve. 142 | Each thought can build on, question, or revise previous insights as understanding deepens. 143 | 144 | 📋 KEY PARAMETERS: 145 | - thought: Your current reasoning step (required) 146 | - thought_number: Current number in sequence (required) 147 | - total_thoughts: Estimated final count (required, can adjust as needed) 148 | - next_thought_needed: Set to FALSE ONLY when completely done (required) 149 | - branch_from_thought + branch_id: When exploring alternative approaches (🌿) 150 | - is_revision + revises_thought: When correcting earlier thinking (🔄) 151 | 152 | ✅ CRITICAL CHECKLIST (review every 3 thoughts): 153 | 1. Need to explore alternatives? → Use BRANCH (🌿) with branch_from_thought + branch_id 154 | 2. Need to correct earlier thinking? → Use REVISION (🔄) with is_revision + revises_thought 155 | 3. Scope changed? → Adjust total_thoughts up or down as needed 156 | 4. Only set next_thought_needed = false when you have a complete, verified solution 157 | 158 | 💡 BEST PRACTICES: 159 | - Start with an initial estimate of total_thoughts, but adjust as you go 160 | - Don't hesitate to revise earlier conclusions when new insights emerge 161 | - Use branching to explore multiple approaches to the same problem 162 | - Express uncertainty when present 163 | - Ignore information that is irrelevant to the current step 164 | - End with a clear, validated conclusion before setting next_thought_needed = false 165 | 166 | ✍️ End each thought by asking: "What am I missing or need to reconsider?"`, 167 | annotations: { 168 | readOnlyHint: true, 169 | openWorldHint: false, 170 | }, 171 | _meta: { 172 | schema_version: '1.0.0', 173 | server_version: serverVersion, 174 | categories: ['reasoning', 'analysis'], 175 | recommended_prompt: 'code-reasoning/default', 176 | }, 177 | }); 178 | 179 | /* -------------------------------------------------------------------------- */ 180 | /* SERVER IMPLEMENTATION */ 181 | /* -------------------------------------------------------------------------- */ 182 | 183 | type ThoughtTracker = { 184 | add: (thought: ValidatedThoughtData) => void; 185 | ensureBranchIsValid: (branchFromThought?: number) => void; 186 | branches: () => string[]; 187 | count: () => number; 188 | }; 189 | 190 | interface ServerLogger { 191 | debug: (message: string, details?: unknown) => void; 192 | info: (message: string, details?: unknown) => void; 193 | notice: (message: string, details?: unknown) => void; 194 | warn: (message: string, details?: unknown) => void; 195 | error: (message: string, details?: unknown) => void; 196 | enableRemoteLogging: () => void; 197 | } 198 | 199 | const createServerLogger = (srv: McpServer, debug: boolean): ServerLogger => { 200 | let remoteLoggingEnabled = false; 201 | 202 | const emit = (level: LoggingLevel, message: string, details?: unknown) => { 203 | const data = details === undefined ? { message } : { message, details }; 204 | 205 | if (debug || level !== 'debug') { 206 | const prefix = `[${level}]`; 207 | if (message.startsWith('\n')) { 208 | console.error(message); 209 | } else if (details !== undefined) { 210 | console.error(`${prefix} ${message}`, details); 211 | } else { 212 | console.error(`${prefix} ${message}`); 213 | } 214 | } 215 | 216 | if (remoteLoggingEnabled) { 217 | void srv.sendLoggingMessage({ level, logger: 'code-reasoning', data }).catch(err => { 218 | if (debug) { 219 | console.error('[error] Failed to send logging notification', err); 220 | } 221 | }); 222 | } 223 | }; 224 | 225 | return { 226 | debug: (message, details) => emit('debug', message, details), 227 | info: (message, details) => emit('info', message, details), 228 | notice: (message, details) => emit('notice', message, details), 229 | warn: (message, details) => emit('warning', message, details), 230 | error: (message, details) => emit('error', message, details), 231 | enableRemoteLogging: () => { 232 | remoteLoggingEnabled = true; 233 | }, 234 | }; 235 | }; 236 | 237 | const createThoughtTracker = (): ThoughtTracker => { 238 | const thoughtHistory: ValidatedThoughtData[] = []; 239 | const branches = new Map(); 240 | 241 | return { 242 | add: thought => { 243 | thoughtHistory.push(thought); 244 | if (thought.branch_id) { 245 | const branchThoughts = branches.get(thought.branch_id) ?? []; 246 | branchThoughts.push(thought); 247 | branches.set(thought.branch_id, branchThoughts); 248 | } 249 | }, 250 | ensureBranchIsValid: branchFromThought => { 251 | if (branchFromThought && branchFromThought > thoughtHistory.length) { 252 | throw new Error(`Invalid branch_from_thought ${branchFromThought}.`); 253 | } 254 | }, 255 | branches: () => Array.from(branches.keys()), 256 | count: () => thoughtHistory.length, 257 | }; 258 | }; 259 | 260 | const formatThought = (t: ValidatedThoughtData): string => { 261 | const { 262 | thought_number, 263 | total_thoughts, 264 | thought, 265 | is_revision, 266 | revises_thought, 267 | branch_id, 268 | branch_from_thought, 269 | } = t; 270 | 271 | const header = is_revision 272 | ? `🔄 Revision ${thought_number}/${total_thoughts} (of ${revises_thought})` 273 | : branch_id 274 | ? `🌿 Branch ${thought_number}/${total_thoughts} (from ${branch_from_thought}, id:${branch_id})` 275 | : `💭 Thought ${thought_number}/${total_thoughts}`; 276 | 277 | const body = thought 278 | .split('\n') 279 | .map(l => ` ${l}`) 280 | .join('\n'); 281 | 282 | return `\n${header}\n---\n${body}\n---`; 283 | }; 284 | 285 | const getExampleThought = (errorMsg: string): Partial => { 286 | if (errorMsg.includes('branch')) { 287 | return { 288 | thought: 'Exploring alternative: Consider algorithm X.', 289 | thought_number: 3, 290 | total_thoughts: 7, 291 | next_thought_needed: true, 292 | branch_from_thought: 2, 293 | branch_id: 'alternative-algo-x', 294 | }; 295 | } 296 | if (errorMsg.includes('revis')) { 297 | return { 298 | thought: 'Revisiting earlier point: Assumption Y was flawed.', 299 | thought_number: 4, 300 | total_thoughts: 6, 301 | next_thought_needed: true, 302 | is_revision: true, 303 | revises_thought: 2, 304 | }; 305 | } 306 | if (errorMsg.includes('length') || errorMsg.includes('Thought cannot be empty')) { 307 | return { 308 | thought: 'Breaking down the thought into smaller parts...', 309 | thought_number: 2, 310 | total_thoughts: 5, 311 | next_thought_needed: true, 312 | }; 313 | } 314 | return { 315 | thought: 'Initial exploration of the problem.', 316 | thought_number: 1, 317 | total_thoughts: 5, 318 | next_thought_needed: true, 319 | }; 320 | }; 321 | 322 | const buildSuccess = (t: ValidatedThoughtData, tracker: ThoughtTracker): CallToolResult => { 323 | const payload = { 324 | status: 'processed', 325 | thought_number: t.thought_number, 326 | total_thoughts: t.total_thoughts, 327 | next_thought_needed: t.next_thought_needed, 328 | branches: tracker.branches(), 329 | thought_history_length: tracker.count(), 330 | } as const; 331 | 332 | return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }], isError: false }; 333 | }; 334 | 335 | const buildError = (error: Error, debug: boolean, logger: ServerLogger): CallToolResult => { 336 | let errorMessage = error.message; 337 | let guidance = 'Check the tool description and schema for correct usage.'; 338 | const example = getExampleThought(errorMessage); 339 | 340 | if (error instanceof ZodError) { 341 | if (debug) { 342 | logger.debug('Zod validation errors', error.errors); 343 | } 344 | errorMessage = `Validation Error: ${error.errors 345 | .map(e => `${e.path.join('.')}: ${e.message}`) 346 | .join(', ')}`; 347 | 348 | const firstPath = error.errors[0]?.path.join('.'); 349 | if (firstPath?.includes('thought') && !firstPath.includes('number')) { 350 | guidance = `The 'thought' field is empty or invalid. Must be a non-empty string below ${MAX_THOUGHT_LENGTH} characters.`; 351 | } else if (firstPath?.includes('thought_number')) { 352 | guidance = 'Ensure thought_number is a positive integer and increments correctly.'; 353 | } else if (firstPath?.includes('branch')) { 354 | guidance = 355 | 'When branching, provide both "branch_from_thought" (number) and "branch_id" (string), and do not combine with revision.'; 356 | } else if (firstPath?.includes('revision')) { 357 | guidance = 358 | 'When revising, set is_revision=true and provide revises_thought (positive number). Do not combine with branching.'; 359 | } 360 | } else if (errorMessage.includes('length')) { 361 | guidance = `The thought is too long. Keep it under ${MAX_THOUGHT_LENGTH} characters.`; 362 | } else if (errorMessage.includes('Max thought_number exceeded')) { 363 | guidance = `The maximum thought limit (${MAX_THOUGHTS}) was reached.`; 364 | } 365 | 366 | const payload = { 367 | status: 'failed', 368 | error: errorMessage, 369 | guidance, 370 | example, 371 | }; 372 | 373 | return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }], isError: true }; 374 | }; 375 | 376 | const enforceCrossFieldRules = (data: ThoughtData): ValidatedThoughtData => { 377 | if (data.is_revision) { 378 | if (typeof data.revises_thought !== 'number' || data.branch_id || data.branch_from_thought) { 379 | throw new Error('If is_revision=true, provide revises_thought and omit branch_* fields.'); 380 | } 381 | } else if (data.revises_thought !== undefined) { 382 | throw new Error('revises_thought only allowed when is_revision=true.'); 383 | } 384 | 385 | const hasBranchFields = data.branch_id !== undefined || data.branch_from_thought !== undefined; 386 | if (hasBranchFields) { 387 | if ( 388 | data.branch_id === undefined || 389 | data.branch_from_thought === undefined || 390 | data.is_revision 391 | ) { 392 | throw new Error('branch_id and branch_from_thought required together and not with revision.'); 393 | } 394 | } 395 | 396 | return data; 397 | }; 398 | 399 | const createThoughtProcessor = (cfg: Readonly, logger: ServerLogger) => { 400 | const tracker = createThoughtTracker(); 401 | logger.info('Code-Reasoning logic ready', { config: cfg }); 402 | 403 | return async (input: ParsedThoughtData): Promise => { 404 | const t0 = performance.now(); 405 | 406 | try { 407 | const parsed = StrictThoughtSchema.parse(input); 408 | const data = enforceCrossFieldRules(parsed); 409 | 410 | if (data.thought_number > MAX_THOUGHTS) { 411 | throw new Error(`Max thought_number exceeded (${MAX_THOUGHTS}).`); 412 | } 413 | 414 | tracker.ensureBranchIsValid(data.branch_from_thought); 415 | tracker.add(data); 416 | 417 | logger.info(formatThought(data)); 418 | logger.debug('Thought metrics', { 419 | num: data.thought_number, 420 | elapsedMs: +(performance.now() - t0).toFixed(1), 421 | }); 422 | 423 | return buildSuccess(data, tracker); 424 | } catch (err) { 425 | const e = err as Error; 426 | logger.error('Thought processing failed', { 427 | error: e.message, 428 | elapsedMs: +(performance.now() - t0).toFixed(1), 429 | }); 430 | return buildError(e, cfg.debug, logger); 431 | } 432 | }; 433 | }; 434 | 435 | /* -------------------------------------------------------------------------- */ 436 | /* BOOTSTRAP */ 437 | /* -------------------------------------------------------------------------- */ 438 | 439 | export async function runServer(debugFlag = false): Promise { 440 | const config = createConfig(debugFlag ? { debug: true } : undefined); 441 | 442 | const serverMeta = { name: 'code-reasoning-server', version: '0.7.0' } as const; 443 | 444 | const capabilityOptions: Record = { 445 | logging: {}, 446 | completions: {}, 447 | }; 448 | if (config.promptsEnabled) { 449 | capabilityOptions.prompts = {}; 450 | } 451 | 452 | const mcp = new McpServer(serverMeta, { capabilities: capabilityOptions }); 453 | const logger = createServerLogger(mcp, config.debug); 454 | const processThought = createThoughtProcessor(config, logger); 455 | logger.info('Server initialized', { 456 | version: serverMeta.version, 457 | promptsEnabled: config.promptsEnabled, 458 | }); 459 | 460 | // Register tool with MCP helper APIs 461 | const toolDefinition = createCodeReasoningToolDefinition(serverMeta.version); 462 | mcp.registerTool( 463 | TOOL_NAME, 464 | { 465 | title: toolDefinition.title, 466 | description: toolDefinition.description, 467 | annotations: toolDefinition.annotations, 468 | _meta: toolDefinition._meta, 469 | inputSchema: ThoughtDataInputShape, 470 | }, 471 | async args => processThought(args) 472 | ); 473 | 474 | // Initialize prompt manager if enabled 475 | let promptManager: PromptManager | undefined; 476 | if (config.promptsEnabled) { 477 | promptManager = new PromptManager(CONFIG_DIR); 478 | logger.info('Prompts capability enabled'); 479 | 480 | // Add prompt handlers 481 | mcp.server.setRequestHandler(ListPromptsRequestSchema, async () => { 482 | const prompts = promptManager?.getAllPrompts() || []; 483 | logger.debug('Returning prompts', { total: prompts.length }); 484 | return { prompts }; 485 | }); 486 | 487 | mcp.server.setRequestHandler(GetPromptRequestSchema, async req => { 488 | try { 489 | if (!promptManager) { 490 | throw new Error('Prompt manager not initialized'); 491 | } 492 | 493 | const promptName = req.params.name; 494 | const args = req.params.arguments || {}; 495 | 496 | logger.debug('Getting prompt', { promptName, args }); 497 | 498 | // Get the prompt result 499 | const result = promptManager.applyPrompt(promptName, args); 500 | 501 | // Return the result in the format expected by MCP 502 | return { 503 | messages: result.messages, 504 | _meta: { 505 | prompt_name: promptName, 506 | applied_arguments: Object.keys(args), 507 | server_version: serverMeta.version, 508 | }, 509 | }; 510 | } catch (err) { 511 | const e = err as Error; 512 | logger.error('Prompt error', { message: e.message }); 513 | return { 514 | isError: true, 515 | content: [{ type: 'text', text: e.message }], 516 | }; 517 | } 518 | }); 519 | 520 | // Add handler for completion/complete requests 521 | mcp.server.setRequestHandler(CompleteRequestSchema, async req => { 522 | try { 523 | if (!promptManager) { 524 | throw new Error('Prompt manager not initialized'); 525 | } 526 | 527 | // Check if this is a prompt reference 528 | if (req.params.ref.type !== 'ref/prompt') { 529 | return { 530 | completion: { 531 | values: [], 532 | }, 533 | }; 534 | } 535 | 536 | const promptName = req.params.ref.name; 537 | const argName = req.params.argument.name; 538 | 539 | logger.debug('Completing prompt argument', { promptName, argument: argName }); 540 | 541 | // Get stored values for this prompt using the public method 542 | const storedValues = promptManager.getStoredValues(promptName); 543 | 544 | // Return the stored value for this argument if available 545 | if (storedValues[argName]) { 546 | return { 547 | completion: { 548 | values: [storedValues[argName]], 549 | }, 550 | }; 551 | } 552 | 553 | // Return empty array if no stored value 554 | return { 555 | completion: { 556 | values: [], 557 | }, 558 | }; 559 | } catch (err) { 560 | const e = err as Error; 561 | logger.error('Completion error', { message: e.message }); 562 | return { 563 | completion: { 564 | values: [], 565 | }, 566 | }; 567 | } 568 | }); 569 | } else { 570 | // Keep the empty handlers if prompts disabled 571 | mcp.server.setRequestHandler(ListPromptsRequestSchema, async () => ({ prompts: [] })); 572 | 573 | // Add empty handler for completion requests as well when prompts are disabled 574 | mcp.server.setRequestHandler(CompleteRequestSchema, async () => ({ 575 | completion: { 576 | values: [], 577 | }, 578 | })); 579 | } 580 | 581 | const transport = new StdioServerTransport(); 582 | await mcp.connect(transport); 583 | logger.enableRemoteLogging(); 584 | logger.notice('🚀 Code-Reasoning MCP Server ready.'); 585 | 586 | const shutdown = async (signal_name: string, exit_code = 0) => { 587 | logger.info('Shutdown signal received', { signal: signal_name, exit_code }); 588 | 589 | try { 590 | await mcp.close(); 591 | } catch (close_error) { 592 | const error = close_error as Error; 593 | logger.error('Error closing MCP server', { message: error.message }); 594 | } 595 | 596 | try { 597 | await transport.close(); 598 | } catch (close_error) { 599 | const error = close_error as Error; 600 | logger.error('Error closing transport', { message: error.message }); 601 | } 602 | 603 | process.exit(exit_code); 604 | }; 605 | 606 | ['SIGINT', 'SIGTERM'].forEach(signal_name => { 607 | process.on(signal_name, () => { 608 | void shutdown(signal_name); 609 | }); 610 | }); 611 | 612 | process.on('uncaughtException', uncaught_error => { 613 | const error = uncaught_error as Error; 614 | logger.error('💥 uncaught exception', { message: error.message, stack: error.stack }); 615 | void shutdown('uncaughtException', 1); 616 | }); 617 | 618 | process.on('unhandledRejection', rejection_reason => { 619 | logger.error('💥 unhandledPromiseRejection', { reason: rejection_reason }); 620 | void shutdown('unhandledRejection', 1); 621 | }); 622 | } 623 | 624 | // Self-execute when run directly ------------------------------------------------ 625 | if (import.meta.url === `file://${process.argv[1]}`) { 626 | runServer(process.argv.includes('--debug')).catch(err => { 627 | console.error('FATAL: failed to start', err); 628 | process.exit(1); 629 | }); 630 | } 631 | --------------------------------------------------------------------------------