├── .gitignore ├── README.md ├── docs ├── README.md └── clinerules.md ├── logo.png ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── src └── index.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | *.log 4 | .env* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cline Memory Bank 2 | 3 | Inspired by [roo-code-memory-bank](https://github.com/GreatScottyMac/roo-code-memory-bank) 4 | 5 | This project is **still in development** but is mostly working. 6 | 7 | A Model Context Protocol server that provides persistent project context management for AI-assisted development - specifically designed to work with [Cline VSCode Extenson](https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev). 8 | 9 | ## Table of Contents 10 | 11 | - [Overview](#overview) 12 | - [Installation](#installation) 13 | - [Prerequisites](#prerequisites) 14 | - [Setup Steps](#setup-steps) 15 | - [Features](#features) 16 | - [Tools](#tools) 17 | - [Resources](#resources) 18 | - [System Prompt for Cline](#system-prompt-suggestion) 19 | - [File Structure](#file-structure) 20 | - [Using With Cline](#using-with-cline) 21 | - [Development](#development) 22 | - [Contributing](#contributing) 23 | - [License](#license) 24 | 25 | ## Overview 26 | 27 | The Memory Bank MCP server helps maintain consistent project context across development sessions by providing structured tools and resources for managing: 28 | 29 | - Project context and technical details 30 | - Current session state and tasks 31 | - Progress tracking and milestones 32 | - Technical decisions and rationale 33 | 34 | ```mermaid 35 | graph LR 36 | VSCode[VS Code + Cline] --> MemBank[Memory Bank Server] 37 | MemBank --> Files[Markdown Files] 38 | Files --> Context[Project Context] 39 | Files --> Progress[Progress Tracking] 40 | Files --> Decisions[Decision Log] 41 | AI[AI Assistant] --> Files 42 | VSCode --> AI 43 | AI --> MemBank 44 | ``` 45 | 46 | ## Persistent Memory System 47 | 48 | One of the most powerful features of this project is its ability to maintain context across different coding sessions. Think of it as giving your AI assistant a "memory" that doesn't forget what you've been working on, even when you close VSCode and come back later. 49 | 50 | ### How It Works 51 | 52 | Imagine you're working on a complex project that spans multiple days or weeks. Normally, each time you start a new coding session, you'd need to re-explain your project's context to the AI assistant. With the Memory Bank: 53 | 54 | ```mermaid 55 | graph LR 56 | Session[New Session] --> Load[Load Context] 57 | Load --> Read[Read Files] 58 | Read --> Update[Update Context] 59 | Update --> Write[Write Changes] 60 | Write --> Track[Track Progress] 61 | Track --> Record[Record Decisions] 62 | Record --> Ready[Ready for Tasks] 63 | ``` 64 | 65 | - Your AI assistant remembers previous discussions and decisions 66 | - Maintains understanding of your project's architecture and goals 67 | - Keeps track of ongoing tasks and progress 68 | - Remembers your coding preferences and project conventions 69 | 70 | ### Key Benefits 71 | 72 | 1. **Continuity Across Sessions** 73 | - No need to re-explain your project every time 74 | - Pick up exactly where you left off 75 | - Maintains consistent understanding of your codebase 76 | 77 | 2. **Smart Context Management** 78 | - Automatically tracks important technical decisions 79 | - Records project progress and milestones 80 | - Maintains documentation of your development journey 81 | 82 | 3. **Enhanced Productivity** 83 | - Faster project onboarding for each session 84 | - More consistent and contextual AI assistance 85 | - Reduces repetitive explanations 86 | 87 | 4. **Project History** 88 | - Keeps track of why certain decisions were made 89 | - Maintains a log of completed features and changes 90 | - Helps new team members understand project evolution 91 | 92 | The Memory Bank seamlessly integrates with the Cline VSCode Extension, requiring no additional setup from you once configured. It works quietly in the background, ensuring your AI assistant always has the context it needs to provide relevant and helpful assistance. 93 | 94 | ## Installation 95 | 96 | ### Prerequisites 97 | 98 | - Node.js (v16 or later) 99 | - VS Code with Cline extension installed 100 | - TypeScript (for development) 101 | 102 | ### Setup Steps 103 | 104 | 1. Clone and build the server: 105 | ```bash 106 | # Clone the repository 107 | git clone https://github.com/dazeb/cline-mcp-memory-bank 108 | cd cline-mcp-memory-bank 109 | 110 | # Install dependencies (using pnpm as recommended) 111 | pnpm install 112 | 113 | # Build the server 114 | pnpm run build 115 | 116 | # Make globally available (optional, requires pnpm setup for global linking) 117 | # pnpm link --global 118 | ``` 119 | 120 | 2. Configure Cline Extension (Recommended: Use Initialization Command): 121 | 122 | **Recommended Method:** After building, run the initialization command from the project root. This automatically creates the memory bank files and configures the Cline MCP settings for you: 123 | ```bash 124 | node build/index.js initialize_memory_bank . 125 | ``` 126 | 127 | **Manual Method (If needed):** Add the following to your Cline MCP settings file. The path varies by OS: 128 | - **Linux:** `~/.config/Code - Insiders/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json` 129 | - **macOS:** `~/Library/Application Support/Code - Insiders/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json` 130 | - **Windows:** `%APPDATA%\Code - Insiders\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json` 131 | 132 | Add this JSON object: 133 | 134 | ```json 135 | { 136 | "mcpServers": { 137 | "memory-bank": { 138 | "command": "node", 139 | "args": [ 140 | "/path/to/cline-memory-bank/build/index.js" 141 | ], 142 | "disabled": false, 143 | "autoApprove": [] 144 | } 145 | } 146 | } 147 | ``` 148 | 149 | Replace `/path/to/cline-memory-bank` with the actual, absolute path to your server installation (e.g., `C:\Users\YourUser\Projects\cline-mcp-memory-bank` on Windows). **Note:** Using the initialization command above handles this automatically. 150 | 151 | ## Features 152 | 153 | ### Tools 154 | 155 | After installation and building, initialize the memory bank for your project by running this command in the project's root directory: 156 | ```bash 157 | node /path/to/cline-mcp-memory-bank/build/index.js initialize_memory_bank . 158 | ``` 159 | (Replace `/path/to/cline-mcp-memory-bank` with the actual path where you cloned and built the server). 160 | 161 | Alternatively, if the server is configured in Cline, you can ask Cline to run the tool: `initialize the memory bank`. 162 | 163 | Once initialized, you can ask Cline to update the memory bank context, record decisions, or track progress using the tools below, or configure it via `.clinerules` or the system prompt. 164 | 165 | 1. `initialize_memory_bank` 166 | - Creates Memory Bank structure for a new project 167 | - Creates required markdown files with initial templates 168 | ```typescript 169 | use_mcp_tool('memory-bank', 'initialize_memory_bank', { 170 | projectPath: '/path/to/project' 171 | }); 172 | ``` 173 | 174 | 2. `update_context` 175 | - Updates active context with current session information 176 | - Tracks mode, tasks, and session state 177 | ```typescript 178 | use_mcp_tool('memory-bank', 'update_context', { 179 | projectPath: '/path/to/project', 180 | content: { 181 | currentSession: { 182 | date: '2025-03-13', 183 | mode: 'development', 184 | task: 'Implementing new feature' 185 | } 186 | } 187 | }); 188 | ``` 189 | 190 | 3. `record_decision` 191 | - Records technical decisions with rationale 192 | - Maintains history of architectural choices 193 | ```typescript 194 | use_mcp_tool('memory-bank', 'record_decision', { 195 | projectPath: '/path/to/project', 196 | decision: { 197 | title: 'Authentication System', 198 | description: 'Implementing JWT-based authentication', 199 | rationale: 'Better scalability and stateless operation', 200 | alternatives: [ 201 | 'Session-based auth', 202 | 'OAuth only' 203 | ] 204 | } 205 | }); 206 | ``` 207 | 208 | 4. `track_progress` 209 | - Updates project progress and milestones 210 | - Manages task status and blockers 211 | ```typescript 212 | use_mcp_tool('memory-bank', 'track_progress', { 213 | projectPath: '/path/to/project', 214 | progress: { 215 | completed: ['Setup project', 'Initialize database'], 216 | inProgress: ['Implement auth', 'Create API routes'], 217 | blocked: ['Deploy to production'] 218 | } 219 | }); 220 | ``` 221 | 222 | ### Resources 223 | 224 | 1. `memory://project/context` 225 | - Project overview and technical stack 226 | - Architecture principles and guidelines 227 | 228 | 2. `memory://active/context` 229 | - Current session state and tasks 230 | - Active considerations and notes 231 | 232 | 3. `memory://progress` 233 | - Project milestones and task tracking 234 | - Work status and blockers 235 | 236 | 4. `memory://decisions` 237 | - Technical decisions and rationale 238 | - Architecture choices and alternatives 239 | 240 | ### System Prompt Suggestion 241 | 242 | Add to Cline system prompt or `.clinerules` file under settings. 243 | 244 | ``` 245 | Memory Bank Integration Rules: 246 | 247 | CRITICAL: Before ANY task or response: 248 | 1. ALWAYS check active context (memory://active/context): 249 | - Current project state and mode 250 | - Ongoing tasks and their status 251 | - Recent decisions and updates 252 | - Open questions and concerns 253 | 254 | 2. ALWAYS review project context (memory://project/context): 255 | - Technical stack and dependencies 256 | - Project guidelines and standards 257 | - Architecture principles 258 | - Development workflow 259 | 260 | 3. ALWAYS consult decision log (memory://decisions) for: 261 | - Previous architectural choices 262 | - Established patterns 263 | - Technical rationales 264 | - Related decisions 265 | 266 | 4. ALWAYS check progress tracking (memory://progress): 267 | - Current phase and milestones 268 | - Completed work 269 | - In-progress tasks 270 | - Known blockers 271 | 272 | After EVERY task: 273 | 1. Update active context with: 274 | - Task completion status 275 | - New information learned 276 | - Changes made 277 | 278 | 2. Record any technical decisions with: 279 | - Clear rationale 280 | - Considered alternatives 281 | - Impact assessment 282 | 283 | 3. Update progress tracking: 284 | - Mark completed items 285 | - Add new tasks identified 286 | - Note any blockers found 287 | 288 | Key Guidelines: 289 | - NEVER proceed without checking memory bank context 290 | - ALWAYS maintain consistent project state 291 | - Record ALL significant technical decisions 292 | - Track progress in real-time 293 | - Keep context updated with EVERY change 294 | ``` 295 | ## File Structure 296 | 297 | When initialized, the Memory Bank creates the following structure in your project: 298 | 299 | ```mermaid 300 | graph LR 301 | Root[Project Root] --> Bank[memory-bank] 302 | Bank --> PC[projectContext.md] 303 | Bank --> AC[activeContext.md] 304 | Bank --> P[progress.md] 305 | Bank --> DL[decisionLog.md] 306 | PC --> Stack[Technical Stack] 307 | AC --> Tasks[Active Tasks] 308 | P --> Status[Project Status] 309 | DL --> History[Decision History] 310 | ``` 311 | 312 | ### Initial File Contents 313 | 314 | Upon initialization, each file is populated with structured content: 315 | 316 | 1. `activeContext.md`: 317 | - Current session information with timestamp 318 | - Initial tasks (Project initialization, Environment setup) 319 | - Open questions about project goals and requirements 320 | - Recent updates section 321 | 322 | 2. `progress.md`: 323 | - Current phase (Initialization) 324 | - Initial completed tasks (Repository setup, Basic structure) 325 | - In-progress tasks (Environment configuration, Documentation) 326 | - Upcoming tasks section 327 | - Blockers tracking 328 | 329 | 3. `decisionLog.md`: 330 | - Initial project structure decisions 331 | - Development workflow choices with alternatives 332 | - Documentation strategy decisions 333 | - Section for pending decisions 334 | 335 | 4. `projectContext.md`: 336 | - Project overview and version 337 | - Detected technical stack and dependencies 338 | - Configuration files listing 339 | - Architecture principles 340 | - Development setup instructions 341 | - Project workflow guidelines 342 | 343 | ## Using with Cline 344 | 345 | ```mermaid 346 | graph LR 347 | Start[Start] --> Init[Initialize] 348 | Init --> Context[Load Context] 349 | Context --> Update[Make Changes] 350 | Update --> Progress[Track Progress] 351 | Progress --> Record[Record Decisions] 352 | Record --> Sync[Auto Sync] 353 | Sync --> Context 354 | ``` 355 | 356 | Simply ask Cline to initialize the memory bank. 357 | 358 | 1. Initialize a new Memory Bank: 359 | ``` 360 | use_mcp_tool('memory-bank', 'initialize_memory_bank', { 361 | projectPath: process.cwd() // or specific path 362 | }); 363 | ``` 364 | 365 | 2. Access project context: 366 | ``` 367 | access_mcp_resource('memory-bank', 'memory://project/context'); 368 | ``` 369 | 370 | 3. Update session context: 371 | ``` 372 | use_mcp_tool('memory-bank', 'update_context', { 373 | projectPath: process.cwd(), 374 | content: { 375 | currentSession: { 376 | date: new Date().toISOString().split('T')[0], 377 | mode: 'development', 378 | task: 'Current task description' 379 | } 380 | } 381 | }); 382 | ``` 383 | 384 | 4. Record technical decisions: 385 | ``` 386 | use_mcp_tool('memory-bank', 'record_decision', { 387 | projectPath: process.cwd(), 388 | decision: { 389 | title: 'Decision Title', 390 | description: 'What was decided', 391 | rationale: 'Why it was decided' 392 | } 393 | }); 394 | ``` 395 | 396 | ## Development 397 | 398 | To modify or enhance the server: 399 | 400 | 1. Update source in `src/index.ts` 401 | 2. Run tests: `npm test` 402 | 3. Build: `npm run build` 403 | 4. Restart Cline extension to load changes 404 | 405 | ## Contributing 406 | 407 | Contributions are welcome! Please: 408 | 409 | 1. Fork the repository 410 | 2. Create a feature branch 411 | 3. Make your changes 412 | 4. Submit a pull request 413 | 414 | ## License 415 | 416 | MIT © dazeb 417 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | Add the contents of `.clinerules` to your system prompt of choice. 2 | 3 | You can add it to your codebase as a `.clinerules` file or to your system prompt within Cline. -------------------------------------------------------------------------------- /docs/clinerules.md: -------------------------------------------------------------------------------- 1 | Memory Bank Integration Rules: 2 | 3 | CRITICAL: Before ANY task or response: 4 | 1. ALWAYS check active context (memory://active/context): 5 | - Current project state and mode 6 | - Ongoing tasks and their status 7 | - Recent decisions and updates 8 | - Open questions and concerns 9 | 10 | 2. ALWAYS review project context (memory://project/context): 11 | - Technical stack and dependencies 12 | - Project guidelines and standards 13 | - Architecture principles 14 | - Development workflow 15 | 16 | 3. ALWAYS consult decision log (memory://decisions) for: 17 | - Previous architectural choices 18 | - Established patterns 19 | - Technical rationales 20 | - Related decisions 21 | 22 | 4. ALWAYS check progress tracking (memory://progress): 23 | - Current phase and milestones 24 | - Completed work 25 | - In-progress tasks 26 | - Known blockers 27 | 28 | After EVERY task: 29 | 1. Update active context with: 30 | - Task completion status 31 | - New information learned 32 | - Changes made 33 | 34 | 2. Record any technical decisions with: 35 | - Clear rationale 36 | - Considered alternatives 37 | - Impact assessment 38 | 39 | 3. Update progress tracking: 40 | - Mark completed items 41 | - Add new tasks identified 42 | - Note any blockers found 43 | 44 | Key Guidelines: 45 | - NEVER proceed without checking memory bank context 46 | - ALWAYS maintain consistent project state 47 | - Record ALL significant technical decisions 48 | - Track progress in real-time 49 | - Keep context updated with EVERY change -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dazeb/cline-mcp-memory-bank/c956fa692523e8a609407b3fbed4ba1a74a5d7e2/logo.png -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "memory-bank-server", 3 | "version": "0.1.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "memory-bank-server", 9 | "version": "0.1.0", 10 | "dependencies": { 11 | "@modelcontextprotocol/sdk": "0.6.0" 12 | }, 13 | "bin": { 14 | "memory-bank-server": "build/index.js" 15 | }, 16 | "devDependencies": { 17 | "@types/node": "^20.11.24", 18 | "typescript": "^5.3.3" 19 | } 20 | }, 21 | "node_modules/@modelcontextprotocol/sdk": { 22 | "version": "0.6.0", 23 | "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-0.6.0.tgz", 24 | "integrity": "sha512-9rsDudGhDtMbvxohPoMMyAUOmEzQsOK+XFchh6gZGqo8sx9sBuZQs+CUttXqa8RZXKDaJRCN2tUtgGof7jRkkw==", 25 | "license": "MIT", 26 | "dependencies": { 27 | "content-type": "^1.0.5", 28 | "raw-body": "^3.0.0", 29 | "zod": "^3.23.8" 30 | } 31 | }, 32 | "node_modules/@types/node": { 33 | "version": "20.17.24", 34 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.24.tgz", 35 | "integrity": "sha512-d7fGCyB96w9BnWQrOsJtpyiSaBcAYYr75bnK6ZRjDbql2cGLj/3GsL5OYmLPNq76l7Gf2q4Rv9J2o6h5CrD9sA==", 36 | "dev": true, 37 | "license": "MIT", 38 | "dependencies": { 39 | "undici-types": "~6.19.2" 40 | } 41 | }, 42 | "node_modules/bytes": { 43 | "version": "3.1.2", 44 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 45 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 46 | "license": "MIT", 47 | "engines": { 48 | "node": ">= 0.8" 49 | } 50 | }, 51 | "node_modules/content-type": { 52 | "version": "1.0.5", 53 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 54 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 55 | "license": "MIT", 56 | "engines": { 57 | "node": ">= 0.6" 58 | } 59 | }, 60 | "node_modules/depd": { 61 | "version": "2.0.0", 62 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 63 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 64 | "license": "MIT", 65 | "engines": { 66 | "node": ">= 0.8" 67 | } 68 | }, 69 | "node_modules/http-errors": { 70 | "version": "2.0.0", 71 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 72 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 73 | "license": "MIT", 74 | "dependencies": { 75 | "depd": "2.0.0", 76 | "inherits": "2.0.4", 77 | "setprototypeof": "1.2.0", 78 | "statuses": "2.0.1", 79 | "toidentifier": "1.0.1" 80 | }, 81 | "engines": { 82 | "node": ">= 0.8" 83 | } 84 | }, 85 | "node_modules/iconv-lite": { 86 | "version": "0.6.3", 87 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", 88 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", 89 | "license": "MIT", 90 | "dependencies": { 91 | "safer-buffer": ">= 2.1.2 < 3.0.0" 92 | }, 93 | "engines": { 94 | "node": ">=0.10.0" 95 | } 96 | }, 97 | "node_modules/inherits": { 98 | "version": "2.0.4", 99 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 100 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 101 | "license": "ISC" 102 | }, 103 | "node_modules/raw-body": { 104 | "version": "3.0.0", 105 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", 106 | "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", 107 | "license": "MIT", 108 | "dependencies": { 109 | "bytes": "3.1.2", 110 | "http-errors": "2.0.0", 111 | "iconv-lite": "0.6.3", 112 | "unpipe": "1.0.0" 113 | }, 114 | "engines": { 115 | "node": ">= 0.8" 116 | } 117 | }, 118 | "node_modules/safer-buffer": { 119 | "version": "2.1.2", 120 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 121 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 122 | "license": "MIT" 123 | }, 124 | "node_modules/setprototypeof": { 125 | "version": "1.2.0", 126 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 127 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", 128 | "license": "ISC" 129 | }, 130 | "node_modules/statuses": { 131 | "version": "2.0.1", 132 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 133 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 134 | "license": "MIT", 135 | "engines": { 136 | "node": ">= 0.8" 137 | } 138 | }, 139 | "node_modules/toidentifier": { 140 | "version": "1.0.1", 141 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 142 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 143 | "license": "MIT", 144 | "engines": { 145 | "node": ">=0.6" 146 | } 147 | }, 148 | "node_modules/typescript": { 149 | "version": "5.8.2", 150 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", 151 | "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", 152 | "dev": true, 153 | "license": "Apache-2.0", 154 | "bin": { 155 | "tsc": "bin/tsc", 156 | "tsserver": "bin/tsserver" 157 | }, 158 | "engines": { 159 | "node": ">=14.17" 160 | } 161 | }, 162 | "node_modules/undici-types": { 163 | "version": "6.19.8", 164 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", 165 | "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", 166 | "dev": true, 167 | "license": "MIT" 168 | }, 169 | "node_modules/unpipe": { 170 | "version": "1.0.0", 171 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 172 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 173 | "license": "MIT", 174 | "engines": { 175 | "node": ">= 0.8" 176 | } 177 | }, 178 | "node_modules/zod": { 179 | "version": "3.24.2", 180 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", 181 | "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", 182 | "license": "MIT", 183 | "funding": { 184 | "url": "https://github.com/sponsors/colinhacks" 185 | } 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "memory-bank-server", 3 | "version": "0.1.0", 4 | "description": "MCP server for persistent project context management", 5 | "type": "module", 6 | "main": "build/index.js", 7 | "bin": { 8 | "memory-bank-server": "./build/index.js" 9 | }, 10 | "scripts": { 11 | "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"", 12 | "watch": "tsc -w", 13 | "clean": "rm -rf build", 14 | "prepare": "npm run build" 15 | }, 16 | "keywords": [ 17 | "mcp", 18 | "model-context-protocol", 19 | "project-management", 20 | "context-management", 21 | "ai-development", 22 | "cline" 23 | ], 24 | "author": "", 25 | "license": "MIT", 26 | "dependencies": { 27 | "@modelcontextprotocol/sdk": "^1.8.0" 28 | }, 29 | "devDependencies": { 30 | "@types/node": "^20.17.30", 31 | "typescript": "^5.0.0" 32 | }, 33 | "repository": { 34 | "type": "git", 35 | "url": "https://github.com/your-username/memory-bank-server" 36 | }, 37 | "engines": { 38 | "node": ">=16" 39 | }, 40 | "packageManager": "pnpm@10.3.0+sha512.ee592eda8815a8a293c206bb0917c4bb0ff274c50def7cbc17be05ec641fc2d1b02490ce660061356bd0d126a4d7eb2ec8830e6959fb8a447571c631d5a2442d" 41 | } 42 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | '@modelcontextprotocol/sdk': 12 | specifier: ^1.8.0 13 | version: 1.8.0 14 | devDependencies: 15 | '@types/node': 16 | specifier: ^20.17.30 17 | version: 20.17.30 18 | typescript: 19 | specifier: ^5.0.0 20 | version: 5.8.2 21 | 22 | packages: 23 | 24 | '@modelcontextprotocol/sdk@1.8.0': 25 | resolution: {integrity: sha512-e06W7SwrontJDHwCawNO5SGxG+nU9AAx+jpHHZqGl/WrDBdWOpvirC+s58VpJTB5QemI4jTRcjWT4Pt3Q1NPQQ==} 26 | engines: {node: '>=18'} 27 | 28 | '@types/node@20.17.30': 29 | resolution: {integrity: sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg==} 30 | 31 | accepts@2.0.0: 32 | resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} 33 | engines: {node: '>= 0.6'} 34 | 35 | body-parser@2.2.0: 36 | resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} 37 | engines: {node: '>=18'} 38 | 39 | bytes@3.1.2: 40 | resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} 41 | engines: {node: '>= 0.8'} 42 | 43 | call-bind-apply-helpers@1.0.2: 44 | resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} 45 | engines: {node: '>= 0.4'} 46 | 47 | call-bound@1.0.4: 48 | resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} 49 | engines: {node: '>= 0.4'} 50 | 51 | content-disposition@1.0.0: 52 | resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} 53 | engines: {node: '>= 0.6'} 54 | 55 | content-type@1.0.5: 56 | resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} 57 | engines: {node: '>= 0.6'} 58 | 59 | cookie-signature@1.2.2: 60 | resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} 61 | engines: {node: '>=6.6.0'} 62 | 63 | cookie@0.7.2: 64 | resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} 65 | engines: {node: '>= 0.6'} 66 | 67 | cors@2.8.5: 68 | resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} 69 | engines: {node: '>= 0.10'} 70 | 71 | cross-spawn@7.0.6: 72 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 73 | engines: {node: '>= 8'} 74 | 75 | debug@4.4.0: 76 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} 77 | engines: {node: '>=6.0'} 78 | peerDependencies: 79 | supports-color: '*' 80 | peerDependenciesMeta: 81 | supports-color: 82 | optional: true 83 | 84 | depd@2.0.0: 85 | resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} 86 | engines: {node: '>= 0.8'} 87 | 88 | dunder-proto@1.0.1: 89 | resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} 90 | engines: {node: '>= 0.4'} 91 | 92 | ee-first@1.1.1: 93 | resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} 94 | 95 | encodeurl@2.0.0: 96 | resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} 97 | engines: {node: '>= 0.8'} 98 | 99 | es-define-property@1.0.1: 100 | resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} 101 | engines: {node: '>= 0.4'} 102 | 103 | es-errors@1.3.0: 104 | resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} 105 | engines: {node: '>= 0.4'} 106 | 107 | es-object-atoms@1.1.1: 108 | resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} 109 | engines: {node: '>= 0.4'} 110 | 111 | escape-html@1.0.3: 112 | resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} 113 | 114 | etag@1.8.1: 115 | resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} 116 | engines: {node: '>= 0.6'} 117 | 118 | eventsource-parser@3.0.1: 119 | resolution: {integrity: sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==} 120 | engines: {node: '>=18.0.0'} 121 | 122 | eventsource@3.0.6: 123 | resolution: {integrity: sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==} 124 | engines: {node: '>=18.0.0'} 125 | 126 | express-rate-limit@7.5.0: 127 | resolution: {integrity: sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==} 128 | engines: {node: '>= 16'} 129 | peerDependencies: 130 | express: ^4.11 || 5 || ^5.0.0-beta.1 131 | 132 | express@5.1.0: 133 | resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} 134 | engines: {node: '>= 18'} 135 | 136 | finalhandler@2.1.0: 137 | resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} 138 | engines: {node: '>= 0.8'} 139 | 140 | forwarded@0.2.0: 141 | resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} 142 | engines: {node: '>= 0.6'} 143 | 144 | fresh@2.0.0: 145 | resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} 146 | engines: {node: '>= 0.8'} 147 | 148 | function-bind@1.1.2: 149 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 150 | 151 | get-intrinsic@1.3.0: 152 | resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} 153 | engines: {node: '>= 0.4'} 154 | 155 | get-proto@1.0.1: 156 | resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} 157 | engines: {node: '>= 0.4'} 158 | 159 | gopd@1.2.0: 160 | resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} 161 | engines: {node: '>= 0.4'} 162 | 163 | has-symbols@1.1.0: 164 | resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} 165 | engines: {node: '>= 0.4'} 166 | 167 | hasown@2.0.2: 168 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 169 | engines: {node: '>= 0.4'} 170 | 171 | http-errors@2.0.0: 172 | resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} 173 | engines: {node: '>= 0.8'} 174 | 175 | iconv-lite@0.6.3: 176 | resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} 177 | engines: {node: '>=0.10.0'} 178 | 179 | inherits@2.0.4: 180 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 181 | 182 | ipaddr.js@1.9.1: 183 | resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} 184 | engines: {node: '>= 0.10'} 185 | 186 | is-promise@4.0.0: 187 | resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} 188 | 189 | isexe@2.0.0: 190 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 191 | 192 | math-intrinsics@1.1.0: 193 | resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} 194 | engines: {node: '>= 0.4'} 195 | 196 | media-typer@1.1.0: 197 | resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} 198 | engines: {node: '>= 0.8'} 199 | 200 | merge-descriptors@2.0.0: 201 | resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} 202 | engines: {node: '>=18'} 203 | 204 | mime-db@1.54.0: 205 | resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} 206 | engines: {node: '>= 0.6'} 207 | 208 | mime-types@3.0.1: 209 | resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} 210 | engines: {node: '>= 0.6'} 211 | 212 | ms@2.1.3: 213 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 214 | 215 | negotiator@1.0.0: 216 | resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} 217 | engines: {node: '>= 0.6'} 218 | 219 | object-assign@4.1.1: 220 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 221 | engines: {node: '>=0.10.0'} 222 | 223 | object-inspect@1.13.4: 224 | resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} 225 | engines: {node: '>= 0.4'} 226 | 227 | on-finished@2.4.1: 228 | resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} 229 | engines: {node: '>= 0.8'} 230 | 231 | once@1.4.0: 232 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 233 | 234 | parseurl@1.3.3: 235 | resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} 236 | engines: {node: '>= 0.8'} 237 | 238 | path-key@3.1.1: 239 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 240 | engines: {node: '>=8'} 241 | 242 | path-to-regexp@8.2.0: 243 | resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} 244 | engines: {node: '>=16'} 245 | 246 | pkce-challenge@4.1.0: 247 | resolution: {integrity: sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==} 248 | engines: {node: '>=16.20.0'} 249 | 250 | proxy-addr@2.0.7: 251 | resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} 252 | engines: {node: '>= 0.10'} 253 | 254 | qs@6.14.0: 255 | resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} 256 | engines: {node: '>=0.6'} 257 | 258 | range-parser@1.2.1: 259 | resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} 260 | engines: {node: '>= 0.6'} 261 | 262 | raw-body@3.0.0: 263 | resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} 264 | engines: {node: '>= 0.8'} 265 | 266 | router@2.2.0: 267 | resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} 268 | engines: {node: '>= 18'} 269 | 270 | safe-buffer@5.2.1: 271 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 272 | 273 | safer-buffer@2.1.2: 274 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 275 | 276 | send@1.2.0: 277 | resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} 278 | engines: {node: '>= 18'} 279 | 280 | serve-static@2.2.0: 281 | resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} 282 | engines: {node: '>= 18'} 283 | 284 | setprototypeof@1.2.0: 285 | resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} 286 | 287 | shebang-command@2.0.0: 288 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 289 | engines: {node: '>=8'} 290 | 291 | shebang-regex@3.0.0: 292 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 293 | engines: {node: '>=8'} 294 | 295 | side-channel-list@1.0.0: 296 | resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} 297 | engines: {node: '>= 0.4'} 298 | 299 | side-channel-map@1.0.1: 300 | resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} 301 | engines: {node: '>= 0.4'} 302 | 303 | side-channel-weakmap@1.0.2: 304 | resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} 305 | engines: {node: '>= 0.4'} 306 | 307 | side-channel@1.1.0: 308 | resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} 309 | engines: {node: '>= 0.4'} 310 | 311 | statuses@2.0.1: 312 | resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} 313 | engines: {node: '>= 0.8'} 314 | 315 | toidentifier@1.0.1: 316 | resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} 317 | engines: {node: '>=0.6'} 318 | 319 | type-is@2.0.1: 320 | resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} 321 | engines: {node: '>= 0.6'} 322 | 323 | typescript@5.8.2: 324 | resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} 325 | engines: {node: '>=14.17'} 326 | hasBin: true 327 | 328 | undici-types@6.19.8: 329 | resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} 330 | 331 | unpipe@1.0.0: 332 | resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} 333 | engines: {node: '>= 0.8'} 334 | 335 | vary@1.1.2: 336 | resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} 337 | engines: {node: '>= 0.8'} 338 | 339 | which@2.0.2: 340 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 341 | engines: {node: '>= 8'} 342 | hasBin: true 343 | 344 | wrappy@1.0.2: 345 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 346 | 347 | zod-to-json-schema@3.24.5: 348 | resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} 349 | peerDependencies: 350 | zod: ^3.24.1 351 | 352 | zod@3.24.2: 353 | resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==} 354 | 355 | snapshots: 356 | 357 | '@modelcontextprotocol/sdk@1.8.0': 358 | dependencies: 359 | content-type: 1.0.5 360 | cors: 2.8.5 361 | cross-spawn: 7.0.6 362 | eventsource: 3.0.6 363 | express: 5.1.0 364 | express-rate-limit: 7.5.0(express@5.1.0) 365 | pkce-challenge: 4.1.0 366 | raw-body: 3.0.0 367 | zod: 3.24.2 368 | zod-to-json-schema: 3.24.5(zod@3.24.2) 369 | transitivePeerDependencies: 370 | - supports-color 371 | 372 | '@types/node@20.17.30': 373 | dependencies: 374 | undici-types: 6.19.8 375 | 376 | accepts@2.0.0: 377 | dependencies: 378 | mime-types: 3.0.1 379 | negotiator: 1.0.0 380 | 381 | body-parser@2.2.0: 382 | dependencies: 383 | bytes: 3.1.2 384 | content-type: 1.0.5 385 | debug: 4.4.0 386 | http-errors: 2.0.0 387 | iconv-lite: 0.6.3 388 | on-finished: 2.4.1 389 | qs: 6.14.0 390 | raw-body: 3.0.0 391 | type-is: 2.0.1 392 | transitivePeerDependencies: 393 | - supports-color 394 | 395 | bytes@3.1.2: {} 396 | 397 | call-bind-apply-helpers@1.0.2: 398 | dependencies: 399 | es-errors: 1.3.0 400 | function-bind: 1.1.2 401 | 402 | call-bound@1.0.4: 403 | dependencies: 404 | call-bind-apply-helpers: 1.0.2 405 | get-intrinsic: 1.3.0 406 | 407 | content-disposition@1.0.0: 408 | dependencies: 409 | safe-buffer: 5.2.1 410 | 411 | content-type@1.0.5: {} 412 | 413 | cookie-signature@1.2.2: {} 414 | 415 | cookie@0.7.2: {} 416 | 417 | cors@2.8.5: 418 | dependencies: 419 | object-assign: 4.1.1 420 | vary: 1.1.2 421 | 422 | cross-spawn@7.0.6: 423 | dependencies: 424 | path-key: 3.1.1 425 | shebang-command: 2.0.0 426 | which: 2.0.2 427 | 428 | debug@4.4.0: 429 | dependencies: 430 | ms: 2.1.3 431 | 432 | depd@2.0.0: {} 433 | 434 | dunder-proto@1.0.1: 435 | dependencies: 436 | call-bind-apply-helpers: 1.0.2 437 | es-errors: 1.3.0 438 | gopd: 1.2.0 439 | 440 | ee-first@1.1.1: {} 441 | 442 | encodeurl@2.0.0: {} 443 | 444 | es-define-property@1.0.1: {} 445 | 446 | es-errors@1.3.0: {} 447 | 448 | es-object-atoms@1.1.1: 449 | dependencies: 450 | es-errors: 1.3.0 451 | 452 | escape-html@1.0.3: {} 453 | 454 | etag@1.8.1: {} 455 | 456 | eventsource-parser@3.0.1: {} 457 | 458 | eventsource@3.0.6: 459 | dependencies: 460 | eventsource-parser: 3.0.1 461 | 462 | express-rate-limit@7.5.0(express@5.1.0): 463 | dependencies: 464 | express: 5.1.0 465 | 466 | express@5.1.0: 467 | dependencies: 468 | accepts: 2.0.0 469 | body-parser: 2.2.0 470 | content-disposition: 1.0.0 471 | content-type: 1.0.5 472 | cookie: 0.7.2 473 | cookie-signature: 1.2.2 474 | debug: 4.4.0 475 | encodeurl: 2.0.0 476 | escape-html: 1.0.3 477 | etag: 1.8.1 478 | finalhandler: 2.1.0 479 | fresh: 2.0.0 480 | http-errors: 2.0.0 481 | merge-descriptors: 2.0.0 482 | mime-types: 3.0.1 483 | on-finished: 2.4.1 484 | once: 1.4.0 485 | parseurl: 1.3.3 486 | proxy-addr: 2.0.7 487 | qs: 6.14.0 488 | range-parser: 1.2.1 489 | router: 2.2.0 490 | send: 1.2.0 491 | serve-static: 2.2.0 492 | statuses: 2.0.1 493 | type-is: 2.0.1 494 | vary: 1.1.2 495 | transitivePeerDependencies: 496 | - supports-color 497 | 498 | finalhandler@2.1.0: 499 | dependencies: 500 | debug: 4.4.0 501 | encodeurl: 2.0.0 502 | escape-html: 1.0.3 503 | on-finished: 2.4.1 504 | parseurl: 1.3.3 505 | statuses: 2.0.1 506 | transitivePeerDependencies: 507 | - supports-color 508 | 509 | forwarded@0.2.0: {} 510 | 511 | fresh@2.0.0: {} 512 | 513 | function-bind@1.1.2: {} 514 | 515 | get-intrinsic@1.3.0: 516 | dependencies: 517 | call-bind-apply-helpers: 1.0.2 518 | es-define-property: 1.0.1 519 | es-errors: 1.3.0 520 | es-object-atoms: 1.1.1 521 | function-bind: 1.1.2 522 | get-proto: 1.0.1 523 | gopd: 1.2.0 524 | has-symbols: 1.1.0 525 | hasown: 2.0.2 526 | math-intrinsics: 1.1.0 527 | 528 | get-proto@1.0.1: 529 | dependencies: 530 | dunder-proto: 1.0.1 531 | es-object-atoms: 1.1.1 532 | 533 | gopd@1.2.0: {} 534 | 535 | has-symbols@1.1.0: {} 536 | 537 | hasown@2.0.2: 538 | dependencies: 539 | function-bind: 1.1.2 540 | 541 | http-errors@2.0.0: 542 | dependencies: 543 | depd: 2.0.0 544 | inherits: 2.0.4 545 | setprototypeof: 1.2.0 546 | statuses: 2.0.1 547 | toidentifier: 1.0.1 548 | 549 | iconv-lite@0.6.3: 550 | dependencies: 551 | safer-buffer: 2.1.2 552 | 553 | inherits@2.0.4: {} 554 | 555 | ipaddr.js@1.9.1: {} 556 | 557 | is-promise@4.0.0: {} 558 | 559 | isexe@2.0.0: {} 560 | 561 | math-intrinsics@1.1.0: {} 562 | 563 | media-typer@1.1.0: {} 564 | 565 | merge-descriptors@2.0.0: {} 566 | 567 | mime-db@1.54.0: {} 568 | 569 | mime-types@3.0.1: 570 | dependencies: 571 | mime-db: 1.54.0 572 | 573 | ms@2.1.3: {} 574 | 575 | negotiator@1.0.0: {} 576 | 577 | object-assign@4.1.1: {} 578 | 579 | object-inspect@1.13.4: {} 580 | 581 | on-finished@2.4.1: 582 | dependencies: 583 | ee-first: 1.1.1 584 | 585 | once@1.4.0: 586 | dependencies: 587 | wrappy: 1.0.2 588 | 589 | parseurl@1.3.3: {} 590 | 591 | path-key@3.1.1: {} 592 | 593 | path-to-regexp@8.2.0: {} 594 | 595 | pkce-challenge@4.1.0: {} 596 | 597 | proxy-addr@2.0.7: 598 | dependencies: 599 | forwarded: 0.2.0 600 | ipaddr.js: 1.9.1 601 | 602 | qs@6.14.0: 603 | dependencies: 604 | side-channel: 1.1.0 605 | 606 | range-parser@1.2.1: {} 607 | 608 | raw-body@3.0.0: 609 | dependencies: 610 | bytes: 3.1.2 611 | http-errors: 2.0.0 612 | iconv-lite: 0.6.3 613 | unpipe: 1.0.0 614 | 615 | router@2.2.0: 616 | dependencies: 617 | debug: 4.4.0 618 | depd: 2.0.0 619 | is-promise: 4.0.0 620 | parseurl: 1.3.3 621 | path-to-regexp: 8.2.0 622 | transitivePeerDependencies: 623 | - supports-color 624 | 625 | safe-buffer@5.2.1: {} 626 | 627 | safer-buffer@2.1.2: {} 628 | 629 | send@1.2.0: 630 | dependencies: 631 | debug: 4.4.0 632 | encodeurl: 2.0.0 633 | escape-html: 1.0.3 634 | etag: 1.8.1 635 | fresh: 2.0.0 636 | http-errors: 2.0.0 637 | mime-types: 3.0.1 638 | ms: 2.1.3 639 | on-finished: 2.4.1 640 | range-parser: 1.2.1 641 | statuses: 2.0.1 642 | transitivePeerDependencies: 643 | - supports-color 644 | 645 | serve-static@2.2.0: 646 | dependencies: 647 | encodeurl: 2.0.0 648 | escape-html: 1.0.3 649 | parseurl: 1.3.3 650 | send: 1.2.0 651 | transitivePeerDependencies: 652 | - supports-color 653 | 654 | setprototypeof@1.2.0: {} 655 | 656 | shebang-command@2.0.0: 657 | dependencies: 658 | shebang-regex: 3.0.0 659 | 660 | shebang-regex@3.0.0: {} 661 | 662 | side-channel-list@1.0.0: 663 | dependencies: 664 | es-errors: 1.3.0 665 | object-inspect: 1.13.4 666 | 667 | side-channel-map@1.0.1: 668 | dependencies: 669 | call-bound: 1.0.4 670 | es-errors: 1.3.0 671 | get-intrinsic: 1.3.0 672 | object-inspect: 1.13.4 673 | 674 | side-channel-weakmap@1.0.2: 675 | dependencies: 676 | call-bound: 1.0.4 677 | es-errors: 1.3.0 678 | get-intrinsic: 1.3.0 679 | object-inspect: 1.13.4 680 | side-channel-map: 1.0.1 681 | 682 | side-channel@1.1.0: 683 | dependencies: 684 | es-errors: 1.3.0 685 | object-inspect: 1.13.4 686 | side-channel-list: 1.0.0 687 | side-channel-map: 1.0.1 688 | side-channel-weakmap: 1.0.2 689 | 690 | statuses@2.0.1: {} 691 | 692 | toidentifier@1.0.1: {} 693 | 694 | type-is@2.0.1: 695 | dependencies: 696 | content-type: 1.0.5 697 | media-typer: 1.1.0 698 | mime-types: 3.0.1 699 | 700 | typescript@5.8.2: {} 701 | 702 | undici-types@6.19.8: {} 703 | 704 | unpipe@1.0.0: {} 705 | 706 | vary@1.1.2: {} 707 | 708 | which@2.0.2: 709 | dependencies: 710 | isexe: 2.0.0 711 | 712 | wrappy@1.0.2: {} 713 | 714 | zod-to-json-schema@3.24.5(zod@3.24.2): 715 | dependencies: 716 | zod: 3.24.2 717 | 718 | zod@3.24.2: {} 719 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { Server } from '@modelcontextprotocol/sdk/server/index.js'; 3 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; 4 | import { 5 | CallToolRequestSchema, 6 | ErrorCode, 7 | ListResourcesRequestSchema, 8 | ListToolsRequestSchema, 9 | McpError, 10 | ReadResourceRequestSchema, 11 | } from '@modelcontextprotocol/sdk/types.js'; 12 | import fs from 'fs/promises'; 13 | import os from 'os'; 14 | import path from 'path'; 15 | 16 | interface MemoryBankFile { 17 | path: string; 18 | content: string; 19 | } 20 | 21 | interface ProjectInfo { 22 | name: string; 23 | version: string; 24 | description: string; 25 | license: string; 26 | dependencies: string[]; 27 | devDependencies: string[]; 28 | } 29 | 30 | interface Decision { 31 | title: string; 32 | description: string; 33 | rationale: string; 34 | alternatives?: string[]; 35 | date?: string; 36 | status: 'proposed' | 'accepted' | 'rejected' | 'superseded'; 37 | impact?: string; 38 | relatedDecisions?: string[]; 39 | } 40 | 41 | interface TechStack { 42 | runtime: string; 43 | frameworks: string[]; 44 | languages: Set; 45 | configs: string[]; 46 | } 47 | 48 | interface SessionState { 49 | questionCount: number; 50 | lastPrompted: string; 51 | currentPhase: string; 52 | taskUpdates: { 53 | completed: Set; 54 | inProgress: Set; 55 | blocked: Set; 56 | }; 57 | } 58 | 59 | interface McpSettings { 60 | mcpServers: { 61 | [key: string]: { 62 | command: string; 63 | args: string[]; 64 | env?: { [key: string]: string }; 65 | disabled?: boolean; 66 | autoApprove?: string[]; 67 | }; 68 | }; 69 | } 70 | 71 | class MemoryBankServer { 72 | private sessionState: SessionState; 73 | private server: Server; 74 | private memoryBankPath: string; 75 | private static readonly MCP_SETTINGS_PATHS = { 76 | linux: '.config/Code - Insiders/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json', 77 | darwin: 'Library/Application Support/Code - Insiders/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json', 78 | win32: 'AppData/Roaming/Code - Insiders/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json' 79 | }; 80 | 81 | constructor() { 82 | this.sessionState = { 83 | questionCount: 0, 84 | lastPrompted: new Date().toISOString().split('T')[0], 85 | currentPhase: 'Development', 86 | taskUpdates: { 87 | completed: new Set(), 88 | inProgress: new Set(), 89 | blocked: new Set() 90 | } 91 | }; 92 | 93 | this.server = new Server( 94 | { 95 | name: 'memory-bank-server', 96 | version: '0.1.0', 97 | }, 98 | { 99 | capabilities: { 100 | resources: {}, 101 | tools: {}, 102 | }, 103 | } 104 | ); 105 | 106 | this.memoryBankPath = 'memory-bank'; 107 | this.setupToolHandlers(); 108 | this.setupResourceHandlers(); 109 | 110 | // Error handling 111 | this.server.onerror = (error: unknown) => { 112 | if (error instanceof Error) { 113 | console.error('[MCP Error]', error.message, error.stack); 114 | } else { 115 | console.error('[MCP Error]', error); 116 | } 117 | }; 118 | process.on('SIGINT', async () => { 119 | await this.server.close(); 120 | process.exit(0); 121 | }); 122 | } 123 | 124 | private setupToolHandlers() { 125 | this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ 126 | tools: [ 127 | { 128 | name: 'initialize_memory_bank', 129 | description: 'Initialize Memory Bank structure for a project', 130 | inputSchema: { 131 | type: 'object', 132 | properties: { 133 | projectPath: { 134 | type: 'string', 135 | description: 'Path to project root directory', 136 | }, 137 | }, 138 | required: ['projectPath'], 139 | }, 140 | }, 141 | { 142 | name: 'update_context', 143 | description: 'Update active context with current session information', 144 | inputSchema: { 145 | type: 'object', 146 | properties: { 147 | projectPath: { 148 | type: 'string', 149 | description: 'Path to project root directory', 150 | }, 151 | content: { 152 | type: 'object', 153 | description: 'Current session context to update', 154 | properties: { 155 | currentSession: { 156 | type: 'object', 157 | properties: { 158 | date: { type: 'string' }, 159 | mode: { type: 'string' }, 160 | task: { type: 'string' }, 161 | }, 162 | required: ['date', 'mode', 'task'], 163 | }, 164 | }, 165 | required: ['currentSession'], 166 | }, 167 | }, 168 | required: ['projectPath', 'content'], 169 | }, 170 | }, 171 | { 172 | name: 'record_decision', 173 | description: 'Add a new technical decision with rationale and metadata', 174 | inputSchema: { 175 | type: 'object', 176 | properties: { 177 | projectPath: { 178 | type: 'string', 179 | description: 'Path to project root directory', 180 | }, 181 | decision: { 182 | type: 'object', 183 | properties: { 184 | title: { type: 'string', description: 'Title of the decision' }, 185 | description: { type: 'string', description: 'What was decided' }, 186 | rationale: { type: 'string', description: 'Why this decision was made' }, 187 | status: { 188 | type: 'string', 189 | description: 'Current status of the decision', 190 | enum: ['proposed', 'accepted', 'rejected', 'superseded'], 191 | default: 'accepted' 192 | }, 193 | impact: { 194 | type: 'string', 195 | description: 'Areas of the project affected by this decision' 196 | }, 197 | alternatives: { 198 | type: 'array', 199 | items: { type: 'string' }, 200 | description: 'Alternative options that were considered' 201 | }, 202 | relatedDecisions: { 203 | type: 'array', 204 | items: { type: 'string' }, 205 | description: 'Titles of related decisions' 206 | }, 207 | date: { 208 | type: 'string', 209 | description: 'Optional decision date (defaults to current date)', 210 | pattern: '^\\d{4}-\\d{2}-\\d{2}$' 211 | } 212 | }, 213 | required: ['title', 'description', 'rationale', 'status'], 214 | }, 215 | }, 216 | required: ['projectPath', 'decision'], 217 | }, 218 | }, 219 | { 220 | name: 'track_progress', 221 | description: 'Update project progress and milestones', 222 | inputSchema: { 223 | type: 'object', 224 | properties: { 225 | projectPath: { 226 | type: 'string', 227 | description: 'Path to project root directory', 228 | }, 229 | progress: { 230 | type: 'object', 231 | properties: { 232 | completed: { type: 'array', items: { type: 'string' } }, 233 | inProgress: { type: 'array', items: { type: 'string' } }, 234 | blocked: { type: 'array', items: { type: 'string' } }, 235 | }, 236 | required: ['completed', 'inProgress'], 237 | }, 238 | }, 239 | required: ['projectPath', 'progress'], 240 | }, 241 | }, 242 | ], 243 | })); 244 | 245 | this.server.setRequestHandler(CallToolRequestSchema, async (request) => { 246 | try { 247 | switch (request.params.name) { 248 | case 'initialize_memory_bank': 249 | return await this.handleInitializeMemoryBank(request.params.arguments); 250 | case 'update_context': 251 | return await this.handleUpdateContext(request.params.arguments); 252 | case 'record_decision': 253 | return await this.handleRecordDecision(request.params.arguments); 254 | case 'track_progress': 255 | return await this.handleTrackProgress(request.params.arguments); 256 | default: 257 | throw new McpError( 258 | ErrorCode.MethodNotFound, 259 | `Unknown tool: ${request.params.name}` 260 | ); 261 | } 262 | } catch (error: unknown) { 263 | if (error instanceof McpError) throw error; 264 | throw new McpError( 265 | ErrorCode.InternalError, 266 | `Tool execution failed: ${error instanceof Error ? error.message : String(error)}` 267 | ); 268 | } 269 | }); 270 | } 271 | 272 | private setupResourceHandlers() { 273 | this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({ 274 | resources: [ 275 | { 276 | uri: 'memory://project/context', 277 | name: 'Project Context', 278 | description: 'Project overview, technical stack, and guidelines', 279 | mimeType: 'text/markdown', 280 | }, 281 | { 282 | uri: 'memory://active/context', 283 | name: 'Active Context', 284 | description: 'Current session state and tasks', 285 | mimeType: 'text/markdown', 286 | }, 287 | { 288 | uri: 'memory://progress', 289 | name: 'Progress Log', 290 | description: 'Project milestones and task tracking', 291 | mimeType: 'text/markdown', 292 | }, 293 | { 294 | uri: 'memory://decisions', 295 | name: 'Decision Log', 296 | description: 'Technical decisions and rationale', 297 | mimeType: 'text/markdown', 298 | }, 299 | ], 300 | })); 301 | 302 | this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { 303 | const projectPath = process.env.PROJECT_PATH; 304 | if (!projectPath) { 305 | throw new McpError( 306 | ErrorCode.InvalidRequest, 307 | 'PROJECT_PATH environment variable not set' 308 | ); 309 | } 310 | 311 | try { 312 | const content = await this.readMemoryBankFile( 313 | projectPath, 314 | this.getFileNameFromUri(request.params.uri) 315 | ); 316 | 317 | return { 318 | contents: [ 319 | { 320 | uri: request.params.uri, 321 | mimeType: 'text/markdown', 322 | text: content, 323 | }, 324 | ], 325 | }; 326 | } catch (error: unknown) { 327 | throw new McpError( 328 | ErrorCode.InternalError, 329 | `Failed to read resource: ${error instanceof Error ? error.message : String(error)}` 330 | ); 331 | } 332 | }); 333 | } 334 | 335 | private async getProjectInfo(projectPath: string): Promise { 336 | try { 337 | const packageJsonPath = path.join(projectPath, 'package.json'); 338 | const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8')); 339 | 340 | return { 341 | name: packageJson.name || 'Unknown', 342 | version: packageJson.version || '0.1.0', 343 | description: packageJson.description || 'No description provided', 344 | license: packageJson.license || 'Not specified', 345 | dependencies: Object.keys(packageJson.dependencies || {}), 346 | devDependencies: Object.keys(packageJson.devDependencies || {}) 347 | }; 348 | } catch (error) { 349 | return { 350 | name: 'Unknown', 351 | version: '0.1.0', 352 | description: 'No description provided', 353 | license: 'Not specified', 354 | dependencies: [], 355 | devDependencies: [] 356 | }; 357 | } 358 | } 359 | 360 | private async detectTechStack(projectPath: string): Promise { 361 | const stack: TechStack = { 362 | runtime: 'Node.js', 363 | frameworks: [], 364 | languages: new Set(), 365 | configs: [] 366 | }; 367 | 368 | // Define valid programming language extensions 369 | const validLanguages = new Map([ 370 | ['js', 'JavaScript'], 371 | ['mjs', 'JavaScript'], 372 | ['jsx', 'JavaScript (React)'], 373 | ['ts', 'TypeScript'], 374 | ['tsx', 'TypeScript (React)'], 375 | ['py', 'Python'], 376 | ['rb', 'Ruby'], 377 | ['php', 'PHP'], 378 | ['java', 'Java'], 379 | ['go', 'Go'], 380 | ['rs', 'Rust'], 381 | ['c', 'C'], 382 | ['cpp', 'C++'], 383 | ['h', 'C/C++ Header'], 384 | ['cs', 'C#'], 385 | ['swift', 'Swift'], 386 | ['kt', 'Kotlin'], 387 | ['dart', 'Dart'] 388 | ]); 389 | 390 | // Define relevant config files 391 | const relevantConfigs = new Set([ 392 | 'package.json', 393 | 'tsconfig.json', 394 | '.eslintrc', 395 | '.prettierrc', 396 | '.babelrc', 397 | '.env', 398 | 'webpack.config.js', 399 | 'vite.config.js', 400 | 'next.config.js', 401 | '.gitignore', 402 | 'jest.config.js', 403 | 'rollup.config.js' 404 | ]); 405 | 406 | try { 407 | const files = await fs.readdir(projectPath, { recursive: true }); 408 | 409 | // Process each file 410 | files.forEach((file: string) => { 411 | const ext = path.extname(file).toLowerCase().substring(1); 412 | const basename = path.basename(file); 413 | 414 | // Add valid programming languages 415 | if (validLanguages.has(ext)) { 416 | stack.languages.add(validLanguages.get(ext)!); 417 | } 418 | 419 | // Add relevant config files 420 | if (relevantConfigs.has(basename)) { 421 | stack.configs.push(basename); 422 | } 423 | }); 424 | 425 | // Remove duplicates from configs 426 | stack.configs = [...new Set(stack.configs)]; 427 | 428 | // Detect frameworks from package.json 429 | const packageJson = await fs.readFile(path.join(projectPath, 'package.json'), 'utf8'); 430 | const { dependencies = {}, devDependencies = {} } = JSON.parse(packageJson); 431 | 432 | const allDeps = { ...dependencies, ...devDependencies }; 433 | const frameworkDetection = { 434 | 'react': 'React', 435 | 'next': 'Next.js', 436 | 'express': 'Express', 437 | 'vue': 'Vue.js', 438 | 'angular': 'Angular', 439 | 'svelte': 'Svelte', 440 | 'nestjs': 'NestJS', 441 | '@nestjs/core': 'NestJS', 442 | 'fastify': 'Fastify', 443 | 'koa': 'Koa', 444 | 'gatsby': 'Gatsby', 445 | 'nuxt': 'Nuxt.js' 446 | }; 447 | 448 | for (const [dep, framework] of Object.entries(frameworkDetection)) { 449 | if (allDeps[dep]) { 450 | stack.frameworks.push(framework); 451 | } 452 | } 453 | 454 | return stack; 455 | } catch (error) { 456 | return stack; 457 | } 458 | } 459 | 460 | private generateInitialDecisions(info: ProjectInfo, stack: TechStack): Decision[] { 461 | const decisions: Decision[] = [ 462 | { 463 | title: 'Initial Project Structure', 464 | description: `Initialized ${info.name} with a modular architecture using ${stack.runtime}`, 465 | rationale: 'Established foundation for scalable and maintainable development', 466 | status: 'accepted', 467 | impact: 'Project-wide', 468 | date: new Date().toISOString().split('T')[0] 469 | } 470 | ]; 471 | 472 | // Add framework-specific decisions 473 | if (stack.frameworks.length > 0) { 474 | decisions.push({ 475 | title: 'Framework Selection', 476 | description: `Selected ${stack.frameworks.join(', ')} as primary framework(s)`, 477 | rationale: 'Chosen based on project requirements and team expertise', 478 | status: 'accepted', 479 | impact: 'Technical architecture', 480 | date: new Date().toISOString().split('T')[0] 481 | }); 482 | } 483 | 484 | return decisions; 485 | } 486 | 487 | private formatDecisionLog(decisions: Decision[]): string { 488 | return `# Decision Log 489 | 490 | ## Technical Decisions 491 | 492 | ${decisions.map(d => `### ${d.title} (${d.date || 'No date'}) 493 | ${d.description} 494 | 495 | **Status:** ${d.status} 496 | ${d.impact ? `**Impact:** ${d.impact}\n` : ''} 497 | Rationale: 498 | ${d.rationale} 499 | 500 | ${d.alternatives ? `Alternatives Considered:\n${d.alternatives.map(alt => `- ${alt}`).join('\n')}\n` : ''} 501 | ${d.relatedDecisions ? `Related Decisions:\n${d.relatedDecisions.map(rd => `- ${rd}`).join('\n')}` : ''}`).join('\n\n')} 502 | 503 | ## Pending Decisions 504 | `; 505 | } 506 | 507 | private formatProjectContext(info: ProjectInfo, stack: TechStack): string { 508 | // Filter out core dependencies 509 | const corePackages = new Set(['@types/node', 'typescript', 'ts-node', 'nodemon']); 510 | const keyDeps = info.dependencies.filter(d => !corePackages.has(d)); 511 | const keyDevDeps = info.devDependencies.filter(d => !corePackages.has(d)); 512 | 513 | const formatDeps = (deps: string[]) => 514 | deps.length ? deps.map(d => `- ${d}`).join('\n') : 'None'; 515 | 516 | return `# Project Context 517 | 518 | ## Overview 519 | ${info.name} - ${info.description} 520 | Version: ${info.version} 521 | License: ${info.license} 522 | 523 | ## Technical Stack 524 | Runtime: ${stack.runtime} 525 | ${stack.languages.size ? `Languages: ${Array.from(stack.languages).sort().join(', ')}` : ''} 526 | ${stack.frameworks.length ? `Frameworks: ${stack.frameworks.join(', ')}` : ''} 527 | 528 | ## Dependencies 529 | Core: 530 | ${formatDeps(keyDeps)} 531 | 532 | Development: 533 | ${formatDeps(keyDevDeps)} 534 | 535 | ## Configuration 536 | ${stack.configs.sort().map(c => `- ${c}`).join('\n')} 537 | 538 | ## Architecture 539 | - Type: ${stack.frameworks.length ? `Framework-based (${stack.frameworks.join(', ')})` : 'Modular'} 540 | - Language: ${Array.from(stack.languages)[0] || 'Not detected'} 541 | - Environment: Node.js 542 | ${info.dependencies.includes('@modelcontextprotocol/sdk') ? '- MCP Server Implementation' : ''} 543 | `; 544 | } 545 | 546 | public async handleInitializeMemoryBank(args: any) { 547 | const projectPath = args.projectPath; 548 | if (!projectPath) { 549 | throw new McpError(ErrorCode.InvalidParams, 'Project path is required'); 550 | } 551 | 552 | // Convert to absolute path if not already 553 | const absoluteProjectPath = path.isAbsolute(projectPath) 554 | ? projectPath 555 | : path.resolve(process.cwd(), projectPath); 556 | 557 | try { 558 | const memoryBankPath = path.join(projectPath, this.memoryBankPath); 559 | await fs.mkdir(memoryBankPath, { recursive: true }); 560 | 561 | // Gather project information 562 | const projectInfo = await this.getProjectInfo(projectPath); 563 | const techStack = await this.detectTechStack(projectPath); 564 | const projectContext = this.formatProjectContext(projectInfo, techStack); 565 | 566 | // Generate initial decisions 567 | const initialDecisions = this.generateInitialDecisions(projectInfo, techStack); 568 | 569 | const currentDate = new Date().toISOString().split('T')[0]; 570 | const currentTime = new Date().toLocaleTimeString(); 571 | 572 | const files: MemoryBankFile[] = [ 573 | { 574 | path: 'projectContext.md', 575 | content: projectContext, 576 | }, 577 | { 578 | path: 'activeContext.md', 579 | content: `# Active Context 580 | 581 | ## Current Session 582 | Started: ${currentDate} ${currentTime} 583 | Mode: Development 584 | Current Task: Initial Setup 585 | 586 | ## Tasks 587 | ### In Progress 588 | - [ ] Project initialization 589 | - [ ] Environment setup 590 | 591 | ## Open Questions 592 | - What are the primary project goals? 593 | - What are the key technical requirements? 594 | 595 | ## Recent Updates 596 | - ${currentDate}: Project initialized`, 597 | }, 598 | { 599 | path: 'progress.md', 600 | content: `# Progress Log 601 | 602 | ## Current Phase 603 | Initialization 604 | 605 | ## Completed Tasks 606 | - Repository setup (${currentDate}) 607 | - Basic project structure (${currentDate}) 608 | 609 | ## In Progress 610 | - Development environment configuration 611 | - Initial documentation 612 | 613 | ## Upcoming 614 | - Code implementation 615 | - Testing setup 616 | 617 | ## Blockers 618 | [None currently identified]`, 619 | }, 620 | { 621 | path: 'decisionLog.md', 622 | content: this.formatDecisionLog([ 623 | ...initialDecisions, 624 | { 625 | title: 'Development Workflow', 626 | description: 'Established initial development workflow and practices', 627 | rationale: 'Ensure consistent development process and code quality', 628 | status: 'accepted', 629 | impact: 'Development process', 630 | date: currentDate, 631 | alternatives: [ 632 | 'Ad-hoc development process', 633 | 'Waterfall methodology' 634 | ] 635 | }, 636 | { 637 | title: 'Documentation Strategy', 638 | description: 'Implemented automated documentation with memory bank', 639 | rationale: 'Maintain up-to-date project context and decision history', 640 | status: 'accepted', 641 | impact: 'Project documentation', 642 | date: currentDate 643 | } 644 | ]), 645 | }, 646 | ]; 647 | 648 | for (const file of files) { 649 | await fs.writeFile( 650 | path.join(memoryBankPath, file.path), 651 | file.content, 652 | 'utf8' 653 | ); 654 | } 655 | 656 | // Update MCP settings 657 | await this.updateMcpSettings(absoluteProjectPath); 658 | 659 | return { 660 | content: [ 661 | { 662 | type: 'text', 663 | text: 'Memory Bank initialized successfully and MCP settings configured', 664 | }, 665 | ], 666 | }; 667 | } catch (error: unknown) { 668 | throw new McpError( 669 | ErrorCode.InternalError, 670 | `Failed to initialize Memory Bank: ${error instanceof Error ? error.message : String(error)}` 671 | ); 672 | } 673 | } 674 | 675 | private async handleUpdateContext(args: any) { 676 | const { projectPath, content } = args; 677 | if (!projectPath || !content) { 678 | throw new McpError( 679 | ErrorCode.InvalidParams, 680 | 'Project path and content are required' 681 | ); 682 | } 683 | 684 | try { 685 | const filePath = path.join(projectPath, this.memoryBankPath, 'activeContext.md'); 686 | const currentContent = await fs.readFile(filePath, 'utf8'); 687 | const updatedContent = this.mergeContext(currentContent, content); 688 | await fs.writeFile(filePath, updatedContent, 'utf8'); 689 | 690 | return { 691 | content: [ 692 | { 693 | type: 'text', 694 | text: 'Active context updated successfully', 695 | }, 696 | ], 697 | }; 698 | } catch (error: unknown) { 699 | throw new McpError( 700 | ErrorCode.InternalError, 701 | `Failed to update context: ${error instanceof Error ? error.message : String(error)}` 702 | ); 703 | } 704 | } 705 | 706 | private async handleRecordDecision(args: any) { 707 | const { projectPath, decision } = args; 708 | if (!projectPath || !decision) { 709 | throw new McpError( 710 | ErrorCode.InvalidParams, 711 | 'Project path and decision are required' 712 | ); 713 | } 714 | 715 | try { 716 | const filePath = path.join(projectPath, this.memoryBankPath, 'decisionLog.md'); 717 | const currentContent = await fs.readFile(filePath, 'utf8'); 718 | const updatedContent = this.addDecision(currentContent, decision); 719 | await fs.writeFile(filePath, updatedContent, 'utf8'); 720 | 721 | return { 722 | content: [ 723 | { 724 | type: 'text', 725 | text: 'Decision recorded successfully', 726 | }, 727 | ], 728 | }; 729 | } catch (error: unknown) { 730 | throw new McpError( 731 | ErrorCode.InternalError, 732 | `Failed to record decision: ${error instanceof Error ? error.message : String(error)}` 733 | ); 734 | } 735 | } 736 | 737 | private async handleTrackProgress(args: any) { 738 | const { projectPath, progress } = args; 739 | if (!projectPath || !progress) { 740 | throw new McpError( 741 | ErrorCode.InvalidParams, 742 | 'Project path and progress are required' 743 | ); 744 | } 745 | 746 | try { 747 | const filePath = path.join(projectPath, this.memoryBankPath, 'progress.md'); 748 | const currentContent = await fs.readFile(filePath, 'utf8'); 749 | const updatedContent = this.updateProgress(currentContent, progress); 750 | await fs.writeFile(filePath, updatedContent, 'utf8'); 751 | 752 | return { 753 | content: [ 754 | { 755 | type: 'text', 756 | text: 'Progress updated successfully', 757 | }, 758 | ], 759 | }; 760 | } catch (error: unknown) { 761 | throw new McpError( 762 | ErrorCode.InternalError, 763 | `Failed to update progress: ${error instanceof Error ? error.message : String(error)}` 764 | ); 765 | } 766 | } 767 | 768 | private async updateMcpSettings(projectPath: string): Promise { 769 | try { 770 | const settingsPath = await this.getMcpSettingsPath(); 771 | const settings = await this.readMcpSettings(settingsPath); 772 | 773 | // Update memory-bank server configuration 774 | settings.mcpServers = settings.mcpServers || {}; 775 | settings.mcpServers['memory-bank'] = { 776 | command: 'node', 777 | args: [path.join(projectPath, 'build', 'index.js')], 778 | env: { 779 | PROJECT_PATH: projectPath 780 | }, 781 | disabled: false, 782 | autoApprove: [] 783 | }; 784 | 785 | await this.writeMcpSettings(settingsPath, settings); 786 | } catch (error: unknown) { 787 | throw new McpError( 788 | ErrorCode.InternalError, 789 | `Failed to update MCP settings: ${error instanceof Error ? error.message : String(error)}` 790 | ); 791 | } 792 | } 793 | 794 | private async getMcpSettingsPath(): Promise { 795 | let homedir: string; 796 | try { 797 | homedir = os.homedir(); 798 | } catch (error) { 799 | console.error('Error getting home directory:', error); 800 | throw new Error(`Could not determine user home directory: ${error instanceof Error ? error.message : String(error)}`); 801 | } 802 | 803 | const platform = process.platform as keyof typeof MemoryBankServer.MCP_SETTINGS_PATHS; 804 | const relativePath = MemoryBankServer.MCP_SETTINGS_PATHS[platform]; 805 | if (!relativePath) { 806 | throw new Error(`Unsupported platform: ${platform}`); 807 | } 808 | 809 | return path.join(homedir, relativePath); 810 | } 811 | 812 | private async readMcpSettings(settingsPath: string): Promise { 813 | try { 814 | const content = await fs.readFile(settingsPath, 'utf8'); 815 | return JSON.parse(content); 816 | } catch (error) { 817 | if (error instanceof Error && 'code' in error && error.code === 'ENOENT') { 818 | // Return default settings if file doesn't exist 819 | return { mcpServers: {} }; 820 | } 821 | throw error; 822 | } 823 | } 824 | 825 | private async writeMcpSettings(settingsPath: string, settings: McpSettings): Promise { 826 | // Ensure settings directory exists 827 | await fs.mkdir(path.dirname(settingsPath), { recursive: true }); 828 | await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2), 'utf8'); 829 | } 830 | 831 | private async readMemoryBankFile(projectPath: string, fileName: string): Promise { 832 | const filePath = path.join(projectPath, this.memoryBankPath, fileName); 833 | try { 834 | return await fs.readFile(filePath, 'utf8'); 835 | } catch (error: unknown) { 836 | throw new Error(`Failed to read file ${fileName}: ${error instanceof Error ? error.message : String(error)}`); 837 | } 838 | } 839 | 840 | private getFileNameFromUri(uri: string): string { 841 | const mapping: { [key: string]: string } = { 842 | 'memory://project/context': 'projectContext.md', 843 | 'memory://active/context': 'activeContext.md', 844 | 'memory://progress': 'progress.md', 845 | 'memory://decisions': 'decisionLog.md', 846 | }; 847 | 848 | const fileName = mapping[uri]; 849 | if (!fileName) { 850 | throw new Error(`Invalid URI: ${uri}`); 851 | } 852 | 853 | return fileName; 854 | } 855 | 856 | private mergeContext(current: string, update: any): string { 857 | const date = new Date().toISOString().split('T')[0]; 858 | return `${current}\n\n## Session Update (${date})\n- Mode: ${update.currentSession.mode}\n- Task: ${update.currentSession.task}`; 859 | } 860 | 861 | private addDecision(current: string, decision: Decision): string { 862 | const date = decision.date || new Date().toISOString().split('T')[0]; 863 | const alternatives = decision.alternatives 864 | ? `\n\nAlternatives Considered:\n${decision.alternatives.map((alt: string) => `- ${alt}`).join('\n')}` 865 | : ''; 866 | const impact = decision.impact ? `\n**Impact:** ${decision.impact}` : ''; 867 | const related = decision.relatedDecisions 868 | ? `\n\nRelated Decisions:\n${decision.relatedDecisions.map((rd: string) => `- ${rd}`).join('\n')}` 869 | : ''; 870 | 871 | // Find the appropriate section based on status 872 | const statusSection = decision.status === 'proposed' ? '## Pending Decisions' : '## Technical Decisions'; 873 | const sections = current.split('\n\n## '); 874 | const targetSectionIndex = sections.findIndex(s => s.startsWith('Technical Decisions') || s.startsWith('Pending Decisions')); 875 | 876 | if (targetSectionIndex === -1) return current; // Fallback if sections not found 877 | 878 | const newDecision = `### ${decision.title} (${date}) 879 | ${decision.description} 880 | 881 | **Status:** ${decision.status}${impact} 882 | 883 | Rationale: 884 | ${decision.rationale}${alternatives}${related}`; 885 | 886 | sections[targetSectionIndex] = sections[targetSectionIndex].trim() + '\n\n' + newDecision; 887 | return sections.join('\n\n## '); 888 | } 889 | 890 | private async checkAndPromptProgress(): Promise { 891 | if (this.sessionState.questionCount >= 10) { 892 | this.sessionState.questionCount = 0; // Reset counter 893 | this.sessionState.lastPrompted = new Date().toISOString().split('T')[0]; 894 | 895 | // Auto-save progress 896 | await this.saveProgressUpdate(); 897 | } 898 | } 899 | 900 | private async saveProgressUpdate(): Promise { 901 | const projectPath = process.env.PROJECT_PATH; 902 | if (!projectPath) return; 903 | 904 | const progress = { 905 | completed: Array.from(this.sessionState.taskUpdates.completed), 906 | inProgress: Array.from(this.sessionState.taskUpdates.inProgress), 907 | blocked: Array.from(this.sessionState.taskUpdates.blocked) 908 | }; 909 | 910 | await this.handleTrackProgress({ 911 | projectPath, 912 | progress 913 | }); 914 | 915 | // Clear the sets after saving 916 | this.sessionState.taskUpdates.completed.clear(); 917 | this.sessionState.taskUpdates.inProgress.clear(); 918 | this.sessionState.taskUpdates.blocked.clear(); 919 | } 920 | 921 | private updateProgress(current: string, progress: any): string { 922 | const date = new Date().toISOString().split('T')[0]; 923 | 924 | // Add tasks to session state 925 | progress.completed?.forEach((task: string) => this.sessionState.taskUpdates.completed.add(task)); 926 | progress.inProgress?.forEach((task: string) => this.sessionState.taskUpdates.inProgress.add(task)); 927 | progress.blocked?.forEach((task: string) => this.sessionState.taskUpdates.blocked.add(task)); 928 | 929 | const completed = progress.completed.map((task: string) => `- ✓ ${task}`).join('\n'); 930 | const inProgress = progress.inProgress.map((task: string) => `- → ${task}`).join('\n'); 931 | const blocked = progress.blocked 932 | ? `\n\nBlocked:\n${progress.blocked.map((task: string) => `- ⚠ ${task}`).join('\n')}` 933 | : ''; 934 | 935 | this.sessionState.questionCount++; // Increment question counter 936 | this.checkAndPromptProgress(); // Check if we should prompt for progress save 937 | 938 | return `${current}\n\n## Update (${date})\nPhase: ${this.sessionState.currentPhase}\nQuestions Processed: ${this.sessionState.questionCount}\n\nCompleted:\n${completed}\n\nIn Progress:\n${inProgress}${blocked}`; 939 | } 940 | 941 | async run() { 942 | const transport = new StdioServerTransport(); 943 | await this.server.connect(transport); 944 | 945 | // Initialize with current phase 946 | this.sessionState.currentPhase = 'Development'; 947 | console.error('Memory Bank MCP server running on stdio'); 948 | } 949 | } 950 | 951 | async function handleCliCommand() { 952 | if (process.argv[2] === 'initialize_memory_bank') { 953 | const projectPath = process.argv[3]; 954 | if (!projectPath) { 955 | console.error('Error: Project path is required'); 956 | process.exit(1); 957 | } 958 | 959 | const server = new MemoryBankServer(); 960 | try { 961 | const result = await server.handleInitializeMemoryBank({ projectPath }); 962 | console.log(result.content[0].text); 963 | process.exit(0); 964 | } catch (error) { 965 | console.error('Error:', error instanceof Error ? error.message : String(error)); 966 | process.exit(1); 967 | } 968 | } else { 969 | // Run as MCP server 970 | const server = new MemoryBankServer(); 971 | server.run().catch(console.error); 972 | } 973 | } 974 | 975 | handleCliCommand(); 976 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "Node16", 5 | "moduleResolution": "Node16", 6 | "outDir": "./build", 7 | "rootDir": "./src", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true 12 | }, 13 | "include": ["src/**/*"], 14 | "exclude": ["node_modules"] 15 | } 16 | --------------------------------------------------------------------------------