#
tokens: 42959/50000 6/41 files (page 2/4)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 2 of 4. Use http://codebase.md/crazyrabbitltc/mcp-vibecoder?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .gitignore
├── bun.lockb
├── debug.js
├── docs
│   └── mcp-sdk-improvements.md
├── documents
│   ├── test-feature
│   │   └── prd.md
│   └── test-feature-custom.md
├── instructions
│   ├── checklist.md
│   ├── Impl.md
│   ├── mcp_sdk_improvements.md
│   ├── mcp_server_improvements.md
│   ├── plan.md
│   ├── PRD.md
│   └── solidity_tic_tac_toe_project.md
├── MCP-docs.txt
├── MCP-Typescript-readme.txt
├── package-lock.json
├── package.json
├── README.md
├── repomix-output.txt
├── src
│   ├── clarification.ts
│   ├── document-storage.ts
│   ├── documentation.ts
│   ├── errors.ts
│   ├── index-updated.ts
│   ├── index.ts
│   ├── mcp-server.ts
│   ├── phases.ts
│   ├── registry.ts
│   ├── resource-handlers.ts
│   ├── schemas.ts
│   ├── storage.ts
│   ├── templates
│   │   ├── impl-template.md
│   │   └── prd-template.md
│   ├── test-mcp-improved.js
│   ├── tool-handlers.ts
│   ├── types.ts
│   ├── utils.ts
│   └── validators.ts
├── test-document-storage.js
├── test-document-tools.js
├── test-mcp.js
├── tsconfig.build.json
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/src/resource-handlers.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * @file resource-handlers.ts
  3 |  * @version 1.0.0
  4 |  * 
  5 |  * Provides handlers for resources exposed by the Vibe-Coder MCP Server.
  6 |  * These handlers are registered with the resource registry for consistent handling.
  7 |  */
  8 | 
  9 | import { ResourceTemplate } from '@modelcontextprotocol/sdk/types.js';
 10 | import { resourceRegistry, ResourceHandler } from './registry.js';
 11 | import { Feature } from './types.js';
 12 | import { listFeatures, getFeature } from './storage.js';
 13 | import { formatClarificationResponses } from './clarification.js';
 14 | import { generatePRD, generateImplementationPlan } from './documentation.js';
 15 | import { generateFeatureProgressSummary } from './utils.js';
 16 | import { ErrorCode, createErrorResponse } from './errors.js';
 17 | 
 18 | /**
 19 |  * Define resource templates for all resources
 20 |  */
 21 | const RESOURCE_TEMPLATES = {
 22 |   featuresList: new ResourceTemplate('features://list', { list: undefined }),
 23 |   featuresStatus: new ResourceTemplate('features://status', { list: undefined }),
 24 |   featureDetail: new ResourceTemplate('feature://{featureId}', { list: undefined }),
 25 |   featureProgress: new ResourceTemplate('feature://{featureId}/progress', { list: undefined }),
 26 |   featurePrd: new ResourceTemplate('feature://{featureId}/prd', { list: undefined }),
 27 |   featureImplementation: new ResourceTemplate('feature://{featureId}/implementation', { list: undefined }),
 28 |   featurePhases: new ResourceTemplate('feature://{featureId}/phases', { list: undefined }),
 29 |   featureTasks: new ResourceTemplate('feature://{featureId}/tasks', { list: undefined }),
 30 |   phaseDetail: new ResourceTemplate('feature://{featureId}/phase/{phaseId}', { list: undefined }),
 31 |   phaseTasks: new ResourceTemplate('feature://{featureId}/phase/{phaseId}/tasks', { list: undefined }),
 32 |   taskDetail: new ResourceTemplate('feature://{featureId}/phase/{phaseId}/task/{taskId}', { list: undefined }),
 33 | };
 34 | 
 35 | /**
 36 |  * Handler for the features list resource
 37 |  */
 38 | const featuresListHandler: ResourceHandler = async (uri, params) => {
 39 |   return {
 40 |     contents: [{
 41 |       uri: uri.href,
 42 |       mimeType: "text/plain",
 43 |       text: listFeatures().map(f => `${f.id}: ${f.name}`).join("\n")
 44 |     }]
 45 |   };
 46 | };
 47 | 
 48 | /**
 49 |  * Handler for the features status resource
 50 |  */
 51 | const featuresStatusHandler: ResourceHandler = async (uri, params) => {
 52 |   const features = listFeatures();
 53 |   
 54 |   if (features.length === 0) {
 55 |     return {
 56 |       contents: [{
 57 |         uri: uri.href,
 58 |         mimeType: "text/markdown",
 59 |         text: "# Project Status\n\nNo features have been created yet."
 60 |       }]
 61 |     };
 62 |   }
 63 |   
 64 |   const featuresStatus = features.map(feature => {
 65 |     const totalPhases = feature.phases.length;
 66 |     const completedPhases = feature.phases.filter(p => p.status === 'completed' || p.status === 'reviewed').length;
 67 |     const totalTasks = feature.phases.reduce((acc, phase) => acc + phase.tasks.length, 0);
 68 |     const completedTasks = feature.phases.reduce(
 69 |       (acc, phase) => acc + phase.tasks.filter(t => t.completed).length, 0
 70 |     );
 71 |     
 72 |     return `## ${feature.name}
 73 | - ID: ${feature.id}
 74 | - Status: ${completedPhases === totalPhases && totalPhases > 0 ? 'Completed' : 'In Progress'}
 75 | - Phases: ${completedPhases}/${totalPhases} completed
 76 | - Tasks: ${completedTasks}/${totalTasks} completed
 77 | - [View Details](feature://${feature.id}/progress)
 78 | `;
 79 |   }).join('\n');
 80 |   
 81 |   return {
 82 |     contents: [{
 83 |       uri: uri.href,
 84 |       mimeType: "text/markdown",
 85 |       text: `# Project Status\n\n${featuresStatus}`
 86 |     }]
 87 |   };
 88 | };
 89 | 
 90 | /**
 91 |  * Handler for the feature detail resource
 92 |  */
 93 | const featureDetailHandler: ResourceHandler = async (uri, params) => {
 94 |   const featureId = params.featureId;
 95 |   const feature = getFeature(featureId);
 96 |   
 97 |   if (!feature) {
 98 |     return createErrorResponse(ErrorCode.FEATURE_NOT_FOUND, `Feature ${featureId} not found`);
 99 |   }
100 |   
101 |   const timestamp = feature.updatedAt.toISOString();
102 |   const clarifications = formatClarificationResponses(feature.clarificationResponses);
103 |   const phasesText = feature.phases.map(p => 
104 |     `- ${p.name} (${p.status}): ${p.tasks.filter(t => t.completed).length}/${p.tasks.length} tasks completed`
105 |   ).join('\n');
106 |   
107 |   const featureDetails = `
108 | Feature: ${feature.name}
109 | ID: ${feature.id}
110 | Description: ${feature.description}
111 | Last Updated: ${timestamp}
112 | 
113 | Clarification Responses:
114 | ${clarifications}
115 | 
116 | Phases (${feature.phases.length}):
117 | ${phasesText}
118 | `;
119 |   
120 |   return {
121 |     contents: [{
122 |       uri: uri.href,
123 |       mimeType: "text/plain",
124 |       text: featureDetails
125 |     }]
126 |   };
127 | };
128 | 
129 | /**
130 |  * Handler for the feature progress resource
131 |  */
132 | const featureProgressHandler: ResourceHandler = async (uri, params) => {
133 |   const featureId = params.featureId;
134 |   const feature = getFeature(featureId);
135 |   
136 |   if (!feature) {
137 |     return createErrorResponse(ErrorCode.FEATURE_NOT_FOUND, `Feature ${featureId} not found`);
138 |   }
139 |   
140 |   const progressReport = generateFeatureProgressSummary(feature);
141 |   
142 |   return {
143 |     contents: [{
144 |       uri: uri.href,
145 |       mimeType: "text/markdown",
146 |       text: progressReport
147 |     }]
148 |   };
149 | };
150 | 
151 | /**
152 |  * Handler for the feature PRD resource
153 |  */
154 | const featurePrdHandler: ResourceHandler = async (uri, params) => {
155 |   const featureId = params.featureId;
156 |   const feature = getFeature(featureId);
157 |   
158 |   if (!feature) {
159 |     return createErrorResponse(ErrorCode.FEATURE_NOT_FOUND, `Feature ${featureId} not found`);
160 |   }
161 |   
162 |   const prdContent = feature.prdDoc || generatePRD(feature);
163 |   
164 |   return {
165 |     contents: [{
166 |       uri: uri.href,
167 |       mimeType: "text/markdown",
168 |       text: prdContent
169 |     }]
170 |   };
171 | };
172 | 
173 | /**
174 |  * Handler for the feature implementation plan resource
175 |  */
176 | const featureImplementationHandler: ResourceHandler = async (uri, params) => {
177 |   const featureId = params.featureId;
178 |   const feature = getFeature(featureId);
179 |   
180 |   if (!feature) {
181 |     return createErrorResponse(ErrorCode.FEATURE_NOT_FOUND, `Feature ${featureId} not found`);
182 |   }
183 |   
184 |   const implContent = feature.implDoc || generateImplementationPlan(feature);
185 |   
186 |   return {
187 |     contents: [{
188 |       uri: uri.href,
189 |       mimeType: "text/markdown",
190 |       text: implContent
191 |     }]
192 |   };
193 | };
194 | 
195 | /**
196 |  * Handler for the feature phases resource
197 |  */
198 | const featurePhasesHandler: ResourceHandler = async (uri, params) => {
199 |   const featureId = params.featureId;
200 |   const feature = getFeature(featureId);
201 |   
202 |   if (!feature) {
203 |     return createErrorResponse(ErrorCode.FEATURE_NOT_FOUND, `Feature ${featureId} not found`);
204 |   }
205 |   
206 |   if (feature.phases.length === 0) {
207 |     return {
208 |       contents: [{
209 |         uri: uri.href,
210 |         mimeType: "text/plain",
211 |         text: `No phases defined for feature: ${feature.name}`
212 |       }]
213 |     };
214 |   }
215 |   
216 |   const phasesContent = feature.phases.map(phase => {
217 |     const completedTasks = phase.tasks.filter(t => t.completed).length;
218 |     const totalTasks = phase.tasks.length;
219 |     return `Phase: ${phase.name} (ID: ${phase.id})
220 | Status: ${phase.status}
221 | Description: ${phase.description}
222 | Progress: ${completedTasks}/${totalTasks} tasks completed
223 | Last Updated: ${phase.updatedAt.toISOString()}
224 | `;
225 |   }).join('\n---\n\n');
226 |   
227 |   return {
228 |     contents: [{
229 |       uri: uri.href,
230 |       mimeType: "text/plain",
231 |       text: `# Phases for Feature: ${feature.name}\n\n${phasesContent}`
232 |     }]
233 |   };
234 | };
235 | 
236 | /**
237 |  * Handler for the feature tasks resource
238 |  */
239 | const featureTasksHandler: ResourceHandler = async (uri, params) => {
240 |   const featureId = params.featureId;
241 |   const feature = getFeature(featureId);
242 |   
243 |   if (!feature) {
244 |     return createErrorResponse(ErrorCode.FEATURE_NOT_FOUND, `Feature ${featureId} not found`);
245 |   }
246 |   
247 |   const allTasks = feature.phases.flatMap(phase => 
248 |     phase.tasks.map(task => ({
249 |       ...task,
250 |       phaseName: phase.name,
251 |       phaseId: phase.id,
252 |       phaseStatus: phase.status
253 |     }))
254 |   );
255 |   
256 |   if (allTasks.length === 0) {
257 |     return {
258 |       contents: [{
259 |         uri: uri.href,
260 |         mimeType: "text/plain",
261 |         text: `No tasks defined for feature: ${feature.name}`
262 |       }]
263 |     };
264 |   }
265 |   
266 |   const pendingTasks = allTasks.filter(t => !t.completed);
267 |   const completedTasks = allTasks.filter(t => t.completed);
268 |   
269 |   const pendingTasksText = pendingTasks.length > 0 
270 |     ? pendingTasks.map(task => `- [ ] ${task.description} (ID: ${task.id}, Phase: ${task.phaseName})`).join('\n')
271 |     : "No pending tasks.";
272 |     
273 |   const completedTasksText = completedTasks.length > 0
274 |     ? completedTasks.map(task => `- [x] ${task.description} (ID: ${task.id}, Phase: ${task.phaseName})`).join('\n')
275 |     : "No completed tasks.";
276 |   
277 |   const tasksContent = `# All Tasks for Feature: ${feature.name}
278 | 
279 | ## Pending Tasks (${pendingTasks.length})
280 | ${pendingTasksText}
281 | 
282 | ## Completed Tasks (${completedTasks.length})
283 | ${completedTasksText}
284 | `;
285 |   
286 |   return {
287 |     contents: [{
288 |       uri: uri.href,
289 |       mimeType: "text/plain",
290 |       text: tasksContent
291 |     }]
292 |   };
293 | };
294 | 
295 | /**
296 |  * Handler for the phase detail resource
297 |  */
298 | const phaseDetailHandler: ResourceHandler = async (uri, params) => {
299 |   const featureId = params.featureId;
300 |   const phaseId = params.phaseId;
301 |   
302 |   const feature = getFeature(featureId);
303 |   
304 |   if (!feature) {
305 |     return createErrorResponse(ErrorCode.FEATURE_NOT_FOUND, `Feature ${featureId} not found`);
306 |   }
307 |   
308 |   const phase = feature.phases.find(p => p.id === phaseId);
309 |   
310 |   if (!phase) {
311 |     return createErrorResponse(ErrorCode.PHASE_NOT_FOUND, `Phase ${phaseId} not found in feature ${feature.name}`);
312 |   }
313 |   
314 |   const completedTasks = phase.tasks.filter(t => t.completed).length;
315 |   const totalTasks = phase.tasks.length;
316 |   
317 |   const taskList = phase.tasks.map(task => 
318 |     `- [${task.completed ? 'x' : ' '}] ${task.description} (ID: ${task.id})`
319 |   ).join('\n');
320 |   
321 |   const phaseDetails = `
322 | Phase: ${phase.name}
323 | ID: ${phase.id}
324 | Status: ${phase.status}
325 | Description: ${phase.description}
326 | Created: ${phase.createdAt.toISOString()}
327 | Last Updated: ${phase.updatedAt.toISOString()}
328 | Progress: ${completedTasks}/${totalTasks} tasks completed
329 | 
330 | Tasks:
331 | ${taskList}
332 | `;
333 |   
334 |   return {
335 |     contents: [{
336 |       uri: uri.href,
337 |       mimeType: "text/plain",
338 |       text: phaseDetails
339 |     }]
340 |   };
341 | };
342 | 
343 | /**
344 |  * Handler for the phase tasks resource
345 |  */
346 | const phaseTasksHandler: ResourceHandler = async (uri, params) => {
347 |   const featureId = params.featureId;
348 |   const phaseId = params.phaseId;
349 |   
350 |   const feature = getFeature(featureId);
351 |   
352 |   if (!feature) {
353 |     return createErrorResponse(ErrorCode.FEATURE_NOT_FOUND, `Feature ${featureId} not found`);
354 |   }
355 |   
356 |   const phase = feature.phases.find(p => p.id === phaseId);
357 |   
358 |   if (!phase) {
359 |     return createErrorResponse(ErrorCode.PHASE_NOT_FOUND, `Phase ${phaseId} not found in feature ${feature.name}`);
360 |   }
361 |   
362 |   if (phase.tasks.length === 0) {
363 |     return {
364 |       contents: [{
365 |         uri: uri.href,
366 |         mimeType: "text/plain",
367 |         text: `No tasks defined for phase: ${phase.name}`
368 |       }]
369 |     };
370 |   }
371 |   
372 |   const tasksContent = phase.tasks.map(task => `
373 | Task: ${task.description}
374 | ID: ${task.id}
375 | Status: ${task.completed ? 'Completed' : 'Pending'}
376 | Created: ${task.createdAt.toISOString()}
377 | Last Updated: ${task.updatedAt.toISOString()}
378 | `).join('\n---\n');
379 |   
380 |   return {
381 |     contents: [{
382 |       uri: uri.href,
383 |       mimeType: "text/plain",
384 |       text: `# Tasks for Phase: ${phase.name}\n\n${tasksContent}`
385 |     }]
386 |   };
387 | };
388 | 
389 | /**
390 |  * Handler for the task detail resource
391 |  */
392 | const taskDetailHandler: ResourceHandler = async (uri, params) => {
393 |   const featureId = params.featureId;
394 |   const phaseId = params.phaseId;
395 |   const taskId = params.taskId;
396 |   
397 |   const feature = getFeature(featureId);
398 |   
399 |   if (!feature) {
400 |     return createErrorResponse(ErrorCode.FEATURE_NOT_FOUND, `Feature ${featureId} not found`);
401 |   }
402 |   
403 |   const phase = feature.phases.find(p => p.id === phaseId);
404 |   
405 |   if (!phase) {
406 |     return createErrorResponse(ErrorCode.PHASE_NOT_FOUND, `Phase ${phaseId} not found in feature ${feature.name}`);
407 |   }
408 |   
409 |   const task = phase.tasks.find(t => t.id === taskId);
410 |   
411 |   if (!task) {
412 |     return createErrorResponse(ErrorCode.TASK_NOT_FOUND, `Task ${taskId} not found in phase ${phase.name}`);
413 |   }
414 |   
415 |   const taskDetails = `
416 | Task: ${task.description}
417 | ID: ${task.id}
418 | Status: ${task.completed ? 'Completed' : 'Pending'}
419 | Created: ${task.createdAt.toISOString()}
420 | Last Updated: ${task.updatedAt.toISOString()}
421 | `;
422 |   
423 |   return {
424 |     contents: [{
425 |       uri: uri.href,
426 |       mimeType: "text/plain",
427 |       text: taskDetails
428 |     }]
429 |   };
430 | };
431 | 
432 | /**
433 |  * Register all resource handlers
434 |  */
435 | export function registerResourceHandlers() {
436 |   resourceRegistry.register(RESOURCE_TEMPLATES.featuresList, featuresListHandler);
437 |   resourceRegistry.register(RESOURCE_TEMPLATES.featuresStatus, featuresStatusHandler);
438 |   resourceRegistry.register(RESOURCE_TEMPLATES.featureDetail, featureDetailHandler);
439 |   resourceRegistry.register(RESOURCE_TEMPLATES.featureProgress, featureProgressHandler);
440 |   resourceRegistry.register(RESOURCE_TEMPLATES.featurePrd, featurePrdHandler);
441 |   resourceRegistry.register(RESOURCE_TEMPLATES.featureImplementation, featureImplementationHandler);
442 |   resourceRegistry.register(RESOURCE_TEMPLATES.featurePhases, featurePhasesHandler);
443 |   resourceRegistry.register(RESOURCE_TEMPLATES.featureTasks, featureTasksHandler);
444 |   resourceRegistry.register(RESOURCE_TEMPLATES.phaseDetail, phaseDetailHandler);
445 |   resourceRegistry.register(RESOURCE_TEMPLATES.phaseTasks, phaseTasksHandler);
446 |   resourceRegistry.register(RESOURCE_TEMPLATES.taskDetail, taskDetailHandler);
447 | }
448 | 
449 | // Export individual handlers for testing or direct usage
450 | export {
451 |   featuresListHandler,
452 |   featuresStatusHandler,
453 |   featureDetailHandler,
454 |   featureProgressHandler,
455 |   featurePrdHandler,
456 |   featureImplementationHandler,
457 |   featurePhasesHandler,
458 |   featureTasksHandler,
459 |   phaseDetailHandler,
460 |   phaseTasksHandler,
461 |   taskDetailHandler
462 | }; 
```

--------------------------------------------------------------------------------
/instructions/solidity_tic_tac_toe_project.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Solidity Tic Tac Toe Project
  2 | 
  3 | **Feature ID:** feature-hy5l98td
  4 | 
  5 | ## Clarification Responses
  6 | 
  7 | ### What specific problem does this feature solve?
  8 | This feature solves the problem of creating verifiable, tamper-proof gaming experiences on blockchain. It demonstrates how traditional games can be implemented in a decentralized manner where the game state and rules are enforced by smart contracts rather than a central server, ensuring fair play and transparent outcomes.
  9 | 
 10 | ### Who are the target users for this feature?
 11 | The target users are: 
 12 | 1) Blockchain enthusiasts who want to experience decentralized gaming
 13 | 2) Ethereum developers learning how to implement game logic in smart contracts
 14 | 3) Educational platforms teaching blockchain concepts through familiar games
 15 | 4) Players interested in crypto-gaming who want to try simple blockchain games with potential for token rewards
 16 | 
 17 | ### What are the key requirements for this feature?
 18 | Key requirements include: 
 19 | 1) A Solidity smart contract that implements the complete Tic Tac Toe game logic
 20 | 2) Functions for player registration and turn management
 21 | 3) Win condition detection and game state verification
 22 | 4) Prevention of illegal moves and proper handling of drawn games
 23 | 5) Option for players to wager ETH on game outcomes
 24 | 6) Events that can be used by a frontend to track game progress
 25 | 7) Gas-efficient implementation to minimize transaction costs
 26 | 
 27 | ### What are the technical constraints or considerations?
 28 | Technical constraints include: 
 29 | 1) Gas optimization is critical - each move costs ETH to execute
 30 | 2) The contract must be compatible with Solidity 0.8.x and deployable to Ethereum and compatible chains like Polygon
 31 | 3) State management must be efficient as blockchain storage is expensive
 32 | 4) Proper access control is needed to ensure only valid players can make moves in their own games
 33 | 5) Time constraints should be considered to prevent abandoned games
 34 | 6) Input validation is crucial to prevent exploits or illegal game states
 35 | 7) No external dependencies should be required beyond standard Solidity libraries
 36 | 
 37 | ### How will we measure the success of this feature?
 38 | Success will be measured by: 
 39 | 1) Successful deployment of the contract to a testnet with verified gameplay
 40 | 2) Completion of full games without errors or invalid states
 41 | 3) Gas usage below 200,000 gas per move
 42 | 4) Proper detection of all win conditions and draws
 43 | 5) Correct handling of wagers and payouts
 44 | 6) Successful integration with a basic web frontend for demonstration
 45 | 7) Security audit passing without critical vulnerabilities
 46 | 8) Documentation that allows developers to understand and interact with the contract
 47 | 
 48 | ### Are there any dependencies on other features or systems?
 49 | Dependencies include: 
 50 | 1) Ethereum or compatible blockchain network for deployment
 51 | 2) Solidity compiler version 0.8.x
 52 | 3) Hardhat or Truffle for development, testing and deployment
 53 | 4) Ethers.js or Web3.js for frontend integration
 54 | 5) MetaMask or similar Web3 provider for user interaction
 55 | 6) A basic frontend application (HTML/JS/CSS) for user interface, though this could be developed separately
 56 | 7) OpenZeppelin contracts for secure implementation patterns (optional)
 57 | 
 58 | ### What are the potential risks or challenges in implementing this feature?
 59 | The potential risks and challenges include: 
 60 | 1) High gas costs making gameplay expensive if not optimized
 61 | 2) Smart contract security vulnerabilities like reentrancy attacks or integer overflows
 62 | 3) Poor user experience due to blockchain transaction delays
 63 | 4) Abandoned games if players stop participating
 64 | 5) Complexity in handling edge cases like ties or unexpected termination
 65 | 6) Difficulties in upgrading the contract if bugs are found since blockchain code is immutable
 66 | 7) Ensuring fairness in the game mechanics while maintaining decentralization
 67 | 8) Testing challenges due to the distributed nature of blockchain applications
 68 | 
 69 | ## Development Phases
 70 | 
 71 | ### Phase 1: Smart Contract Development
 72 | **Status**: In Progress
 73 | **Description**: Develop the core Solidity smart contract for the Tic Tac Toe game, including game logic, state management, and event emission.
 74 | 
 75 | **Tasks**:
 76 | - Set up Hardhat development environment with Solidity 0.8.x
 77 | - Implement game board representation and state management
 78 | - Implement player registration and game creation functionality
 79 | - Implement move validation and game state updates
 80 | - Implement win condition detection and game completion logic
 81 | 
 82 | ### Phase 2: Testing and Optimization
 83 | **Description**: Write test cases, optimize gas usage, and ensure security of the Tic Tac Toe contract.
 84 | 
 85 | **Tasks**:
 86 | - Write unit tests for all game functionality
 87 | - Perform gas optimization for core game functions
 88 | - Conduct security review and implement safeguards
 89 | 
 90 | ### Phase 3: Deployment and Documentation
 91 | **Description**: Deploy the contract to testnets and create comprehensive documentation for developers and users.
 92 | 
 93 | **Tasks**:
 94 | - Deploy contract to Ethereum testnet (Goerli/Sepolia)
 95 | - Create technical documentation with API references
 96 | - Create a demo frontend for interacting with the contract
 97 | 
 98 | ## Product Requirements Document
 99 | 
100 | ### 1. Introduction
101 | 
102 | #### 1.1 Purpose
103 | This document outlines the requirements and specifications for a decentralized Tic Tac Toe game implemented as a Solidity smart contract on the Ethereum blockchain. The goal is to create a fully functional, gas-efficient, and secure implementation that demonstrates how traditional games can be implemented in a trustless, decentralized environment.
104 | 
105 | #### 1.2 Scope
106 | The scope of this product includes the smart contract implementation of Tic Tac Toe, including game creation, player management, game logic, win condition detection, and wagering functionality. A basic web frontend for interacting with the contract will be developed as part of the demonstration but is not the primary focus of this PRD.
107 | 
108 | #### 1.3 Background
109 | Blockchain games represent a growing segment of the web3 ecosystem, offering new possibilities for transparent and verifiable gameplay. Tic Tac Toe, as a simple yet widely understood game, provides an excellent introduction to smart contract gaming concepts while being straightforward enough to implement efficiently on-chain.
110 | 
111 | ### 2. Product Overview
112 | 
113 | #### 2.1 Product Description
114 | A decentralized Tic Tac Toe game built on Ethereum that allows two players to compete against each other with all game actions and state changes recorded on the blockchain. Players can create games, join existing games, make moves, and potentially wager ETH on the outcome.
115 | 
116 | #### 2.2 Target Users
117 | - Blockchain enthusiasts interested in decentralized applications
118 | - Ethereum developers learning smart contract development
119 | - Educational platforms teaching blockchain concepts
120 | - Casual players interested in crypto gaming experiences
121 | 
122 | ### 3. Functional Requirements
123 | 
124 | #### 3.1 Game Creation and Setup
125 | - Users must be able to create a new game, becoming player 1 (X)
126 | - Users must be able to join an existing open game as player 2 (O)
127 | - Game creators must be able to specify whether ETH wagering is enabled
128 | - If wagering is enabled, both players must contribute the same amount of ETH to participate
129 | 
130 | #### 3.2 Gameplay Mechanics
131 | - The game board must be represented as a 3x3 grid
132 | - Players must take turns making moves, with player 1 (X) always going first
133 | - The contract must validate moves to ensure they are made:
134 |   - By the correct player
135 |   - On a valid, empty position on the board
136 |   - During an active game
137 | - The contract must prevent players from making moves when it's not their turn
138 | - The contract must update and store the game state after each valid move
139 | 
140 | #### 3.3 Win Conditions and Game Completion
141 | - The contract must detect win conditions: 3 in a row horizontally, vertically, or diagonally
142 | - The contract must detect draw conditions when all positions are filled with no winner
143 | - When a game is completed, the contract must:
144 |   - Record the winner (or draw)
145 |   - Prevent further moves
146 |   - Distribute any wagered ETH to the winner (or refund in case of a draw)
147 | 
148 | #### 3.4 Event Emission
149 | - The contract must emit events for:
150 |   - Game creation
151 |   - Player joining a game
152 |   - Each valid move made
153 |   - Game completion (win/draw)
154 |   - ETH distribution if wagering is enabled
155 | 
156 | ### 4. Non-Functional Requirements
157 | 
158 | #### 4.1 Performance and Optimization
159 | - Gas usage for moves should be below 200,000 gas
160 | - The contract should minimize on-chain storage to reduce gas costs
161 | - The game logic should be optimized for minimal computational complexity
162 | 
163 | #### 4.2 Security
164 | - The contract must implement proper access controls
165 | - Input validation must be comprehensive to prevent unexpected game states
166 | - The contract should be resistant to common smart contract vulnerabilities
167 | - The contract must handle ETH transfers securely if wagering is enabled
168 | 
169 | #### 4.3 Compatibility
170 | - The contract must be compatible with Solidity 0.8.x
171 | - The contract must be deployable to Ethereum mainnet and testnets
172 | - The contract should work with standard Web3 providers like MetaMask
173 | 
174 | ### 5. Technical Specifications
175 | 
176 | #### 5.1 Smart Contract Architecture
177 | - `TicTacToe.sol`: Main contract implementing the game logic
178 | - Data structures:
179 |   - Game struct containing board state, player addresses, current turn, game status, and wager information
180 |   - Mapping from game ID to Game struct for multi-game support
181 | - Key functions:
182 |   - `createGame()`: Create a new game instance
183 |   - `joinGame(uint gameId)`: Join an existing game
184 |   - `makeMove(uint gameId, uint8 x, uint8 y)`: Make a move on the board
185 |   - `getGameState(uint gameId)`: Return the current state of a specific game
186 | 
187 | #### 5.2 Development Environment
188 | - Hardhat for development, testing, and deployment
189 | - Solidity 0.8.x as the smart contract language
190 | - Ethers.js for frontend integration
191 | - OpenZeppelin contracts for security patterns (optional)
192 | 
193 | ### 6. User Interface (Frontend)
194 | 
195 | While the frontend is not the primary focus, a basic web interface should be developed to demonstrate interaction with the smart contract:
196 | 
197 | #### 6.1 Key Frontend Features
198 | - Connect wallet functionality
199 | - Create new game / Join existing game options
200 | - Visual representation of the game board
201 | - Move selection interface
202 | - Game status display
203 | - Transaction status and confirmation
204 | 
205 | ### 7. Testing Strategy
206 | 
207 | #### 7.1 Unit Testing
208 | - Test all contract functions in isolation
209 | - Verify win condition logic covers all possible winning configurations
210 | - Test error conditions and invalid inputs
211 | 
212 | #### 7.2 Integration Testing
213 | - Test full game scenarios from creation to completion
214 | - Test wagering functionality if implemented
215 | - Verify correct event emission
216 | 
217 | #### 7.3 Security Testing
218 | - Review for common smart contract vulnerabilities
219 | - Test for correct access control enforcement
220 | - Verify proper handling of ETH transfers
221 | 
222 | ### 8. Milestones and Implementation Plan
223 | 
224 | The implementation will be organized into three main phases:
225 | 
226 | #### 8.1 Phase 1: Smart Contract Development
227 | - Set up development environment
228 | - Implement core game logic and state management
229 | - Build player registration and turn management
230 | - Create win condition detection
231 | 
232 | #### 8.2 Phase 2: Testing and Optimization
233 | - Develop comprehensive test suite
234 | - Optimize for gas efficiency
235 | - Conduct security review
236 | 
237 | #### 8.3 Phase 3: Deployment and Documentation
238 | - Deploy to Ethereum testnet
239 | - Create technical documentation
240 | - Develop demo frontend
241 | 
242 | ## Implementation Plan
243 | 
244 | ### 1. Environment Setup
245 | 
246 | #### 1.1 Development Environment
247 | - Set up a Hardhat project for Solidity development
248 | - Configure for Solidity version 0.8.17
249 | - Install necessary dependencies:
250 |   - `@openzeppelin/contracts` (optional, for security patterns)
251 |   - `@nomiclabs/hardhat-ethers` for testing
252 |   - `@nomiclabs/hardhat-waffle` for testing
253 | - Configure testing environment with Hardhat
254 | 
255 | #### 1.2 Project Structure
256 | ```
257 | /contracts
258 |   /TicTacToe.sol
259 | /test
260 |   /TicTacToe.test.js
261 | /scripts
262 |   /deploy.js
263 | /frontend (optional for demo)
264 |   /src
265 |     /components
266 |     /utils
267 | hardhat.config.js
268 | package.json
269 | README.md
270 | ```
271 | 
272 | ### 2. Smart Contract Development
273 | 
274 | #### 2.1 Contract Data Structures
275 | 
276 | Define the core data structures:
277 | 
278 | ```solidity
279 | // Game status enum
280 | enum GameStatus { OPEN, IN_PROGRESS, WINNER_X, WINNER_O, DRAW }
281 | 
282 | // Game struct to track game state
283 | struct Game {
284 |     address playerX;         // Player 1 (X)
285 |     address playerO;         // Player 2 (O)
286 |     address currentTurn;     // Whose turn it is
287 |     uint8[9] board;          // Board state (0=empty, 1=X, 2=O)
288 |     GameStatus status;       // Current game status
289 |     uint256 wagerAmount;     // ETH wagered (if any)
290 |     uint256 createdAt;       // Timestamp for game creation
291 | }
292 | 
293 | // Mapping to track all games
294 | mapping(uint256 => Game) public games;
295 | uint256 public gameCount;
296 | ```
297 | 
298 | #### 2.2 Core Game Functions
299 | 
300 | Implement these core functions:
301 | 
302 | 1. **Game Creation**
303 | ```solidity
304 | function createGame(bool withWager) external payable returns (uint256 gameId) {
305 |     // Input validation for wager
306 |     // Create new game with player X as msg.sender
307 |     // Set initial game state
308 |     // Emit GameCreated event
309 | }
310 | ```
311 | 
312 | 2. **Joining a Game**
313 | ```solidity
314 | function joinGame(uint256 gameId) external payable {
315 |     // Validate game exists and is open
316 |     // Validate wager amount if needed
317 |     // Set player O as msg.sender
318 |     // Update game status to IN_PROGRESS
319 |     // Emit PlayerJoined event
320 | }
321 | ```
322 | 
323 | 3. **Making a Move**
324 | ```solidity
325 | function makeMove(uint256 gameId, uint8 position) external {
326 |     // Validate game state and player turn
327 |     // Validate move is legal (position is in range and empty)
328 |     // Update board state
329 |     // Check for win conditions
330 |     // Update game status if game is complete
331 |     // Handle ETH distribution if game is complete and has wager
332 |     // Emit MoveExecuted event
333 | }
334 | ```
335 | 
336 | 4. **Game State Retrieval**
337 | ```solidity
338 | function getGameState(uint256 gameId) external view returns (
339 |     address playerX,
340 |     address playerO,
341 |     address currentTurn,
342 |     uint8[9] memory board,
343 |     GameStatus status
344 | ) {
345 |     // Return all relevant game state information
346 | }
347 | ```
348 | 
349 | #### 2.3 Win Condition Detection
350 | 
351 | Implement an efficient algorithm to check for wins:
352 | ```solidity
353 | function checkWinner(uint8[9] memory board) internal pure returns (bool hasWinner, uint8 winner) {
354 |     // Check rows, columns, and diagonals for 3 in a row
355 |     // Return winner (1 for X, 2 for O) if found
356 |     // Otherwise return no winner
357 | }
358 | ```
359 | 
360 | #### 2.4 ETH Handling
361 | 
362 | Handle wagering functionality:
363 | ```solidity
364 | function _distributeWinnings(Game storage game) internal {
365 |     // Send ETH to winner or refund in case of draw
366 |     // Handle potential transfer failures safely
367 | }
368 | ```
369 | 
370 | ### 3. Testing Strategy
371 | 
372 | #### 3.1 Unit Tests
373 | Write tests for:
374 | - Game creation with and without wager
375 | - Joining games
376 | - Making valid and invalid moves
377 | - Win detection for all winning positions
378 | - Draw detection
379 | - ETH distribution logic
380 | 
381 | #### 3.2 Gas Optimization
382 | - Use uint8 for board positions (0, 1, 2)
383 | - Optimize win condition checking
384 | - Minimize storage operations
385 | - Consider using bit manipulation for board state
386 | 
387 | ### 4. Deployment and Documentation
388 | 
389 | #### 4.1 Deployment Scripts
390 | Create scripts for:
391 | - Testnet deployment
392 | - Local testing deployment
393 | 
394 | #### 4.2 Documentation
395 | Document:
396 | - Contract functions and parameters
397 | - Game mechanics and flow
398 | - Integration guidelines for frontends
399 | - Examples of interaction using ethers.js
400 | 
401 | #### 4.3 Frontend Demo (Optional)
402 | If time permits, create a basic React frontend:
403 | - Wallet connection
404 | - Game creation interface
405 | - Game board visualization
406 | - Move submission
407 | 
408 | ### 5. Implementation Timeline
409 | 
410 | #### Week 1: Smart Contract Development
411 | - Day 1-2: Set up environment and implement data structures
412 | - Day 3-4: Implement core game functions
413 | - Day 5: Implement win condition detection and ETH handling
414 | 
415 | #### Week 2: Testing and Optimization
416 | - Day 1-2: Write comprehensive tests
417 | - Day 3-4: Gas optimization
418 | - Day 5: Security review
419 | 
420 | #### Week 3: Deployment and Documentation
421 | - Day 1-2: Create deployment scripts and deploy to testnet
422 | - Day 3-4: Write documentation
423 | - Day 5: (Optional) Create basic frontend demo 
```

--------------------------------------------------------------------------------
/instructions/plan.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Vibe-Coder MCP Server Implementation Plan
  2 | 
  3 | After examining the existing template MCP server and the provided documents, I'll outline a detailed implementation plan for creating the Vibe-Coder MCP server according to the PRD and Implementation documents.
  4 | 
  5 | ## Overview
  6 | 
  7 | The Vibe-Coder MCP server will guide casual coders through a structured development process using features exposed via the Model Context Protocol. It will transform the existing notes system into a comprehensive development workflow tool, helping LLMs organize code development through clarification workflows, documentation generation, and phased implementation.
  8 | 
  9 | ## Implementation Steps
 10 | 
 11 | ### Step 1: Server Configuration and Core Structure
 12 | 
 13 | I'll start by modifying the existing MCP server to align with the Vibe-Coder requirements:
 14 | 
 15 | 1. Update server metadata and capabilities
 16 | 2. Define core data structures for features, PRDs, and implementation plans
 17 | 3. Create in-memory storage for projects and their phases
 18 | 
 19 | ```typescript
 20 | // Core data types
 21 | type Feature = {
 22 |   id: string;
 23 |   name: string;
 24 |   description: string;
 25 |   clarificationResponses: ClarificationResponse[];
 26 |   prdDoc?: string;
 27 |   implDoc?: string;
 28 |   phases: Phase[];
 29 | };
 30 | 
 31 | type ClarificationResponse = {
 32 |   question: string;
 33 |   answer: string;
 34 | };
 35 | 
 36 | type Phase = {
 37 |   id: string;
 38 |   name: string;
 39 |   description: string;
 40 |   tasks: Task[];
 41 |   status: "pending" | "in_progress" | "completed" | "reviewed";
 42 | };
 43 | 
 44 | type Task = {
 45 |   description: string;
 46 |   completed: boolean;
 47 | };
 48 | 
 49 | // In-memory storage
 50 | const features: { [id: string]: Feature } = {};
 51 | ```
 52 | 
 53 | ### Step 2: Feature Clarification Implementation
 54 | 
 55 | The clarification module will use MCP tools to engage users in iterative questioning:
 56 | 
 57 | 1. Create a tool to initiate feature clarification
 58 | 2. Implement a tool to receive clarification responses
 59 | 3. Create a resource to retrieve clarification status
 60 | 
 61 | ```typescript
 62 | // Tool for initiating clarification
 63 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
 64 |   if (request.params.name === "start_feature_clarification") {
 65 |     const featureName = String(request.params.arguments?.featureName || "");
 66 |     const featureId = generateId();
 67 |     
 68 |     features[featureId] = {
 69 |       id: featureId,
 70 |       name: featureName,
 71 |       description: String(request.params.arguments?.initialDescription || ""),
 72 |       clarificationResponses: [],
 73 |       phases: []
 74 |     };
 75 |     
 76 |     // Return first clarification question
 77 |     return {
 78 |       content: [{
 79 |         type: "text",
 80 |         text: `Feature ID: ${featureId}\n\nLet's clarify your feature request. What specific problem does this feature solve?`
 81 |       }]
 82 |     };
 83 |   }
 84 | 
 85 |   // Handle other tools...
 86 | });
 87 | ```
 88 | 
 89 | ### Step 3: PRD and Implementation Plan Generation
 90 | 
 91 | Implement tools to generate documentation based on clarification responses:
 92 | 
 93 | 1. Create a tool to generate the PRD document
 94 | 2. Implement a tool to create the implementation plan
 95 | 3. Add resources to access these documents
 96 | 
 97 | ```typescript
 98 | // Tool for generating PRD
 99 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
100 |   if (request.params.name === "generate_prd") {
101 |     const featureId = String(request.params.arguments?.featureId);
102 |     const feature = features[featureId];
103 |     
104 |     if (!feature) {
105 |       throw new Error("Feature not found");
106 |     }
107 |     
108 |     // Generate PRD content based on clarification responses
109 |     const prdContent = generatePRD(feature);
110 |     feature.prdDoc = prdContent;
111 |     
112 |     return {
113 |       content: [{
114 |         type: "text",
115 |         text: `PRD generated successfully for ${feature.name}. You can view it using the "feature_prd" resource.`
116 |       }]
117 |     };
118 |   }
119 |   
120 |   // Similar implementation for implementation plan generation...
121 | });
122 | ```
123 | 
124 | ### Step 4: Phase Management Implementation
125 | 
126 | Create tools to manage development phases:
127 | 
128 | 1. Implement a tool to create phases
129 | 2. Add a tool to update phase status
130 | 3. Create resources to view phase details
131 | 
132 | ```typescript
133 | // Tool for creating a new phase
134 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
135 |   if (request.params.name === "create_phase") {
136 |     const featureId = String(request.params.arguments?.featureId);
137 |     const phaseName = String(request.params.arguments?.name);
138 |     const phaseDescription = String(request.params.arguments?.description);
139 |     const tasks = JSON.parse(String(request.params.arguments?.tasks || "[]"));
140 |     
141 |     const feature = features[featureId];
142 |     if (!feature) {
143 |       throw new Error("Feature not found");
144 |     }
145 |     
146 |     const phaseId = generateId();
147 |     feature.phases.push({
148 |       id: phaseId,
149 |       name: phaseName,
150 |       description: phaseDescription,
151 |       tasks: tasks.map((task: string) => ({ description: task, completed: false })),
152 |       status: "pending"
153 |     });
154 |     
155 |     return {
156 |       content: [{
157 |         type: "text",
158 |         text: `Phase "${phaseName}" created with ID: ${phaseId}`
159 |       }]
160 |     };
161 |   }
162 |   
163 |   // Handle other tools...
164 | });
165 | ```
166 | 
167 | ### Step 5: Resource Implementation
168 | 
169 | Implement resources to retrieve feature data, PRDs, and implementation plans:
170 | 
171 | 1. Create resources for listing all features
172 | 2. Add resources for accessing feature details
173 | 3. Implement resources for retrieving PRDs and implementation plans
174 | 
175 | ```typescript
176 | // Handler for listing available features as resources
177 | server.setRequestHandler(ListResourcesRequestSchema, async () => {
178 |   return {
179 |     resources: [
180 |       {
181 |         uri: "features://list",
182 |         mimeType: "text/plain",
183 |         name: "Features List",
184 |         description: "Lists all features being developed"
185 |       },
186 |       ...Object.values(features).flatMap(feature => [
187 |         {
188 |           uri: `feature://${feature.id}`,
189 |           mimeType: "text/plain", 
190 |           name: feature.name,
191 |           description: `Details about feature: ${feature.name}`
192 |         },
193 |         {
194 |           uri: `feature://${feature.id}/prd`,
195 |           mimeType: "text/markdown",
196 |           name: `${feature.name} PRD`,
197 |           description: `PRD document for feature: ${feature.name}`
198 |         },
199 |         {
200 |           uri: `feature://${feature.id}/implementation`,
201 |           mimeType: "text/markdown",
202 |           name: `${feature.name} Implementation Plan`,
203 |           description: `Implementation plan for feature: ${feature.name}`
204 |         }
205 |       ])
206 |     ]
207 |   };
208 | });
209 | 
210 | // Handler for reading feature resources
211 | server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
212 |   const url = new URL(request.params.uri);
213 |   
214 |   // Handle various resource types...
215 |   if (url.protocol === "features:") {
216 |     if (url.pathname === "/list") {
217 |       return {
218 |         contents: [{
219 |           uri: request.params.uri,
220 |           mimeType: "text/plain",
221 |           text: Object.values(features).map(f => `${f.id}: ${f.name}`).join("\n")
222 |         }]
223 |       };
224 |     }
225 |   }
226 |   
227 |   if (url.protocol === "feature:") {
228 |     const parts = url.pathname.split('/').filter(Boolean);
229 |     const featureId = parts[0];
230 |     const feature = features[featureId];
231 |     
232 |     if (!feature) {
233 |       throw new Error(`Feature ${featureId} not found`);
234 |     }
235 |     
236 |     if (parts.length === 1) {
237 |       // Return feature details
238 |       return {
239 |         contents: [{
240 |           uri: request.params.uri,
241 |           mimeType: "text/plain",
242 |           text: formatFeatureDetails(feature)
243 |         }]
244 |       };
245 |     }
246 |     
247 |     if (parts[1] === "prd") {
248 |       return {
249 |         contents: [{
250 |           uri: request.params.uri,
251 |           mimeType: "text/markdown",
252 |           text: feature.prdDoc || "PRD not yet generated"
253 |         }]
254 |       };
255 |     }
256 |     
257 |     // Handle other resource types...
258 |   }
259 |   
260 |   throw new Error("Resource not found");
261 | });
262 | ```
263 | 
264 | ### Step 6: Tool Implementation
265 | 
266 | Expose the main tools for interacting with the Vibe-Coder MCP server:
267 | 
268 | ```typescript
269 | server.setRequestHandler(ListToolsRequestSchema, async () => {
270 |   return {
271 |     tools: [
272 |       {
273 |         name: "start_feature_clarification",
274 |         description: "Start the clarification process for a new feature",
275 |         inputSchema: {
276 |           type: "object",
277 |           properties: {
278 |             featureName: {
279 |               type: "string",
280 |               description: "Name of the feature"
281 |             },
282 |             initialDescription: {
283 |               type: "string",
284 |               description: "Initial description of the feature"
285 |             }
286 |           },
287 |           required: ["featureName"]
288 |         }
289 |       },
290 |       {
291 |         name: "provide_clarification",
292 |         description: "Provide answer to a clarification question",
293 |         inputSchema: {
294 |           type: "object",
295 |           properties: {
296 |             featureId: {
297 |               type: "string",
298 |               description: "ID of the feature"
299 |             },
300 |             question: {
301 |               type: "string",
302 |               description: "Clarification question"
303 |             },
304 |             answer: {
305 |               type: "string",
306 |               description: "Answer to the clarification question"
307 |             }
308 |           },
309 |           required: ["featureId", "question", "answer"]
310 |         }
311 |       },
312 |       {
313 |         name: "generate_prd",
314 |         description: "Generate a PRD document based on clarification responses",
315 |         inputSchema: {
316 |           type: "object",
317 |           properties: {
318 |             featureId: {
319 |               type: "string",
320 |               description: "ID of the feature"
321 |             }
322 |           },
323 |           required: ["featureId"]
324 |         }
325 |       },
326 |       {
327 |         name: "generate_implementation_plan",
328 |         description: "Generate an implementation plan document",
329 |         inputSchema: {
330 |           type: "object",
331 |           properties: {
332 |             featureId: {
333 |               type: "string",
334 |               description: "ID of the feature"
335 |             }
336 |           },
337 |           required: ["featureId"]
338 |         }
339 |       },
340 |       {
341 |         name: "create_phase",
342 |         description: "Create a new implementation phase",
343 |         inputSchema: {
344 |           type: "object",
345 |           properties: {
346 |             featureId: {
347 |               type: "string",
348 |               description: "ID of the feature"
349 |             },
350 |             name: {
351 |               type: "string",
352 |               description: "Name of the phase"
353 |             },
354 |             description: {
355 |               type: "string",
356 |               description: "Description of the phase"
357 |             },
358 |             tasks: {
359 |               type: "string",
360 |               description: "JSON array of task descriptions"
361 |             }
362 |           },
363 |           required: ["featureId", "name", "description"]
364 |         }
365 |       },
366 |       {
367 |         name: "update_phase_status",
368 |         description: "Update the status of a phase",
369 |         inputSchema: {
370 |           type: "object",
371 |           properties: {
372 |             featureId: {
373 |               type: "string",
374 |               description: "ID of the feature"
375 |             },
376 |             phaseId: {
377 |               type: "string",
378 |               description: "ID of the phase"
379 |             },
380 |             status: {
381 |               type: "string",
382 |               description: "New status (pending, in_progress, completed, reviewed)"
383 |             }
384 |           },
385 |           required: ["featureId", "phaseId", "status"]
386 |         }
387 |       },
388 |       {
389 |         name: "update_task_status",
390 |         description: "Mark a task as completed or not completed",
391 |         inputSchema: {
392 |           type: "object",
393 |           properties: {
394 |             featureId: {
395 |               type: "string", 
396 |               description: "ID of the feature"
397 |             },
398 |             phaseId: {
399 |               type: "string",
400 |               description: "ID of the phase"
401 |             },
402 |             taskIndex: {
403 |               type: "number",
404 |               description: "Index of the task"
405 |             },
406 |             completed: {
407 |               type: "boolean",
408 |               description: "Whether the task is completed"
409 |             }
410 |           },
411 |           required: ["featureId", "phaseId", "taskIndex", "completed"]
412 |         }
413 |       }
414 |     ]
415 |   };
416 | });
417 | ```
418 | 
419 | ### Step 7: Prompt Implementation
420 | 
421 | Create prompts to guide users through the development workflow:
422 | 
423 | ```typescript
424 | server.setRequestHandler(ListPromptsRequestSchema, async () => {
425 |   return {
426 |     prompts: [
427 |       {
428 |         name: "clarify_feature",
429 |         description: "Guide to clarify a feature request through questioning"
430 |       },
431 |       {
432 |         name: "generate_prd_template",
433 |         description: "Guide to generate a PRD document from clarifications"
434 |       },
435 |       {
436 |         name: "phase_implementation_guide",
437 |         description: "Guide for implementing a development phase"
438 |       }
439 |     ]
440 |   };
441 | });
442 | 
443 | server.setRequestHandler(GetPromptRequestSchema, async (request) => {
444 |   if (request.params.name === "clarify_feature") {
445 |     return {
446 |       messages: [
447 |         {
448 |           role: "user",
449 |           content: {
450 |             type: "text",
451 |             text: "Help me clarify this feature request by asking questions about:"
452 |           }
453 |         },
454 |         {
455 |           role: "user",
456 |           content: {
457 |             type: "text",
458 |             text: "1. The specific problem it solves\n2. The target users\n3. Key requirements\n4. Success criteria\n5. Technical constraints\n\nAsk one question at a time, analyze the response, then proceed to the next most relevant question."
459 |           }
460 |         }
461 |       ]
462 |     };
463 |   }
464 |   
465 |   // Handle other prompts...
466 | });
467 | ```
468 | 
469 | ## Helper Functions to Implement
470 | 
471 | Here are the core helper functions needed for the implementation:
472 | 
473 | ```typescript
474 | // Generate unique IDs
475 | function generateId(): string {
476 |   return Math.random().toString(36).substring(2, 15);
477 | }
478 | 
479 | // Format feature details for display
480 | function formatFeatureDetails(feature: Feature): string {
481 |   return `
482 | Feature: ${feature.name}
483 | ID: ${feature.id}
484 | Description: ${feature.description}
485 | 
486 | Clarification Responses:
487 | ${feature.clarificationResponses.map(cr => `Q: ${cr.question}\nA: ${cr.answer}`).join('\n\n')}
488 | 
489 | Phases (${feature.phases.length}):
490 | ${feature.phases.map(p => `- ${p.name} (${p.status}): ${p.tasks.filter(t => t.completed).length}/${p.tasks.length} tasks completed`).join('\n')}
491 | `;
492 | }
493 | 
494 | // Generate PRD document
495 | function generatePRD(feature: Feature): string {
496 |   const clarifications = feature.clarificationResponses;
497 |   
498 |   return `# ${feature.name} PRD
499 | 
500 | ## 1. Introduction
501 | 
502 | ${feature.description}
503 | 
504 | ## 2. Feature Objectives
505 | 
506 | ${extractObjectivesFromClarifications(clarifications)}
507 | 
508 | ## 3. Scope and Requirements
509 | 
510 | ${extractRequirementsFromClarifications(clarifications)}
511 | 
512 | ## 4. High-Level Implementation Overview
513 | 
514 | To be determined based on the implementation plan.
515 | 
516 | ## 5. Feedback and Iteration Process
517 | 
518 | This PRD will be updated as the implementation progresses and feedback is received.
519 | `;
520 | }
521 | 
522 | // Generate implementation plan
523 | function generateImplementationPlan(feature: Feature): string {
524 |   // Similar to PRD generation, but creating an implementation plan
525 |   // ...
526 | }
527 | 
528 | // Extract objectives from clarification responses
529 | function extractObjectivesFromClarifications(responses: ClarificationResponse[]): string {
530 |   // Logic to extract objectives based on responses to clarification questions
531 |   // ...
532 | }
533 | 
534 | // Extract requirements from clarification responses
535 | function extractRequirementsFromClarifications(responses: ClarificationResponse[]): string {
536 |   // Logic to extract requirements based on responses to clarification questions
537 |   // ...
538 | }
539 | ```
540 | 
541 | ## File Structure
542 | 
543 | The implementation will be organized as follows:
544 | 
545 | ```
546 | src/
547 |   ├── index.ts               # Main server entry point
548 |   ├── types.ts               # Type definitions
549 |   ├── storage.ts             # Feature storage management
550 |   ├── clarification.ts       # Clarification workflow logic
551 |   ├── documentation.ts       # PRD and implementation plan generation
552 |   ├── phases.ts              # Phase and task management
553 |   ├── utils.ts               # Helper utilities
554 |   ├── handlers/              # MCP request handlers
555 |   │   ├── resources.ts       # Resource request handlers
556 |   │   ├── tools.ts           # Tool request handlers
557 |   │   └── prompts.ts         # Prompt request handlers
558 |   └── templates/             # Documentation templates
559 |       ├── prd-template.md    # PRD document template
560 |       └── impl-template.md   # Implementation plan template
561 | ```
562 | 
563 | ## Implementation Timeline
564 | 
565 | 1. **Week 1**: Set up core server structure and data models
566 | 2. **Week 2**: Implement feature clarification workflow
567 | 3. **Week 3**: Build PRD and implementation plan generation
568 | 4. **Week 4**: Develop phase management functionality
569 | 5. **Week 5**: Complete resources and refinements
570 | 6. **Week 6**: Testing and documentation
571 | 
572 | ## Next Steps
573 | 
574 | 1. Start by modifying the existing server to match the Vibe-Coder requirements
575 | 2. Implement the core data structures and storage
576 | 3. Build feature clarification tools and resources
577 | 4. Add document generation capabilities
578 | 5. Implement phase management tools
579 | 6. Complete integration with MCP 
```

--------------------------------------------------------------------------------
/src/mcp-server.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | 
  3 | /**
  4 |  * @file Vibe-Coder MCP Server
  5 |  * @version 0.3.0
  6 |  * @status STABLE - DO NOT MODIFY WITHOUT TESTS
  7 |  * @lastModified 2023-03-23
  8 |  * 
  9 |  * This MCP server implements a structured development workflow that helps
 10 |  * LLM-based coders build features in an organized, clean, and safe manner.
 11 |  * 
 12 |  * IMPORTANT:
 13 |  * - Test any modifications thoroughly
 14 |  * - Maintain backward compatibility
 15 |  * 
 16 |  * Functionality:
 17 |  * - Feature request clarification through iterative questioning
 18 |  * - PRD and implementation plan generation
 19 |  * - Phased development with tasks and status tracking
 20 |  */
 21 | 
 22 | import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
 23 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
 24 | import { z } from "zod";
 25 | 
 26 | // Import core modules
 27 | import { Feature, Phase, Task, ClarificationResponse, PhaseStatus } from './types.js';
 28 | import { getFeature, updateFeature, listFeatures } from './storage.js';
 29 | import { 
 30 |   getNextClarificationQuestion, 
 31 |   addClarificationResponse,
 32 |   formatClarificationResponses,
 33 |   isClarificationComplete
 34 | } from './clarification.js';
 35 | import { generatePRD, generateImplementationPlan } from './documentation.js';
 36 | import { createFeatureObject, generateFeatureProgressSummary, createPhaseObject, createTaskObject, now } from './utils.js';
 37 | import { documentStorage, DocumentType } from './document-storage.js';
 38 | 
 39 | /**
 40 |  * Create an MCP server
 41 |  */
 42 | const server = new McpServer({
 43 |   name: "Vibe-Coder",
 44 |   version: "0.3.0"
 45 | });
 46 | 
 47 | // --------- Helper Functions ---------
 48 | 
 49 | /**
 50 |  * Create a new phase for a feature directly
 51 |  */
 52 | function createPhaseDirectly(feature: Feature, name: string, description: string): Phase {
 53 |   const newPhase = createPhaseObject(name, description);
 54 |   feature.phases.push(newPhase);
 55 |   feature.updatedAt = new Date();
 56 |   return newPhase;
 57 | }
 58 | 
 59 | /**
 60 |  * Update phase status directly
 61 |  */
 62 | function updatePhaseStatusDirectly(feature: Feature, phaseId: string, status: PhaseStatus): void {
 63 |   const phase = feature.phases.find(p => p.id === phaseId);
 64 |   if (!phase) {
 65 |     throw new Error(`Phase ${phaseId} not found`);
 66 |   }
 67 |   
 68 |   phase.status = status;
 69 |   phase.updatedAt = now();
 70 |   feature.updatedAt = now();
 71 | }
 72 | 
 73 | /**
 74 |  * Add task directly
 75 |  */
 76 | function addTaskDirectly(feature: Feature, phaseId: string, description: string): Task {
 77 |   const phase = feature.phases.find(p => p.id === phaseId);
 78 |   if (!phase) {
 79 |     throw new Error(`Phase ${phaseId} not found`);
 80 |   }
 81 |   
 82 |   const newTask = createTaskObject(description);
 83 |   
 84 |   // Convert task ID to string to ensure it's not an object
 85 |   if (typeof newTask.id !== 'string') {
 86 |     newTask.id = String(newTask.id);
 87 |   }
 88 |   
 89 |   phase.tasks.push(newTask);
 90 |   phase.updatedAt = now();
 91 |   feature.updatedAt = now();
 92 |   return newTask;
 93 | }
 94 | 
 95 | /**
 96 |  * Update task status directly
 97 |  */
 98 | function updateTaskStatusDirectly(feature: Feature, phaseId: string, taskId: string, completed: boolean): void {
 99 |   const phase = feature.phases.find(p => p.id === phaseId);
100 |   if (!phase) {
101 |     throw new Error(`Phase ${phaseId} not found`);
102 |   }
103 |   
104 |   const task = phase.tasks.find(t => t.id === taskId);
105 |   if (!task) {
106 |     throw new Error(`Task ${taskId} not found`);
107 |   }
108 |   
109 |   task.completed = completed;
110 |   task.updatedAt = now();
111 |   phase.updatedAt = now();
112 |   feature.updatedAt = now();
113 | }
114 | 
115 | // --------- Register Resources ---------
116 | 
117 | // Features list resource
118 | server.resource(
119 |   "features-list",
120 |   "features://list",
121 |   async (uri) => ({
122 |     contents: [{
123 |       uri: uri.href,
124 |       text: listFeatures().map(f => `${f.id}: ${f.name}`).join("\n")
125 |     }]
126 |   })
127 | );
128 | 
129 | // Features status resource
130 | server.resource(
131 |   "features-status",
132 |   "features://status",
133 |   async (uri) => {
134 |     const features = listFeatures();
135 |     
136 |     if (features.length === 0) {
137 |       return {
138 |         contents: [{
139 |           uri: uri.href,
140 |           text: "# Project Status\n\nNo features have been created yet."
141 |         }]
142 |       };
143 |     }
144 |     
145 |     const featuresStatus = features.map(feature => {
146 |       const totalPhases = feature.phases.length;
147 |       const completedPhases = feature.phases.filter(p => p.status === 'completed' || p.status === 'reviewed').length;
148 |       const totalTasks = feature.phases.reduce((acc, phase) => acc + phase.tasks.length, 0);
149 |       const completedTasks = feature.phases.reduce(
150 |         (acc, phase) => acc + phase.tasks.filter(t => t.completed).length, 0
151 |       );
152 |       
153 |       return `## ${feature.name}
154 | - ID: ${feature.id}
155 | - Status: ${completedPhases === totalPhases && totalPhases > 0 ? 'Completed' : 'In Progress'}
156 | - Phases: ${completedPhases}/${totalPhases} completed
157 | - Tasks: ${completedTasks}/${totalTasks} completed
158 | - [View Details](feature://${feature.id}/progress)
159 | `;
160 |     }).join('\n');
161 |     
162 |     return {
163 |       contents: [{
164 |         uri: uri.href,
165 |         text: `# Project Status\n\n${featuresStatus}`
166 |       }]
167 |     };
168 |   }
169 | );
170 | 
171 | // Feature detail resource with parameter
172 | server.resource(
173 |   "feature-detail",
174 |   new ResourceTemplate("feature://{featureId}", { list: undefined }),
175 |   async (uri, { featureId }) => {
176 |     const feature = getFeature(featureId as string);
177 |     
178 |     if (!feature) {
179 |       throw new Error(`Feature ${featureId} not found`);
180 |     }
181 |     
182 |     const timestamp = feature.updatedAt.toISOString();
183 |     const clarifications = formatClarificationResponses(feature.clarificationResponses);
184 |     const phasesText = feature.phases.map(p => 
185 |       `- ${p.name} (${p.status}): ${p.tasks.filter(t => t.completed).length}/${p.tasks.length} tasks completed`
186 |     ).join('\n');
187 |     
188 |     const featureDetails = `
189 | Feature: ${feature.name}
190 | ID: ${feature.id}
191 | Description: ${feature.description}
192 | Last Updated: ${timestamp}
193 | 
194 | Clarification Responses:
195 | ${clarifications}
196 | 
197 | Phases (${feature.phases.length}):
198 | ${phasesText}
199 | `;
200 |     
201 |     return {
202 |       contents: [{
203 |         uri: uri.href,
204 |         text: featureDetails
205 |       }]
206 |     };
207 |   }
208 | );
209 | 
210 | // Feature progress resource
211 | server.resource(
212 |   "feature-progress",
213 |   new ResourceTemplate("feature://{featureId}/progress", { list: undefined }),
214 |   async (uri, { featureId }) => {
215 |     const feature = getFeature(featureId as string);
216 |     
217 |     if (!feature) {
218 |       throw new Error(`Feature ${featureId} not found`);
219 |     }
220 |     
221 |     const progressReport = generateFeatureProgressSummary(feature);
222 |     
223 |     return {
224 |       contents: [{
225 |         uri: uri.href,
226 |         text: progressReport
227 |       }]
228 |     };
229 |   }
230 | );
231 | 
232 | // Feature PRD resource
233 | server.resource(
234 |   "feature-prd",
235 |   new ResourceTemplate("feature://{featureId}/prd", { list: undefined }),
236 |   async (uri, { featureId }) => {
237 |     const feature = getFeature(featureId as string);
238 |     
239 |     if (!feature) {
240 |       throw new Error(`Feature ${featureId} not found`);
241 |     }
242 |     
243 |     if (!isClarificationComplete(feature)) {
244 |       return {
245 |         contents: [{
246 |           uri: uri.href,
247 |           text: "# PRD Not Available\n\nThe clarification process is not complete. Please answer all clarification questions first."
248 |         }]
249 |       };
250 |     }
251 |     
252 |     const prd = generatePRD(feature);
253 |     
254 |     return {
255 |       contents: [{
256 |         uri: uri.href,
257 |         text: prd
258 |       }]
259 |     };
260 |   }
261 | );
262 | 
263 | // Feature implementation plan resource
264 | server.resource(
265 |   "feature-implementation-plan",
266 |   new ResourceTemplate("feature://{featureId}/implementation", { list: undefined }),
267 |   async (uri, { featureId }) => {
268 |     const feature = getFeature(featureId as string);
269 |     
270 |     if (!feature) {
271 |       throw new Error(`Feature ${featureId} not found`);
272 |     }
273 |     
274 |     if (!isClarificationComplete(feature)) {
275 |       return {
276 |         contents: [{
277 |           uri: uri.href,
278 |           text: "# Implementation Plan Not Available\n\nThe clarification process is not complete. Please answer all clarification questions first."
279 |         }]
280 |       };
281 |     }
282 |     
283 |     const implementationPlan = generateImplementationPlan(feature);
284 |     
285 |     return {
286 |       contents: [{
287 |         uri: uri.href,
288 |         text: implementationPlan
289 |       }]
290 |     };
291 |   }
292 | );
293 | 
294 | // --------- Register Tools ---------
295 | 
296 | // Start feature clarification tool
297 | server.tool(
298 |   "start_feature_clarification",
299 |   { 
300 |     featureName: z.string().min(2).max(100),
301 |     initialDescription: z.string().optional().default("")
302 |   },
303 |   async ({ featureName, initialDescription }) => {
304 |     // Create a new feature
305 |     const feature = createFeatureObject(featureName, initialDescription);
306 |     updateFeature(feature.id, feature);
307 |     
308 |     // Get the first clarification question
309 |     const firstQuestion = getNextClarificationQuestion(feature);
310 |     
311 |     return {
312 |       content: [{
313 |         type: "text",
314 |         text: `Feature ID: ${feature.id}\n\nLet's clarify your feature request. ${firstQuestion}`
315 |       }]
316 |     };
317 |   }
318 | );
319 | 
320 | // Provide clarification tool
321 | server.tool(
322 |   "provide_clarification",
323 |   {
324 |     featureId: z.string().min(1),
325 |     question: z.string().min(1),
326 |     answer: z.string().min(1)
327 |   },
328 |   async ({ featureId, question, answer }) => {
329 |     // Get the feature
330 |     const feature = getFeature(featureId);
331 |     if (!feature) {
332 |       throw new Error(`Feature ${featureId} not found`);
333 |     }
334 |     
335 |     // Add the clarification response to the feature
336 |     feature.clarificationResponses.push({
337 |       question,
338 |       answer,
339 |       timestamp: new Date()
340 |     });
341 |     
342 |     // Save the feature with the updated clarification response
343 |     updateFeature(featureId, feature);
344 |     
345 |     // Get the next question or indicate all questions are answered
346 |     const nextQuestion = getNextClarificationQuestion(feature);
347 |     
348 |     if (nextQuestion) {
349 |       return {
350 |         content: [{
351 |           type: "text",
352 |           text: `Response recorded. ${nextQuestion}`
353 |         }]
354 |       };
355 |     } else {
356 |       // All questions answered
357 |       return {
358 |         content: [{
359 |           type: "text",
360 |           text: "All clarification questions have been answered. You can now generate a PRD for this feature."
361 |         }]
362 |       };
363 |     }
364 |   }
365 | );
366 | 
367 | // Generate PRD tool
368 | server.tool(
369 |   "generate_prd",
370 |   {
371 |     featureId: z.string().min(1)
372 |   },
373 |   async ({ featureId }) => {
374 |     const feature = getFeature(featureId);
375 |     if (!feature) {
376 |       throw new Error(`Feature ${featureId} not found`);
377 |     }
378 |     
379 |     if (!isClarificationComplete(feature)) {
380 |       throw new Error("Clarification process not complete. Please answer all clarification questions.");
381 |     }
382 |     
383 |     const prd = generatePRD(feature);
384 |     feature.prd = prd;
385 |     updateFeature(featureId, feature);
386 |     
387 |     return {
388 |       content: [{
389 |         type: "text",
390 |         text: `PRD generated successfully for "${feature.name}". You can view it at feature://${featureId}/prd`
391 |       }]
392 |     };
393 |   }
394 | );
395 | 
396 | // Create phase tool
397 | server.tool(
398 |   "create_phase",
399 |   {
400 |     featureId: z.string().min(1),
401 |     name: z.string().min(1),
402 |     description: z.string().min(1)
403 |   },
404 |   async ({ featureId, name, description }) => {
405 |     const feature = getFeature(featureId);
406 |     if (!feature) {
407 |       throw new Error(`Feature ${featureId} not found`);
408 |     }
409 |     
410 |     const phase = createPhaseDirectly(feature, name, description);
411 |     updateFeature(featureId, feature);
412 |     
413 |     return {
414 |       content: [{
415 |         type: "text",
416 |         text: `Created phase "${name}" with ID ${phase.id} for feature "${feature.name}"`
417 |       }]
418 |     };
419 |   }
420 | );
421 | 
422 | // Update phase status tool
423 | server.tool(
424 |   "update_phase_status",
425 |   {
426 |     featureId: z.string().min(1),
427 |     phaseId: z.string().min(1),
428 |     status: z.enum(["pending", "in_progress", "completed", "reviewed"])
429 |   },
430 |   async ({ featureId, phaseId, status }) => {
431 |     const feature = getFeature(featureId);
432 |     if (!feature) {
433 |       throw new Error(`Feature ${featureId} not found`);
434 |     }
435 |     
436 |     const phase = feature.phases.find(p => p.id === phaseId);
437 |     if (!phase) {
438 |       throw new Error(`Phase ${phaseId} not found in feature ${featureId}`);
439 |     }
440 |     
441 |     const oldStatus = phase.status;
442 |     updatePhaseStatusDirectly(feature, phaseId, status);
443 |     updateFeature(featureId, feature);
444 |     
445 |     return {
446 |       content: [{
447 |         type: "text",
448 |         text: `Updated phase "${phase.name}" status from "${oldStatus}" to "${status}"`
449 |       }]
450 |     };
451 |   }
452 | );
453 | 
454 | // Add task tool
455 | server.tool(
456 |   "add_task",
457 |   {
458 |     featureId: z.string().min(1),
459 |     phaseId: z.string().min(1),
460 |     description: z.string().min(1)
461 |   },
462 |   async ({ featureId, phaseId, description }) => {
463 |     const feature = getFeature(featureId);
464 |     if (!feature) {
465 |       throw new Error(`Feature ${featureId} not found`);
466 |     }
467 |     
468 |     const phase = feature.phases.find(p => p.id === phaseId);
469 |     if (!phase) {
470 |       throw new Error(`Phase ${phaseId} not found in feature ${featureId}`);
471 |     }
472 |     
473 |     const task = addTaskDirectly(feature, phaseId, description);
474 |     updateFeature(featureId, feature);
475 |     
476 |     // Debug log
477 |     console.error(`DEBUG: Task created with ID: ${task.id}, type: ${typeof task.id}`);
478 |     console.error(`DEBUG: Task object: ${JSON.stringify(task)}`);
479 |     
480 |     // Ensure task.id is explicitly converted to string and check if it's an object
481 |     let taskId: string;
482 |     
483 |     if (typeof task.id === 'object') {
484 |       taskId = JSON.stringify(task.id);
485 |     } else {
486 |       taskId = String(task.id);
487 |     }
488 |     
489 |     return {
490 |       content: [{
491 |         type: "text",
492 |         text: `Added task "${description.substring(0, 30)}${description.length > 30 ? '...' : ''}" with ID: ${taskId} to phase "${phase.name}"`
493 |       }]
494 |     };
495 |   }
496 | );
497 | 
498 | // Update task status tool
499 | server.tool(
500 |   "update_task_status",
501 |   {
502 |     featureId: z.string().min(1),
503 |     phaseId: z.string().min(1),
504 |     taskId: z.string().min(1),
505 |     completed: z.boolean()
506 |   },
507 |   async ({ featureId, phaseId, taskId, completed }) => {
508 |     const feature = getFeature(featureId);
509 |     if (!feature) {
510 |       throw new Error(`Feature ${featureId} not found`);
511 |     }
512 |     
513 |     const phase = feature.phases.find(p => p.id === phaseId);
514 |     if (!phase) {
515 |       throw new Error(`Phase ${phaseId} not found in feature ${featureId}`);
516 |     }
517 |     
518 |     const task = phase.tasks.find(t => t.id === taskId);
519 |     if (!task) {
520 |       throw new Error(`Task ${taskId} not found in phase ${phaseId}`);
521 |     }
522 |     
523 |     updateTaskStatusDirectly(feature, phaseId, taskId, completed);
524 |     updateFeature(featureId, feature);
525 |     
526 |     return {
527 |       content: [{
528 |         type: "text",
529 |         text: `Updated task "${task.description.substring(0, 30)}${task.description.length > 30 ? '...' : ''}" status to ${completed ? 'completed' : 'not completed'}`
530 |       }]
531 |     };
532 |   }
533 | );
534 | 
535 | // Get next phase action tool
536 | server.tool(
537 |   "get_next_phase_action",
538 |   {
539 |     featureId: z.string().min(1)
540 |   },
541 |   async ({ featureId }) => {
542 |     const feature = getFeature(featureId);
543 |     if (!feature) {
544 |       throw new Error(`Feature ${featureId} not found`);
545 |     }
546 |     
547 |     // Check if we need implementation plan first
548 |     if (!feature.implementationPlan) {
549 |       return {
550 |         content: [{
551 |           type: "text",
552 |           text: "You should generate an implementation plan before creating phases."
553 |         }]
554 |       };
555 |     }
556 |     
557 |     // If no phases, suggest creating first phase
558 |     if (feature.phases.length === 0) {
559 |       return {
560 |         content: [{
561 |           type: "text",
562 |           text: "You should create the first development phase based on the implementation plan."
563 |         }]
564 |       };
565 |     }
566 |     
567 |     // Find the current active phase (the first non-completed phase)
568 |     const currentPhase = feature.phases.find(p => p.status !== 'completed' && p.status !== 'reviewed');
569 |     
570 |     if (!currentPhase) {
571 |       return {
572 |         content: [{
573 |           type: "text",
574 |           text: "All phases are complete. You should mark the final phase as reviewed."
575 |         }]
576 |       };
577 |     }
578 |     
579 |     // Check if all tasks in the phase are completed
580 |     const allTasksCompleted = currentPhase.tasks.every(t => t.completed);
581 |     
582 |     if (currentPhase.tasks.length === 0) {
583 |       return {
584 |         content: [{
585 |           type: "text",
586 |           text: `Current phase "${currentPhase.name}" has no tasks. You should add tasks based on the implementation plan.`
587 |         }]
588 |       };
589 |     } else if (!allTasksCompleted) {
590 |       const pendingTasks = currentPhase.tasks.filter(t => !t.completed);
591 |       
592 |       return {
593 |         content: [{
594 |           type: "text",
595 |           text: `Current phase "${currentPhase.name}" has ${pendingTasks.length} incomplete tasks. Complete these tasks before moving to the next phase.`
596 |         }]
597 |       };
598 |     } else {
599 |       return {
600 |         content: [{
601 |           type: "text",
602 |           text: `All tasks in the current phase "${currentPhase.name}" are complete. You can now mark this phase as completed and proceed to the next phase.`
603 |         }]
604 |       };
605 |     }
606 |   }
607 | );
608 | 
609 | // Define prompt for feature planning
610 | server.prompt(
611 |   "feature-planning",
612 |   { 
613 |     featureId: z.string() 
614 |   },
615 |   ({ featureId }) => ({
616 |     messages: [{
617 |       role: "user",
618 |       content: {
619 |         type: "text",
620 |         text: `I need to plan the development of feature with ID ${featureId}. Please help me:
621 | 1. Understand what the feature is about
622 | 2. Break down the feature into development phases 
623 | 3. Create tasks for each phase
624 | 4. Track progress through completion`
625 |       }
626 |     }]
627 |   })
628 | );
629 | 
630 | // Document path tool
631 | server.tool(
632 |   "get_document_path",
633 |   {
634 |     featureId: z.string().min(1),
635 |     documentType: z.string().min(1)
636 |   },
637 |   async ({ featureId, documentType }) => {
638 |     try {
639 |       // Check if the feature exists
640 |       const feature = getFeature(featureId);
641 |       if (!feature) {
642 |         throw new Error(`Feature ${featureId} not found`);
643 |       }
644 |       
645 |       // Map the string to DocumentType enum
646 |       let docType: DocumentType;
647 |       if (documentType === 'prd') {
648 |         docType = DocumentType.PRD;
649 |       } else if (documentType === 'implementation-plan') {
650 |         docType = DocumentType.IMPLEMENTATION_PLAN;
651 |       } else {
652 |         throw new Error(`Invalid document type: ${documentType}. Expected 'prd' or 'implementation-plan'`);
653 |       }
654 |       
655 |       // Check if the document exists
656 |       if (!documentStorage.hasDocument(feature.id, docType)) {
657 |         throw new Error(`Document of type ${documentType} not found for feature ${feature.id}`);
658 |       }
659 |       
660 |       // Get the default file path for the document
661 |       const filePath = documentStorage.getDefaultFilePath(feature.id, docType);
662 |       
663 |       // Get the document to check if it's been saved
664 |       const document = documentStorage.getDocument(feature.id, docType);
665 |       
666 |       return {
667 |         content: [{
668 |           type: "text",
669 |           text: `Document path: ${filePath}\nSaved to disk: ${document?.metadata.isSaved ? 'Yes' : 'No'}`
670 |         }]
671 |       };
672 |     } catch (error) {
673 |       return {
674 |         content: [{
675 |           type: "text",
676 |           text: `Error retrieving document path: ${error instanceof Error ? error.message : String(error)}`
677 |         }],
678 |         isError: true
679 |       };
680 |     }
681 |   }
682 | );
683 | 
684 | // Document save tool
685 | server.tool(
686 |   "save_document",
687 |   {
688 |     featureId: z.string().min(1),
689 |     documentType: z.string().min(1),
690 |     filePath: z.string().min(1).optional()
691 |   },
692 |   async ({ featureId, documentType, filePath }) => {
693 |     try {
694 |       // Check if the feature exists
695 |       const feature = getFeature(featureId);
696 |       if (!feature) {
697 |         throw new Error(`Feature ${featureId} not found`);
698 |       }
699 |       
700 |       // Map the string to DocumentType enum
701 |       let docType: DocumentType;
702 |       if (documentType === 'prd') {
703 |         docType = DocumentType.PRD;
704 |       } else if (documentType === 'implementation-plan') {
705 |         docType = DocumentType.IMPLEMENTATION_PLAN;
706 |       } else {
707 |         throw new Error(`Invalid document type: ${documentType}. Expected 'prd' or 'implementation-plan'`);
708 |       }
709 |       
710 |       // Check if the document exists
711 |       if (!documentStorage.hasDocument(feature.id, docType)) {
712 |         throw new Error(`Document of type ${documentType} not found for feature ${feature.id}`);
713 |       }
714 |       
715 |       let savedPath: string;
716 |       
717 |       // If a custom path was provided, use it; otherwise, save to the default path
718 |       if (filePath) {
719 |         savedPath = await documentStorage.saveDocumentToCustomPath(feature.id, docType, filePath);
720 |       } else {
721 |         savedPath = await documentStorage.saveDocumentToFile(feature.id, docType);
722 |       }
723 |       
724 |       return {
725 |         content: [{
726 |           type: "text",
727 |           text: `Document saved successfully to: ${savedPath}`
728 |         }]
729 |       };
730 |     } catch (error) {
731 |       return {
732 |         content: [{
733 |           type: "text",
734 |           text: `Error saving document: ${error instanceof Error ? error.message : String(error)}`
735 |         }],
736 |         isError: true
737 |       };
738 |     }
739 |   }
740 | );
741 | 
742 | // Start the server
743 | async function main() {
744 |   console.error("Starting Vibe-Coder MCP Server...");
745 |   const transport = new StdioServerTransport();
746 |   await server.connect(transport);
747 | }
748 | 
749 | main().catch(error => {
750 |   console.error("Error in Vibe-Coder MCP Server:", error);
751 |   process.exit(1);
752 | }); 
```

--------------------------------------------------------------------------------
/src/tool-handlers.ts:
--------------------------------------------------------------------------------

```typescript
  1 | /**
  2 |  * @file tool-handlers.ts
  3 |  * @version 1.0.0
  4 |  * 
  5 |  * Provides handlers for the MCP tools exposed by the Vibe-Coder MCP Server.
  6 |  * These handlers are registered with the tool registry for consistent handling.
  7 |  */
  8 | 
  9 | import { z } from 'zod';
 10 | import { ToolHandler, toolRegistry } from './registry.js';
 11 | import { getFeature, updateFeature } from './storage.js';
 12 | import { 
 13 |   getNextClarificationQuestion,
 14 |   isClarificationComplete, 
 15 |   getClarificationStatus 
 16 | } from './clarification.js';
 17 | import { 
 18 |   generatePRD, 
 19 |   generateImplementationPlan 
 20 | } from './documentation.js';
 21 | import {
 22 |   createPhase,
 23 |   updatePhaseStatus,
 24 |   addTask,
 25 |   updateTaskStatus
 26 | } from './phases.js';
 27 | import {
 28 |   createFeatureObject
 29 | } from './utils.js';
 30 | import {
 31 |   validateFeatureId,
 32 |   validatePhaseId,
 33 |   validateTaskId,
 34 |   validateFeaturePhaseTask,
 35 |   validateRequiredText,
 36 |   validatePhaseStatusValue
 37 | } from './validators.js';
 38 | import { 
 39 |   createToolErrorResponse, 
 40 |   featureNotFoundError, 
 41 |   phaseNotFoundError, 
 42 |   taskNotFoundError, 
 43 |   invalidPhaseTransitionError, 
 44 |   clarificationIncompleteError 
 45 | } from './errors.js';
 46 | import { Phase, Task } from './types.js';
 47 | 
 48 | // Schema for start_feature_clarification
 49 | const StartFeatureClarificationSchema = z.object({
 50 |   featureName: z.string().min(2).max(100),
 51 |   initialDescription: z.string().optional().default("")
 52 | });
 53 | 
 54 | /**
 55 |  * Start feature clarification handler
 56 |  */
 57 | const startFeatureClarificationHandler: ToolHandler<z.infer<typeof StartFeatureClarificationSchema>> = async (params) => {
 58 |   try {
 59 |     const { featureName, initialDescription } = StartFeatureClarificationSchema.parse(params);
 60 |     
 61 |     // Create a new feature
 62 |     const feature = createFeatureObject(featureName, initialDescription);
 63 |     updateFeature(feature.id, feature);
 64 |     
 65 |     // Get the first clarification question
 66 |     const firstQuestion = getNextClarificationQuestion(feature);
 67 |     
 68 |     return {
 69 |       content: [{
 70 |         type: "text",
 71 |         text: `Feature ID: ${feature.id}\n\nLet's clarify your feature request. ${firstQuestion}`
 72 |       }]
 73 |     };
 74 |   } catch (error) {
 75 |     if (error instanceof z.ZodError) {
 76 |       const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
 77 |       return createToolErrorResponse(`Validation error: ${errorMessage}`);
 78 |     }
 79 |     return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
 80 |   }
 81 | };
 82 | 
 83 | // Schema for provide_clarification
 84 | const ProvideClarificationSchema = z.object({
 85 |   featureId: z.string().min(1),
 86 |   question: z.string().min(1),
 87 |   answer: z.string().min(1)
 88 | });
 89 | 
 90 | /**
 91 |  * Provide clarification handler
 92 |  */
 93 | const provideClarificationHandler: ToolHandler<z.infer<typeof ProvideClarificationSchema>> = async (params) => {
 94 |   try {
 95 |     const { featureId, question, answer } = ProvideClarificationSchema.parse(params);
 96 |     
 97 |     console.log(`\n[CLARIFICATION] Received request for feature ${featureId}\n  Question: "${question.substring(0, 50)}..."\n  Answer: "${answer.substring(0, 50)}..."`);
 98 |     
 99 |     // Get the feature
100 |     const feature = getFeature(featureId);
101 |     if (!feature) {
102 |       console.log(`[CLARIFICATION] Feature ID ${featureId} not found`);
103 |       return featureNotFoundError(featureId);
104 |     }
105 |     
106 |     console.log(`[CLARIFICATION] Found feature: ${feature.name} with ${feature.clarificationResponses.length} existing responses`);
107 |     
108 |     // Add the clarification response to the feature
109 |     feature.clarificationResponses.push({
110 |       question,
111 |       answer,
112 |       timestamp: new Date()
113 |     });
114 |     
115 |     console.log(`[CLARIFICATION] Added response, now has ${feature.clarificationResponses.length} responses`);
116 |     
117 |     // Save the feature with the updated clarification response
118 |     updateFeature(featureId, feature);
119 |     
120 |     // Get the next question or indicate all questions are answered
121 |     const nextQuestion = getNextClarificationQuestion(feature);
122 |     
123 |     if (nextQuestion) {
124 |       // Check if nextQuestion is a string before using substring
125 |       const questionPreview = typeof nextQuestion === 'string' 
126 |         ? nextQuestion.substring(0, 50) + "..." 
127 |         : "All questions answered";
128 |       console.log(`[CLARIFICATION] Returning next question: "${questionPreview}"`);
129 |       return {
130 |         content: [{
131 |           type: "text",
132 |           text: `Response recorded. ${nextQuestion}`
133 |         }]
134 |       };
135 |     } else {
136 |       // All questions answered
137 |       console.log(`[CLARIFICATION] All questions answered`);
138 |       return {
139 |         content: [{
140 |           type: "text",
141 |           text: "All clarification questions have been answered. You can now generate a PRD for this feature."
142 |         }]
143 |       };
144 |     }
145 |   } catch (error) {
146 |     if (error instanceof z.ZodError) {
147 |       const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
148 |       return createToolErrorResponse(`Validation error: ${errorMessage}`);
149 |     }
150 |     return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
151 |   }
152 | };
153 | 
154 | // Schema for generate_prd
155 | const GeneratePrdSchema = z.object({
156 |   featureId: z.string().min(1)
157 | });
158 | 
159 | /**
160 |  * Generate PRD handler
161 |  */
162 | const generatePrdHandler: ToolHandler<z.infer<typeof GeneratePrdSchema>> = async (params) => {
163 |   try {
164 |     const { featureId } = GeneratePrdSchema.parse(params);
165 |     
166 |     // Validate feature ID
167 |     const featureResult = validateFeatureId(featureId);
168 |     if (!featureResult.valid) {
169 |       return createToolErrorResponse(featureResult.message);
170 |     }
171 |     
172 |     const feature = featureResult.data;
173 |     
174 |     // Check if clarifications are complete
175 |     if (!isClarificationComplete(feature)) {
176 |       return clarificationIncompleteError(getClarificationStatus(feature));
177 |     }
178 |     
179 |     // Generate PRD
180 |     const prdDoc = generatePRD(feature);
181 |     
182 |     // Store the document
183 |     feature.prdDoc = prdDoc;
184 |     updateFeature(featureId, feature);
185 |     
186 |     return {
187 |       content: [{
188 |         type: "text",
189 |         text: `PRD generated for feature ${feature.name}. You can view it using the resource URI: feature://${feature.id}/prd`
190 |       }]
191 |     };
192 |   } catch (error) {
193 |     if (error instanceof z.ZodError) {
194 |       const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
195 |       return createToolErrorResponse(`Validation error: ${errorMessage}`);
196 |     }
197 |     return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
198 |   }
199 | };
200 | 
201 | // Schema for generate_implementation_plan
202 | const GenerateImplementationPlanSchema = z.object({
203 |   featureId: z.string().min(1)
204 | });
205 | 
206 | /**
207 |  * Generate implementation plan handler
208 |  */
209 | const generateImplementationPlanHandler: ToolHandler<z.infer<typeof GenerateImplementationPlanSchema>> = async (params) => {
210 |   try {
211 |     const { featureId } = GenerateImplementationPlanSchema.parse(params);
212 |     
213 |     // Validate feature ID
214 |     const featureResult = validateFeatureId(featureId);
215 |     if (!featureResult.valid) {
216 |       return createToolErrorResponse(featureResult.message);
217 |     }
218 |     
219 |     const feature = featureResult.data;
220 |     
221 |     // Check if clarifications are complete
222 |     if (!isClarificationComplete(feature)) {
223 |       return clarificationIncompleteError(getClarificationStatus(feature));
224 |     }
225 |     
226 |     // Generate the implementation plan
227 |     const implDoc = generateImplementationPlan(feature);
228 |     
229 |     // Store the document
230 |     feature.implDoc = implDoc;
231 |     updateFeature(featureId, feature);
232 |     
233 |     return {
234 |       content: [{
235 |         type: "text",
236 |         text: `Implementation plan generated for feature ${feature.name}. You can view it using the resource URI: feature://${feature.id}/implementation`
237 |       }]
238 |     };
239 |   } catch (error) {
240 |     if (error instanceof z.ZodError) {
241 |       const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
242 |       return createToolErrorResponse(`Validation error: ${errorMessage}`);
243 |     }
244 |     return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
245 |   }
246 | };
247 | 
248 | // Schema for create_phase
249 | const CreatePhaseSchema = z.object({
250 |   featureId: z.string().min(1),
251 |   name: z.string().min(2).max(100),
252 |   description: z.string().min(1)
253 | });
254 | 
255 | /**
256 |  * Create phase handler
257 |  */
258 | const createPhaseHandler: ToolHandler<z.infer<typeof CreatePhaseSchema>> = async (params) => {
259 |   try {
260 |     const { featureId, name, description } = CreatePhaseSchema.parse(params);
261 |     
262 |     // Validate feature ID
263 |     const featureResult = validateFeatureId(featureId);
264 |     if (!featureResult.valid) {
265 |       return createToolErrorResponse(featureResult.message);
266 |     }
267 |     
268 |     const feature = featureResult.data;
269 |     
270 |     // Create the phase
271 |     const phase = createPhase(featureId, name, description);
272 |     
273 |     if (!phase) {
274 |       return createToolErrorResponse(`Failed to create phase for feature ${feature.name}`);
275 |     }
276 |     
277 |     return {
278 |       content: [{
279 |         type: "text",
280 |         text: `Phase "${name}" created with ID: ${phase.id}`
281 |       }]
282 |     };
283 |   } catch (error) {
284 |     if (error instanceof z.ZodError) {
285 |       const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
286 |       return createToolErrorResponse(`Validation error: ${errorMessage}`);
287 |     }
288 |     return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
289 |   }
290 | };
291 | 
292 | // Schema for update_phase_status
293 | const UpdatePhaseStatusSchema = z.object({
294 |   featureId: z.string().min(1),
295 |   phaseId: z.string().min(1),
296 |   status: z.enum(["pending", "in_progress", "completed", "reviewed"])
297 | });
298 | 
299 | /**
300 |  * Update phase status handler
301 |  */
302 | const updatePhaseStatusHandler: ToolHandler<z.infer<typeof UpdatePhaseStatusSchema>> = async (params) => {
303 |   try {
304 |     const { featureId, phaseId, status } = UpdatePhaseStatusSchema.parse(params);
305 |     
306 |     // Validate feature and phase
307 |     const validationResult = validateFeaturePhaseTask(featureId, phaseId);
308 |     if (!validationResult.valid) {
309 |       return createToolErrorResponse(validationResult.message);
310 |     }
311 |     
312 |     const { feature, phase } = validationResult.data;
313 |     
314 |     // Validate the status transition
315 |     const transitionResult = phase.status !== status; 
316 |     if (!transitionResult) {
317 |       return invalidPhaseTransitionError(phase.status, status);
318 |     }
319 |     
320 |     // Update the phase status
321 |     const updatedPhase = updatePhaseStatus(featureId, phaseId, status);
322 |     
323 |     return {
324 |       content: [{
325 |         type: "text",
326 |         text: `Phase status updated to "${status}"`
327 |       }]
328 |     };
329 |   } catch (error) {
330 |     if (error instanceof z.ZodError) {
331 |       const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
332 |       return createToolErrorResponse(`Validation error: ${errorMessage}`);
333 |     }
334 |     return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
335 |   }
336 | };
337 | 
338 | // Schema for add_task
339 | const AddTaskSchema = z.object({
340 |   featureId: z.string().min(1),
341 |   phaseId: z.string().min(1),
342 |   description: z.string().min(3).max(500)
343 | });
344 | 
345 | /**
346 |  * Add task handler
347 |  */
348 | const addTaskHandler: ToolHandler<z.infer<typeof AddTaskSchema>> = async (params) => {
349 |   try {
350 |     const { featureId, phaseId, description } = AddTaskSchema.parse(params);
351 |     
352 |     // Validate feature and phase
353 |     const validationResult = validateFeaturePhaseTask(featureId, phaseId);
354 |     if (!validationResult.valid) {
355 |       return createToolErrorResponse(validationResult.message);
356 |     }
357 |     
358 |     const { feature, phase } = validationResult.data;
359 |     
360 |     // Add the task
361 |     const taskId = addTask(featureId, phaseId, description);
362 |     
363 |     return {
364 |       content: [{
365 |         type: "text",
366 |         text: `Task added to phase "${phase.name}" with ID: ${taskId}`
367 |       }]
368 |     };
369 |   } catch (error) {
370 |     if (error instanceof z.ZodError) {
371 |       const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
372 |       return createToolErrorResponse(`Validation error: ${errorMessage}`);
373 |     }
374 |     return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
375 |   }
376 | };
377 | 
378 | // Schema for update_task_status
379 | const UpdateTaskStatusSchema = z.object({
380 |   featureId: z.string().min(1),
381 |   phaseId: z.string().min(1),
382 |   taskId: z.string().min(1),
383 |   completed: z.boolean()
384 | });
385 | 
386 | /**
387 |  * Update task status handler
388 |  */
389 | const updateTaskStatusHandler: ToolHandler<z.infer<typeof UpdateTaskStatusSchema>> = async (params) => {
390 |   try {
391 |     const { featureId, phaseId, taskId, completed } = UpdateTaskStatusSchema.parse(params);
392 |     
393 |     // Validate feature, phase and task
394 |     const validationResult = validateFeaturePhaseTask(featureId, phaseId, taskId);
395 |     if (!validationResult.valid) {
396 |       return createToolErrorResponse(validationResult.message);
397 |     }
398 |     
399 |     const { feature, phase, task } = validationResult.data;
400 |     
401 |     // Update the task status
402 |     const updatedTask = updateTaskStatus(featureId, phaseId, taskId, completed);
403 |     
404 |     // Check if all tasks in this phase are now completed
405 |     if (completed && phase.tasks.every((t: Task) => t.id === taskId || t.completed)) {
406 |       // Auto-advance the phase to 'completed' status
407 |       return {
408 |         content: [{
409 |           type: "text",
410 |           text: `Task marked as ${completed ? 'completed' : 'incomplete'}. All tasks in this phase are now complete. The phase "${phase.name}" has been automatically marked as completed.`
411 |         }]
412 |       };
413 |     }
414 |     
415 |     // Check if all tasks are completed and suggest phase update if applicable
416 |     let message = `Task status updated to ${completed ? 'completed' : 'not completed'}`;
417 |     
418 |     if (completed && phase.tasks.every((t: Task) => t.id === taskId || t.completed)) {
419 |       // All tasks are now completed
420 |       message += `. All tasks in phase ${phase.name} are now completed. Consider updating the phase status to 'completed'.`;
421 |     }
422 |     
423 |     return {
424 |       content: [{
425 |         type: "text",
426 |         text: message
427 |       }]
428 |     };
429 |   } catch (error) {
430 |     if (error instanceof z.ZodError) {
431 |       const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
432 |       return createToolErrorResponse(`Validation error: ${errorMessage}`);
433 |     }
434 |     return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
435 |   }
436 | };
437 | 
438 | // Schema for get_next_phase_action
439 | const GetNextPhaseActionSchema = z.object({
440 |   featureId: z.string().min(1)
441 | });
442 | 
443 | /**
444 |  * Get next phase action handler
445 |  */
446 | const getNextPhaseActionHandler: ToolHandler<z.infer<typeof GetNextPhaseActionSchema>> = async (params) => {
447 |   try {
448 |     const { featureId } = GetNextPhaseActionSchema.parse(params);
449 |     
450 |     // Validate feature ID
451 |     const featureResult = validateFeatureId(featureId);
452 |     if (!featureResult.valid) {
453 |       return createToolErrorResponse(featureResult.message);
454 |     }
455 |     
456 |     const feature = featureResult.data;
457 |     
458 |     // Find the current active phase (first non-completed/reviewed phase)
459 |     const currentPhase = feature.phases.find((p: Phase) => p.status === 'pending' || p.status === 'in_progress');
460 |     
461 |     if (!currentPhase) {
462 |       // All phases are completed or reviewed
463 |       return {
464 |         content: [{
465 |           type: "text",
466 |           text: 'All phases are completed or reviewed. The feature implementation is done!'
467 |         }]
468 |       };
469 |     }
470 |     
471 |     // Check task completion status
472 |     const completedTasks = currentPhase.tasks.filter((t: Task) => t.completed);
473 |     const pendingTasks = currentPhase.tasks.filter((t: Task) => !t.completed);
474 |     
475 |     // Determine next action based on phase and task status
476 |     let message = '';
477 |     
478 |     if (currentPhase.status === 'pending') {
479 |       message = `Phase "${currentPhase.name}" is pending. Start working on this phase by setting its status to "in_progress".`;
480 |     } else if (currentPhase.status === 'in_progress') {
481 |       if (pendingTasks.length > 0) {
482 |         message = `${completedTasks.length}/${currentPhase.tasks.length} tasks are completed in phase "${currentPhase.name}". Continue working on pending tasks.`;
483 |       } else if (currentPhase.tasks.length === 0) {
484 |         message = `Phase "${currentPhase.name}" has no tasks defined. Add tasks or mark the phase as completed if appropriate.`;
485 |       } else {
486 |         // All tasks are completed
487 |         message = `All tasks in phase "${currentPhase.name}" are completed. Consider marking this phase as completed.`;
488 |       }
489 |     }
490 |     
491 |     return {
492 |       content: [{
493 |         type: "text",
494 |         text: message
495 |       }]
496 |     };
497 |   } catch (error) {
498 |     if (error instanceof z.ZodError) {
499 |       const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
500 |       return createToolErrorResponse(`Validation error: ${errorMessage}`);
501 |     }
502 |     return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
503 |   }
504 | };
505 | 
506 | /**
507 |  * Register all tool handlers with the tool registry
508 |  */
509 | export function registerToolHandlers() {
510 |   toolRegistry.register(
511 |     'start_feature_clarification', 
512 |     startFeatureClarificationHandler,
513 |     'Start the clarification process for a new feature',
514 |     {
515 |       type: "object",
516 |       properties: {
517 |         featureName: {
518 |           type: "string",
519 |           description: "Name of the feature"
520 |         },
521 |         initialDescription: {
522 |           type: "string",
523 |           description: "Initial description of the feature"
524 |         }
525 |       },
526 |       required: ["featureName"]
527 |     },
528 |     [
529 |       {
530 |         featureName: "User Authentication",
531 |         initialDescription: "Add login and registration functionality to the application"
532 |       },
533 |       {
534 |         featureName: "Data Export",
535 |         initialDescription: "Allow users to export their data in CSV and JSON formats"
536 |       }
537 |     ]
538 |   );
539 | 
540 |   toolRegistry.register(
541 |     'provide_clarification', 
542 |     provideClarificationHandler,
543 |     'Provide answer to a clarification question',
544 |     {
545 |       type: "object",
546 |       properties: {
547 |         featureId: {
548 |           type: "string",
549 |           description: "ID of the feature"
550 |         },
551 |         question: {
552 |           type: "string",
553 |           description: "Clarification question"
554 |         },
555 |         answer: {
556 |           type: "string",
557 |           description: "Answer to the clarification question"
558 |         }
559 |       },
560 |       required: ["featureId", "question", "answer"]
561 |     },
562 |     [
563 |       {
564 |         featureId: "feature-123",
565 |         question: "What problem does this feature solve?",
566 |         answer: "This feature solves the problem of users forgetting their passwords by providing a secure password reset flow."
567 |       },
568 |       {
569 |         featureId: "feature-456",
570 |         question: "Who are the target users?",
571 |         answer: "The target users are administrators who need to manage user accounts and permissions."
572 |       }
573 |     ]
574 |   );
575 | 
576 |   toolRegistry.register(
577 |     'generate_prd', 
578 |     generatePrdHandler,
579 |     'Generate a PRD document based on clarification responses',
580 |     {
581 |       type: "object",
582 |       properties: {
583 |         featureId: {
584 |           type: "string",
585 |           description: "ID of the feature"
586 |         }
587 |       },
588 |       required: ["featureId"]
589 |     },
590 |     [
591 |       { featureId: "feature-123" }
592 |     ]
593 |   );
594 | 
595 |   toolRegistry.register(
596 |     'generate_implementation_plan', 
597 |     generateImplementationPlanHandler,
598 |     'Generate an implementation plan for a feature based on clarifications and PRD',
599 |     {
600 |       type: 'object',
601 |       properties: {
602 |         featureId: {
603 |           type: 'string',
604 |           description: 'The ID of the feature to generate an implementation plan for'
605 |         }
606 |       },
607 |       required: ['featureId']
608 |     }
609 |   );
610 | 
611 |   toolRegistry.register(
612 |     'create_phase', 
613 |     createPhaseHandler,
614 |     'Create a new development phase for a feature',
615 |     {
616 |       type: 'object',
617 |       properties: {
618 |         featureId: {
619 |           type: 'string',
620 |           description: 'ID of the feature to create a phase for'
621 |         },
622 |         name: {
623 |           type: 'string',
624 |           description: 'Name of the phase'
625 |         },
626 |         description: {
627 |           type: 'string',
628 |           description: 'Description of the phase'
629 |         }
630 |       },
631 |       required: ['featureId', 'name', 'description']
632 |     },
633 |     [
634 |       {
635 |         featureId: "feature-123",
636 |         name: "Requirements Analysis",
637 |         description: "Gather and analyze requirements for the feature"
638 |       },
639 |       {
640 |         featureId: "feature-123",
641 |         name: "Implementation",
642 |         description: "Implement the core functionality of the feature"
643 |       }
644 |     ]
645 |   );
646 | 
647 |   toolRegistry.register(
648 |     'update_phase_status', 
649 |     updatePhaseStatusHandler,
650 |     'Update the status of a development phase',
651 |     {
652 |       type: 'object',
653 |       properties: {
654 |         featureId: {
655 |           type: 'string',
656 |           description: 'ID of the feature containing the phase'
657 |         },
658 |         phaseId: {
659 |           type: 'string',
660 |           description: 'ID of the phase to update'
661 |         },
662 |         status: {
663 |           type: 'string',
664 |           description: 'New status for the phase (pending, in_progress, completed, reviewed)'
665 |         }
666 |       },
667 |       required: ['featureId', 'phaseId', 'status']
668 |     },
669 |     [
670 |       {
671 |         featureId: "feature-123",
672 |         phaseId: "phase-456",
673 |         status: "in_progress"
674 |       },
675 |       {
676 |         featureId: "feature-123",
677 |         phaseId: "phase-456",
678 |         status: "completed"
679 |       }
680 |     ]
681 |   );
682 | 
683 |   toolRegistry.register(
684 |     'add_task', 
685 |     addTaskHandler,
686 |     'Add a task to a development phase',
687 |     {
688 |       type: 'object',
689 |       properties: {
690 |         featureId: {
691 |           type: 'string',
692 |           description: 'ID of the feature containing the phase'
693 |         },
694 |         phaseId: {
695 |           type: 'string',
696 |           description: 'ID of the phase to add the task to'
697 |         },
698 |         description: {
699 |           type: 'string',
700 |           description: 'Description of the task'
701 |         }
702 |       },
703 |       required: ['featureId', 'phaseId', 'description']
704 |     },
705 |     [
706 |       {
707 |         featureId: "feature-123",
708 |         phaseId: "phase-456",
709 |         description: "Create database migration scripts"
710 |       },
711 |       {
712 |         featureId: "feature-123",
713 |         phaseId: "phase-456",
714 |         description: "Implement user interface components"
715 |       }
716 |     ]
717 |   );
718 | 
719 |   toolRegistry.register(
720 |     'update_task_status', 
721 |     updateTaskStatusHandler,
722 |     'Update the completion status of a task',
723 |     {
724 |       type: 'object',
725 |       properties: {
726 |         featureId: {
727 |           type: 'string',
728 |           description: 'ID of the feature containing the phase'
729 |         },
730 |         phaseId: {
731 |           type: 'string',
732 |           description: 'ID of the phase containing the task'
733 |         },
734 |         taskId: {
735 |           type: 'string',
736 |           description: 'ID of the task to update'
737 |         },
738 |         completed: {
739 |           type: 'boolean',
740 |           description: 'Whether the task is completed'
741 |         }
742 |       },
743 |       required: ['featureId', 'phaseId', 'taskId', 'completed']
744 |     },
745 |     [
746 |       {
747 |         featureId: "feature-123",
748 |         phaseId: "phase-456",
749 |         taskId: "task-789",
750 |         completed: true
751 |       },
752 |       {
753 |         featureId: "feature-123",
754 |         phaseId: "phase-456",
755 |         taskId: "task-789",
756 |         completed: false
757 |       }
758 |     ]
759 |   );
760 | 
761 |   toolRegistry.register(
762 |     'get_next_phase_action', 
763 |     getNextPhaseActionHandler,
764 |     'Get guidance on what to do next in the current phase or whether to move to the next phase',
765 |     {
766 |       type: 'object',
767 |       properties: {
768 |         featureId: {
769 |           type: 'string',
770 |           description: 'ID of the feature'
771 |         }
772 |       },
773 |       required: ['featureId']
774 |     },
775 |     [
776 |       { featureId: "feature-123" }
777 |     ]
778 |   );
779 | }
780 | 
781 | // Export all handlers for testing or direct usage
782 | export {
783 |   startFeatureClarificationHandler,
784 |   provideClarificationHandler,
785 |   generatePrdHandler,
786 |   generateImplementationPlanHandler,
787 |   createPhaseHandler,
788 |   updatePhaseStatusHandler,
789 |   addTaskHandler,
790 |   updateTaskStatusHandler,
791 |   getNextPhaseActionHandler
792 | }; 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
   1 | #!/usr/bin/env node
   2 | 
   3 | /**
   4 |  * @file Vibe-Coder MCP Server
   5 |  * @version 0.1.0
   6 |  * 
   7 |  * This MCP server implements a structured development workflow that helps
   8 |  * LLM-based coders build features in an organized, clean, and safe manner.
   9 |  * 
  10 |  * Core functionalities:
  11 |  * - Feature request clarification through iterative questioning
  12 |  * - PRD and implementation plan generation
  13 |  * - Phased development with tasks and status tracking
  14 |  */
  15 | 
  16 | import { Server } from "@modelcontextprotocol/sdk/server/index.js";
  17 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
  18 | import {
  19 |   CallToolRequestSchema,
  20 |   ListResourcesRequestSchema,
  21 |   ListToolsRequestSchema,
  22 |   ReadResourceRequestSchema,
  23 |   ListPromptsRequestSchema,
  24 |   GetPromptRequestSchema,
  25 | } from "@modelcontextprotocol/sdk/types.js";
  26 | 
  27 | // Import core modules
  28 | import { Feature, FeatureStorage, PhaseStatus, Phase, Task, ClarificationResponse } from './types.js';
  29 | import { features, storeFeature, getFeature, updateFeature, listFeatures } from './storage.js';
  30 | import { 
  31 |   DEFAULT_CLARIFICATION_QUESTIONS as CLARIFICATION_QUESTIONS, 
  32 |   getNextClarificationQuestion, 
  33 |   addClarificationResponse,
  34 |   formatClarificationResponses,
  35 |   isClarificationComplete,
  36 |   getClarificationStatus
  37 | } from './clarification.js';
  38 | import {
  39 |   generatePRD,
  40 |   generateImplementationPlan,
  41 |   extractObjectivesFromClarifications,
  42 |   extractRequirementsFromClarifications,
  43 |   extractTechnicalSpecsFromClarifications
  44 | } from './documentation.js';
  45 | import { 
  46 |   createPhase, 
  47 |   getPhase, 
  48 |   updatePhaseStatus,
  49 |   getNextPhaseStatus,
  50 |   validatePhaseTransition,
  51 |   addTask,
  52 |   updateTaskStatus
  53 | } from './phases.js';
  54 | import { 
  55 |   generateId, 
  56 |   createFeatureObject,
  57 |   createPhaseObject,
  58 |   createTaskObject,
  59 |   generateFeatureProgressSummary,
  60 |   isValidPhaseStatus
  61 | } from './utils.js';
  62 | import { validateFeatureId, validatePhaseId, validateTaskId, validateFeaturePhaseTask, validateRequiredText, validatePhaseStatusValue } from './validators.js';
  63 | 
  64 | /**
  65 |  * Type alias for a note object.
  66 |  */
  67 | type Note = { title: string, content: string };
  68 | 
  69 | /**
  70 |  * Simple in-memory storage for notes.
  71 |  * In a real implementation, this would likely be backed by a database.
  72 |  */
  73 | const notes: { [id: string]: Note } = {
  74 |   "1": { title: "First Note", content: "This is note 1" },
  75 |   "2": { title: "Second Note", content: "This is note 2" }
  76 | };
  77 | 
  78 | /**
  79 |  * Create an MCP server with capabilities for resources, tools, and prompts
  80 |  */
  81 | const server = new Server(
  82 |   {
  83 |     name: "Vibe-Coder MCP Server",
  84 |     version: "0.1.0",
  85 |   },
  86 |   {
  87 |     capabilities: {
  88 |       resources: {}, // Expose resources for features, PRDs, and implementation plans
  89 |       tools: {},     // Provide tools for feature clarification and development
  90 |       prompts: {},   // Supply prompts for guiding the development process
  91 |     },
  92 |   }
  93 | );
  94 | 
  95 | /**
  96 |  * Handler for listing available resources.
  97 |  * Exposes:
  98 |  * - A list of all features
  99 |  * - Individual feature details
 100 |  * - PRD and implementation plan documents
 101 |  * - Phase and task details
 102 |  */
 103 | server.setRequestHandler(ListResourcesRequestSchema, async () => {
 104 |   return {
 105 |     resources: [
 106 |       {
 107 |         uri: "features://list",
 108 |         mimeType: "text/plain",
 109 |         name: "Features List",
 110 |         description: "Lists all features being developed"
 111 |       },
 112 |       {
 113 |         uri: "features://status",
 114 |         mimeType: "text/markdown",
 115 |         name: "Project Status",
 116 |         description: "Provides a summary of all features and their development status"
 117 |       },
 118 |       ...listFeatures().flatMap(feature => [
 119 |         {
 120 |           uri: `feature://${feature.id}`,
 121 |           mimeType: "text/plain", 
 122 |           name: feature.name,
 123 |           description: `Details about feature: ${feature.name}`
 124 |         },
 125 |         {
 126 |           uri: `feature://${feature.id}/progress`,
 127 |           mimeType: "text/markdown",
 128 |           name: `${feature.name} Progress Report`,
 129 |           description: `Detailed progress report for feature: ${feature.name}`
 130 |         },
 131 |         {
 132 |           uri: `feature://${feature.id}/prd`,
 133 |           mimeType: "text/markdown",
 134 |           name: `${feature.name} PRD`,
 135 |           description: `PRD document for feature: ${feature.name}`
 136 |         },
 137 |         {
 138 |           uri: `feature://${feature.id}/implementation`,
 139 |           mimeType: "text/markdown",
 140 |           name: `${feature.name} Implementation Plan`,
 141 |           description: `Implementation plan for feature: ${feature.name}`
 142 |         },
 143 |         {
 144 |           uri: `feature://${feature.id}/phases`,
 145 |           mimeType: "text/plain",
 146 |           name: `${feature.name} Phases`,
 147 |           description: `Lists all phases for feature: ${feature.name}`
 148 |         },
 149 |         {
 150 |           uri: `feature://${feature.id}/tasks`,
 151 |           mimeType: "text/plain",
 152 |           name: `${feature.name} All Tasks`,
 153 |           description: `Lists all tasks across all phases for feature: ${feature.name}`
 154 |         },
 155 |         ...feature.phases.flatMap(phase => [
 156 |           {
 157 |             uri: `feature://${feature.id}/phase/${phase.id}`,
 158 |             mimeType: "text/plain",
 159 |             name: `${feature.name} - ${phase.name}`,
 160 |             description: `Details about phase: ${phase.name} for feature: ${feature.name}`
 161 |           },
 162 |           {
 163 |             uri: `feature://${feature.id}/phase/${phase.id}/tasks`,
 164 |             mimeType: "text/plain",
 165 |             name: `${feature.name} - ${phase.name} Tasks`,
 166 |             description: `Lists all tasks for phase: ${phase.name}`
 167 |           },
 168 |           ...phase.tasks.map(task => ({
 169 |             uri: `feature://${feature.id}/phase/${phase.id}/task/${task.id}`,
 170 |             mimeType: "text/plain",
 171 |             name: `Task: ${task.description.substring(0, 30)}${task.description.length > 30 ? '...' : ''}`,
 172 |             description: `Details about task: ${task.description.substring(0, 50)}${task.description.length > 50 ? '...' : ''}`
 173 |           }))
 174 |         ])
 175 |       ])
 176 |     ]
 177 |   };
 178 | });
 179 | 
 180 | /**
 181 |  * Handler for reading feature resources.
 182 |  * Supports:
 183 |  * - List of all features
 184 |  * - Individual feature details
 185 |  * - PRD and implementation plan documents
 186 |  * - Phase and task details
 187 |  */
 188 | server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
 189 |   try {
 190 |     const url = new URL(request.params.uri);
 191 |     
 192 |     // Handle list of all features
 193 |     if (url.protocol === "features:") {
 194 |       if (url.pathname === "/list") {
 195 |         return {
 196 |           contents: [{
 197 |             uri: request.params.uri,
 198 |             mimeType: "text/plain",
 199 |             text: listFeatures().map(f => `${f.id}: ${f.name}`).join("\n")
 200 |           }]
 201 |         };
 202 |       }
 203 |       
 204 |       if (url.pathname === "/status") {
 205 |         const features = listFeatures();
 206 |         
 207 |         if (features.length === 0) {
 208 |           return {
 209 |             contents: [{
 210 |               uri: request.params.uri,
 211 |               mimeType: "text/markdown",
 212 |               text: "# Project Status\n\nNo features have been created yet."
 213 |             }]
 214 |           };
 215 |         }
 216 |         
 217 |         const featuresStatus = features.map(feature => {
 218 |           const totalPhases = feature.phases.length;
 219 |           const completedPhases = feature.phases.filter(p => p.status === 'completed' || p.status === 'reviewed').length;
 220 |           const totalTasks = feature.phases.reduce((acc, phase) => acc + phase.tasks.length, 0);
 221 |           const completedTasks = feature.phases.reduce(
 222 |             (acc, phase) => acc + phase.tasks.filter(t => t.completed).length, 0
 223 |           );
 224 |           
 225 |           return `## ${feature.name}
 226 | - ID: ${feature.id}
 227 | - Status: ${completedPhases === totalPhases && totalPhases > 0 ? 'Completed' : 'In Progress'}
 228 | - Phases: ${completedPhases}/${totalPhases} completed
 229 | - Tasks: ${completedTasks}/${totalTasks} completed
 230 | - [View Details](feature://${feature.id}/progress)
 231 | `;
 232 |         }).join('\n');
 233 |         
 234 |         return {
 235 |           contents: [{
 236 |             uri: request.params.uri,
 237 |             mimeType: "text/markdown",
 238 |             text: `# Project Status\n\n${featuresStatus}`
 239 |           }]
 240 |         };
 241 |       }
 242 |     }
 243 |     
 244 |     // Handle feature-specific resources
 245 |     if (url.protocol === "feature:") {
 246 |       // The hostname part is actually our feature ID in feature:// URLs
 247 |       let featureId = "";
 248 |       
 249 |       if (url.hostname) {
 250 |         featureId = url.hostname;
 251 |       } else {
 252 |         // Try to get feature ID from pathname for backward compatibility
 253 |         const parts = url.pathname.split('/').filter(Boolean);
 254 |         if (parts.length > 0) {
 255 |           featureId = parts[0];
 256 |         }
 257 |       }
 258 |       
 259 |       if (!featureId) {
 260 |         throw new Error(`Invalid feature URI: ${request.params.uri}. Missing feature ID.`);
 261 |       }
 262 |       
 263 |       const feature = getFeature(featureId);
 264 |       
 265 |       if (!feature) {
 266 |         throw new Error(`Feature ${featureId} not found`);
 267 |       }
 268 |       
 269 |       // Extract path parts, excluding empty strings
 270 |       const parts = url.pathname.split('/').filter(Boolean);
 271 |       
 272 |       // Return feature details - no additional path parts beyond the feature ID
 273 |       if (parts.length === 0) {
 274 |         const timestamp = feature.updatedAt.toISOString();
 275 |         const clarifications = formatClarificationResponses(feature.clarificationResponses);
 276 |         const phasesText = feature.phases.map(p => 
 277 |           `- ${p.name} (${p.status}): ${p.tasks.filter(t => t.completed).length}/${p.tasks.length} tasks completed`
 278 |         ).join('\n');
 279 |         
 280 |         const featureDetails = `
 281 | Feature: ${feature.name}
 282 | ID: ${feature.id}
 283 | Description: ${feature.description}
 284 | Last Updated: ${timestamp}
 285 | 
 286 | Clarification Responses:
 287 | ${clarifications}
 288 | 
 289 | Phases (${feature.phases.length}):
 290 | ${phasesText}
 291 | `;
 292 |         
 293 |         return {
 294 |           contents: [{
 295 |             uri: request.params.uri,
 296 |             mimeType: "text/plain",
 297 |             text: featureDetails
 298 |           }]
 299 |         };
 300 |       }
 301 |       
 302 |       // Resource is a sub-resource of the feature
 303 |       if (parts.length >= 1) {
 304 |         const subResource = parts[0];
 305 |         
 306 |         // Return feature progress report
 307 |         if (subResource === "progress") {
 308 |           const progressReport = generateFeatureProgressSummary(feature);
 309 |           
 310 |           return {
 311 |             contents: [{
 312 |               uri: request.params.uri,
 313 |               mimeType: "text/markdown",
 314 |               text: progressReport
 315 |             }]
 316 |           };
 317 |         }
 318 |         
 319 |         // Return PRD document
 320 |         if (subResource === "prd") {
 321 |           const prdContent = feature.prdDoc || generatePRD(feature);
 322 |           
 323 |           return {
 324 |             contents: [{
 325 |               uri: request.params.uri,
 326 |               mimeType: "text/markdown",
 327 |               text: prdContent
 328 |             }]
 329 |           };
 330 |         }
 331 |         
 332 |         // Return implementation plan document
 333 |         if (subResource === "implementation") {
 334 |           const implContent = feature.implDoc || generateImplementationPlan(feature);
 335 |           
 336 |           return {
 337 |             contents: [{
 338 |               uri: request.params.uri,
 339 |               mimeType: "text/markdown",
 340 |               text: implContent
 341 |             }]
 342 |           };
 343 |         }
 344 |         
 345 |         // Return phase listing
 346 |         if (subResource === "phases") {
 347 |           if (feature.phases.length === 0) {
 348 |             return {
 349 |               contents: [{
 350 |                 uri: request.params.uri,
 351 |                 mimeType: "text/plain",
 352 |                 text: `No phases defined for feature: ${feature.name}`
 353 |               }]
 354 |             };
 355 |           }
 356 |           
 357 |           const phasesContent = feature.phases.map(phase => {
 358 |             const completedTasks = phase.tasks.filter(t => t.completed).length;
 359 |             const totalTasks = phase.tasks.length;
 360 |             return `Phase: ${phase.name} (ID: ${phase.id})
 361 | Status: ${phase.status}
 362 | Description: ${phase.description}
 363 | Progress: ${completedTasks}/${totalTasks} tasks completed
 364 | Last Updated: ${phase.updatedAt.toISOString()}
 365 | `;
 366 |           }).join('\n---\n\n');
 367 |           
 368 |           return {
 369 |             contents: [{
 370 |               uri: request.params.uri,
 371 |               mimeType: "text/plain",
 372 |               text: `# Phases for Feature: ${feature.name}\n\n${phasesContent}`
 373 |             }]
 374 |           };
 375 |         }
 376 |         
 377 |         // Handle list of all tasks for a feature
 378 |         if (subResource === "tasks") {
 379 |           const allTasks = feature.phases.flatMap(phase => 
 380 |             phase.tasks.map(task => ({
 381 |               ...task,
 382 |               phaseName: phase.name,
 383 |               phaseId: phase.id,
 384 |               phaseStatus: phase.status
 385 |             }))
 386 |           );
 387 |           
 388 |           if (allTasks.length === 0) {
 389 |             return {
 390 |               contents: [{
 391 |                 uri: request.params.uri,
 392 |                 mimeType: "text/plain",
 393 |                 text: `No tasks defined for feature: ${feature.name}`
 394 |               }]
 395 |             };
 396 |           }
 397 |           
 398 |           const pendingTasks = allTasks.filter(t => !t.completed);
 399 |           const completedTasks = allTasks.filter(t => t.completed);
 400 |           
 401 |           const pendingTasksText = pendingTasks.length > 0 
 402 |             ? pendingTasks.map(task => `- [ ] ${task.description} (ID: ${task.id}, Phase: ${task.phaseName})`).join('\n')
 403 |             : "No pending tasks.";
 404 |             
 405 |           const completedTasksText = completedTasks.length > 0
 406 |             ? completedTasks.map(task => `- [x] ${task.description} (ID: ${task.id}, Phase: ${task.phaseName})`).join('\n')
 407 |             : "No completed tasks.";
 408 |           
 409 |           const tasksContent = `# All Tasks for Feature: ${feature.name}
 410 | 
 411 | ## Pending Tasks (${pendingTasks.length})
 412 | ${pendingTasksText}
 413 | 
 414 | ## Completed Tasks (${completedTasks.length})
 415 | ${completedTasksText}
 416 | `;
 417 |           
 418 |           return {
 419 |             contents: [{
 420 |               uri: request.params.uri,
 421 |               mimeType: "text/plain",
 422 |               text: tasksContent
 423 |             }]
 424 |           };
 425 |         }
 426 |         
 427 |         // Handle phase-specific resources
 428 |         if (subResource === "phase" && parts.length >= 2) {
 429 |           const phaseId = parts[1];
 430 |           const phase = feature.phases.find(p => p.id === phaseId);
 431 |           
 432 |           if (!phase) {
 433 |             throw new Error(`Phase ${phaseId} not found in feature ${feature.name}`);
 434 |           }
 435 |           
 436 |           // Return phase details
 437 |           if (parts.length === 2) {
 438 |             const completedTasks = phase.tasks.filter(t => t.completed).length;
 439 |             const totalTasks = phase.tasks.length;
 440 |             
 441 |             const taskList = phase.tasks.map(task => 
 442 |               `- [${task.completed ? 'x' : ' '}] ${task.description} (ID: ${task.id})`
 443 |             ).join('\n');
 444 |             
 445 |             const phaseDetails = `
 446 | Phase: ${phase.name}
 447 | ID: ${phase.id}
 448 | Status: ${phase.status}
 449 | Description: ${phase.description}
 450 | Created: ${phase.createdAt.toISOString()}
 451 | Last Updated: ${phase.updatedAt.toISOString()}
 452 | Progress: ${completedTasks}/${totalTasks} tasks completed
 453 | 
 454 | Tasks:
 455 | ${taskList}
 456 | `;
 457 |             
 458 |             return {
 459 |               contents: [{
 460 |                 uri: request.params.uri,
 461 |                 mimeType: "text/plain",
 462 |                 text: phaseDetails
 463 |               }]
 464 |             };
 465 |           }
 466 |           
 467 |           // Return task listing
 468 |           if (parts[2] === "tasks") {
 469 |             if (phase.tasks.length === 0) {
 470 |               return {
 471 |                 contents: [{
 472 |                   uri: request.params.uri,
 473 |                   mimeType: "text/plain",
 474 |                   text: `No tasks defined for phase: ${phase.name}`
 475 |                 }]
 476 |               };
 477 |             }
 478 |             
 479 |             const tasksContent = phase.tasks.map(task => `
 480 | Task: ${task.description}
 481 | ID: ${task.id}
 482 | Status: ${task.completed ? 'Completed' : 'Pending'}
 483 | Created: ${task.createdAt.toISOString()}
 484 | Last Updated: ${task.updatedAt.toISOString()}
 485 | `).join('\n---\n');
 486 |             
 487 |             return {
 488 |               contents: [{
 489 |                 uri: request.params.uri,
 490 |                 mimeType: "text/plain",
 491 |                 text: `# Tasks for Phase: ${phase.name}\n\n${tasksContent}`
 492 |               }]
 493 |             };
 494 |           }
 495 |           
 496 |           // Return individual task details
 497 |           if (parts[2] === "task" && parts.length === 4) {
 498 |             const taskId = parts[3];
 499 |             const task = phase.tasks.find(t => t.id === taskId);
 500 |             
 501 |             if (!task) {
 502 |               throw new Error(`Task ${taskId} not found in phase ${phase.name}`);
 503 |             }
 504 |             
 505 |             const taskDetails = `
 506 | Task: ${task.description}
 507 | ID: ${task.id}
 508 | Status: ${task.completed ? 'Completed' : 'Pending'}
 509 | Created: ${task.createdAt.toISOString()}
 510 | Last Updated: ${task.updatedAt.toISOString()}
 511 | `;
 512 |             
 513 |             return {
 514 |               contents: [{
 515 |                 uri: request.params.uri,
 516 |                 mimeType: "text/plain",
 517 |                 text: taskDetails
 518 |               }]
 519 |             };
 520 |           }
 521 |         }
 522 |       }
 523 |     }
 524 |     
 525 |     throw new Error(`Resource not found: ${request.params.uri}`);
 526 |   } catch (error: any) {
 527 |     console.error(`Error reading resource ${request.params.uri}:`, error);
 528 |     return {
 529 |       contents: [{
 530 |         uri: request.params.uri,
 531 |         mimeType: "text/plain",
 532 |         text: `Error: ${error.message || 'Unknown error'}`
 533 |       }]
 534 |     };
 535 |   }
 536 | });
 537 | 
 538 | /**
 539 |  * Handler that lists available tools.
 540 |  * Exposes tools for feature clarification and development.
 541 |  */
 542 | server.setRequestHandler(ListToolsRequestSchema, async () => {
 543 |   return {
 544 |     tools: [
 545 |       {
 546 |         name: "start_feature_clarification",
 547 |         description: "Start the clarification process for a new feature",
 548 |         inputSchema: {
 549 |           type: "object",
 550 |           properties: {
 551 |             featureName: {
 552 |               type: "string",
 553 |               description: "Name of the feature"
 554 |             },
 555 |             initialDescription: {
 556 |               type: "string",
 557 |               description: "Initial description of the feature"
 558 |             }
 559 |           },
 560 |           required: ["featureName"],
 561 |           examples: [
 562 |             {
 563 |               featureName: "User Authentication",
 564 |               initialDescription: "Add login and registration functionality to the application"
 565 |             },
 566 |             {
 567 |               featureName: "Data Export",
 568 |               initialDescription: "Allow users to export their data in CSV and JSON formats"
 569 |             }
 570 |           ]
 571 |         }
 572 |       },
 573 |       {
 574 |         name: "provide_clarification",
 575 |         description: "Provide answer to a clarification question",
 576 |         inputSchema: {
 577 |           type: "object",
 578 |           properties: {
 579 |             featureId: {
 580 |               type: "string",
 581 |               description: "ID of the feature"
 582 |             },
 583 |             question: {
 584 |               type: "string",
 585 |               description: "Clarification question"
 586 |             },
 587 |             answer: {
 588 |               type: "string",
 589 |               description: "Answer to the clarification question"
 590 |             }
 591 |           },
 592 |           required: ["featureId", "question", "answer"],
 593 |           examples: [
 594 |             {
 595 |               featureId: "feature-123",
 596 |               question: "What problem does this feature solve?",
 597 |               answer: "This feature solves the problem of users forgetting their passwords by providing a secure password reset flow."
 598 |             },
 599 |             {
 600 |               featureId: "feature-456",
 601 |               question: "Who are the target users?",
 602 |               answer: "The target users are administrators who need to manage user accounts and permissions."
 603 |             }
 604 |           ]
 605 |         }
 606 |       },
 607 |       {
 608 |         name: "generate_prd",
 609 |         description: "Generate a PRD document based on clarification responses",
 610 |         inputSchema: {
 611 |           type: "object",
 612 |           properties: {
 613 |             featureId: {
 614 |               type: "string",
 615 |               description: "ID of the feature"
 616 |             }
 617 |           },
 618 |           required: ["featureId"],
 619 |           examples: [
 620 |             {
 621 |               featureId: "feature-123"
 622 |             }
 623 |           ]
 624 |         },
 625 |         handler: async (params: {featureId: string}) => {
 626 |           const { featureId } = params;
 627 |           const feature = getFeature(featureId);
 628 |           
 629 |           if (!feature) {
 630 |             return {
 631 |               error: `Feature with ID ${featureId} not found`
 632 |             };
 633 |           }
 634 |           
 635 |           if (!isClarificationComplete(feature)) {
 636 |             return {
 637 |               error: 'Cannot generate PRD until clarification is complete',
 638 |               clarificationStatus: getClarificationStatus(feature)
 639 |             };
 640 |           }
 641 |           
 642 |           // Generate the PRD
 643 |           const prd = generatePRD(feature);
 644 |           
 645 |           // Update the feature with the PRD
 646 |           updateFeature(featureId, {
 647 |             ...feature,
 648 |             prd,
 649 |             updatedAt: new Date()
 650 |           });
 651 |           
 652 |           return {
 653 |             success: true,
 654 |             message: `PRD generated for feature ${feature.name}`,
 655 |             prd
 656 |           };
 657 |         }
 658 |       },
 659 |       {
 660 |         name: 'generate_implementation_plan',
 661 |         description: 'Generate an implementation plan for a feature based on clarifications and PRD',
 662 |         inputSchema: {
 663 |           type: 'object',
 664 |           properties: {
 665 |             featureId: {
 666 |               type: 'string',
 667 |               description: 'The ID of the feature to generate an implementation plan for'
 668 |             }
 669 |           },
 670 |           required: ['featureId']
 671 |         },
 672 |         handler: async (params: {featureId: string}) => {
 673 |           const { featureId } = params;
 674 |           const feature = getFeature(featureId);
 675 |           
 676 |           if (!feature) {
 677 |             return {
 678 |               error: `Feature with ID ${featureId} not found`
 679 |             };
 680 |           }
 681 |           
 682 |           if (!isClarificationComplete(feature)) {
 683 |             return {
 684 |               error: 'Cannot generate implementation plan until clarification is complete',
 685 |               clarificationStatus: getClarificationStatus(feature)
 686 |             };
 687 |           }
 688 |           
 689 |           // Generate the implementation plan
 690 |           const implementationPlan = generateImplementationPlan(feature);
 691 |           
 692 |           // Update the feature with the implementation plan
 693 |           updateFeature(featureId, {
 694 |             ...feature,
 695 |             implementationPlan,
 696 |             updatedAt: new Date()
 697 |           });
 698 |           
 699 |           return {
 700 |             success: true,
 701 |             message: `Implementation plan generated for feature ${feature.name}`,
 702 |             implementationPlan
 703 |           };
 704 |         }
 705 |       },
 706 |       {
 707 |         name: 'create_phase',
 708 |         description: 'Create a new development phase for a feature',
 709 |         inputSchema: {
 710 |           type: 'object',
 711 |           properties: {
 712 |             featureId: {
 713 |               type: 'string',
 714 |               description: 'ID of the feature to create a phase for'
 715 |             },
 716 |             name: {
 717 |               type: 'string',
 718 |               description: 'Name of the phase'
 719 |             },
 720 |             description: {
 721 |               type: 'string',
 722 |               description: 'Description of the phase'
 723 |             }
 724 |           },
 725 |           required: ['featureId', 'name', 'description'],
 726 |           examples: [
 727 |             {
 728 |               featureId: "feature-123",
 729 |               name: "Requirements Analysis",
 730 |               description: "Gather and analyze requirements for the feature"
 731 |             },
 732 |             {
 733 |               featureId: "feature-123",
 734 |               name: "Implementation",
 735 |               description: "Implement the core functionality of the feature"
 736 |             }
 737 |           ]
 738 |         },
 739 |         handler: async (params: {featureId: string, name: string, description: string}) => {
 740 |           const { featureId, name, description } = params;
 741 |           const feature = getFeature(featureId);
 742 |           
 743 |           if (!feature) {
 744 |             return {
 745 |               error: `Feature with ID ${featureId} not found`
 746 |             };
 747 |           }
 748 |           
 749 |           // Create the phase with validated inputs
 750 |           const phaseId = generateId();
 751 |           const phase = createPhase(feature.id, name, description);
 752 |           
 753 |           return {
 754 |             success: true,
 755 |             message: `Phase ${name} created for feature ${feature.name}`,
 756 |             phase
 757 |           };
 758 |         }
 759 |       },
 760 |       {
 761 |         name: 'update_phase_status',
 762 |         description: 'Update the status of a development phase',
 763 |         inputSchema: {
 764 |           type: 'object',
 765 |           properties: {
 766 |             featureId: {
 767 |               type: 'string',
 768 |               description: 'ID of the feature containing the phase'
 769 |             },
 770 |             phaseId: {
 771 |               type: 'string',
 772 |               description: 'ID of the phase to update'
 773 |             },
 774 |             status: {
 775 |               type: 'string',
 776 |               description: 'New status for the phase (pending, in_progress, completed, reviewed)'
 777 |             }
 778 |           },
 779 |           required: ['featureId', 'phaseId', 'status'],
 780 |           examples: [
 781 |             {
 782 |               featureId: "feature-123",
 783 |               phaseId: "phase-456",
 784 |               status: "in_progress"
 785 |             },
 786 |             {
 787 |               featureId: "feature-123",
 788 |               phaseId: "phase-456",
 789 |               status: "completed"
 790 |             }
 791 |           ]
 792 |         },
 793 |         handler: async (params: {featureId: string, phaseId: string, status: PhaseStatus}) => {
 794 |           const { featureId, phaseId, status } = params;
 795 |           const feature = getFeature(featureId);
 796 |           
 797 |           if (!feature) {
 798 |             return {
 799 |               error: `Feature with ID ${featureId} not found`
 800 |             };
 801 |           }
 802 |           
 803 |           const phase = feature.phases.find(p => p.id === phaseId);
 804 |           
 805 |           if (!phase) {
 806 |             return {
 807 |               error: `Phase with ID ${phaseId} not found in feature ${feature.name}`
 808 |             };
 809 |           }
 810 |           
 811 |           // Validate the status transition
 812 |           const validationResult = validatePhaseTransition(phase.status, status);
 813 |           
 814 |           if (!validationResult.valid) {
 815 |             return {
 816 |               error: validationResult.message
 817 |             };
 818 |           }
 819 |           
 820 |           // Update the phase status
 821 |           const updatedPhase = updatePhaseStatus(featureId, phaseId, status);
 822 |           
 823 |           return {
 824 |             success: true,
 825 |             message: `Phase ${phase.name} status updated to ${status}`,
 826 |             phase: updatedPhase
 827 |           };
 828 |         }
 829 |       },
 830 |       {
 831 |         name: 'add_task',
 832 |         description: 'Add a task to a development phase',
 833 |         inputSchema: {
 834 |           type: 'object',
 835 |           properties: {
 836 |             featureId: {
 837 |               type: 'string',
 838 |               description: 'ID of the feature containing the phase'
 839 |             },
 840 |             phaseId: {
 841 |               type: 'string',
 842 |               description: 'ID of the phase to add the task to'
 843 |             },
 844 |             description: {
 845 |               type: 'string',
 846 |               description: 'Description of the task'
 847 |             }
 848 |           },
 849 |           required: ['featureId', 'phaseId', 'description'],
 850 |           examples: [
 851 |             {
 852 |               featureId: "feature-123",
 853 |               phaseId: "phase-456",
 854 |               description: "Create database migration scripts"
 855 |             },
 856 |             {
 857 |               featureId: "feature-123",
 858 |               phaseId: "phase-456",
 859 |               description: "Implement user interface components"
 860 |             }
 861 |           ]
 862 |         },
 863 |         handler: async (params: {featureId: string, phaseId: string, description: string}) => {
 864 |           const { featureId, phaseId, description } = params;
 865 |           const feature = getFeature(featureId);
 866 |           
 867 |           if (!feature) {
 868 |             return {
 869 |               error: `Feature with ID ${featureId} not found`
 870 |             };
 871 |           }
 872 |           
 873 |           const phase = feature.phases.find(p => p.id === phaseId);
 874 |           
 875 |           if (!phase) {
 876 |             return {
 877 |               error: `Phase with ID ${phaseId} not found in feature ${feature.name}`
 878 |             };
 879 |           }
 880 |           
 881 |           // Add the task to the phase
 882 |           const updatedPhase = addTask(featureId, phaseId, description);
 883 |           
 884 |           return {
 885 |             success: true,
 886 |             message: `Task added to phase ${phase.name}`,
 887 |             phase: updatedPhase
 888 |           };
 889 |         }
 890 |       },
 891 |       {
 892 |         name: 'update_task_status',
 893 |         description: 'Update the completion status of a task',
 894 |         inputSchema: {
 895 |           type: 'object',
 896 |           properties: {
 897 |             featureId: {
 898 |               type: 'string',
 899 |               description: 'ID of the feature containing the phase'
 900 |             },
 901 |             phaseId: {
 902 |               type: 'string',
 903 |               description: 'ID of the phase containing the task'
 904 |             },
 905 |             taskId: {
 906 |               type: 'string',
 907 |               description: 'ID of the task to update'
 908 |             },
 909 |             completed: {
 910 |               type: 'boolean',
 911 |               description: 'Whether the task is completed'
 912 |             }
 913 |           },
 914 |           required: ['featureId', 'phaseId', 'taskId', 'completed'],
 915 |           examples: [
 916 |             {
 917 |               featureId: "feature-123",
 918 |               phaseId: "phase-456",
 919 |               taskId: "task-789",
 920 |               completed: true
 921 |             },
 922 |             {
 923 |               featureId: "feature-123",
 924 |               phaseId: "phase-456",
 925 |               taskId: "task-789",
 926 |               completed: false
 927 |             }
 928 |           ]
 929 |         },
 930 |         handler: async (params: {featureId: string, phaseId: string, taskId: string, completed: boolean}) => {
 931 |           const { featureId, phaseId, taskId, completed } = params;
 932 |           const feature = getFeature(featureId);
 933 |           
 934 |           if (!feature) {
 935 |             return {
 936 |               error: `Feature with ID ${featureId} not found`
 937 |             };
 938 |           }
 939 |           
 940 |           const phase = feature.phases.find(p => p.id === phaseId);
 941 |           
 942 |           if (!phase) {
 943 |             return {
 944 |               error: `Phase with ID ${phaseId} not found in feature ${feature.name}`
 945 |             };
 946 |           }
 947 |           
 948 |           const task = phase.tasks.find(t => t.id === taskId);
 949 |           
 950 |           if (!task) {
 951 |             return {
 952 |               error: `Task with ID ${taskId} not found in phase ${phase.name}`
 953 |             };
 954 |           }
 955 |           
 956 |           // Update the task status
 957 |           const updatedTask = updateTaskStatus(featureId, phaseId, taskId, completed);
 958 |           
 959 |           // Check if all tasks are completed and suggest phase update if applicable
 960 |           let message = `Task status updated to ${completed ? 'completed' : 'not completed'}`;
 961 |           
 962 |           // @ts-ignore - We know the task structure from our validation
 963 |           if (completed && phase.tasks.every(t => t.id === taskId || t.completed)) {
 964 |             // All tasks are now completed
 965 |             message += `. All tasks in phase ${phase.name} are now completed. Consider updating the phase status to 'completed'.`;
 966 |           }
 967 |           
 968 |           return {
 969 |             success: true,
 970 |             message,
 971 |             task: updatedTask
 972 |           };
 973 |         }
 974 |       },
 975 |       {
 976 |         name: 'get_next_phase_action',
 977 |         description: 'Get guidance on what to do next in the current phase or whether to move to the next phase',
 978 |         inputSchema: {
 979 |           type: 'object',
 980 |           properties: {
 981 |             featureId: {
 982 |               type: 'string',
 983 |               description: 'ID of the feature'
 984 |             }
 985 |           },
 986 |           required: ['featureId'],
 987 |           examples: [
 988 |             {
 989 |               featureId: "feature-123"
 990 |             }
 991 |           ]
 992 |         },
 993 |         handler: async (params: {featureId: string}) => {
 994 |           const { featureId } = params;
 995 |           const feature = getFeature(featureId);
 996 |           
 997 |           if (!feature) {
 998 |             return {
 999 |               error: `Feature with ID ${featureId} not found`
1000 |             };
1001 |           }
1002 |           
1003 |           // Find the current active phase (first non-completed/reviewed phase)
1004 |           // @ts-ignore - We know the phase structure from our Feature type
1005 |           const currentPhase = feature.phases.find(p => p.status === 'pending' || p.status === 'in_progress');
1006 |           
1007 |           if (!currentPhase) {
1008 |             // All phases are completed or reviewed
1009 |             return {
1010 |               content: [{
1011 |                 type: "text",
1012 |                 text: 'All phases are completed or reviewed. The feature implementation is done!'
1013 |               }]
1014 |             };
1015 |           }
1016 |           
1017 |           // Check task completion status
1018 |           // @ts-ignore - We know the task structure from our Phase type
1019 |           const completedTasks = currentPhase.tasks.filter(t => t.completed);
1020 |           // @ts-ignore - We know the task structure from our Phase type
1021 |           const pendingTasks = currentPhase.tasks.filter(t => !t.completed);
1022 |           
1023 |           // Determine next action based on phase and task status
1024 |           let message = '';
1025 |           
1026 |           if (currentPhase.status === 'pending') {
1027 |             message = `Phase "${currentPhase.name}" is pending. Start working on this phase by setting its status to "in_progress".`;
1028 |           } else if (currentPhase.status === 'in_progress') {
1029 |             if (pendingTasks.length > 0) {
1030 |               message = `${completedTasks.length}/${currentPhase.tasks.length} tasks are completed in phase "${currentPhase.name}". Continue working on pending tasks.`;
1031 |             } else if (currentPhase.tasks.length === 0) {
1032 |               message = `Phase "${currentPhase.name}" has no tasks defined. Add tasks or mark the phase as completed if appropriate.`;
1033 |             } else {
1034 |               // All tasks are completed
1035 |               message = `All tasks in phase "${currentPhase.name}" are completed. Consider marking this phase as completed.`;
1036 |             }
1037 |           }
1038 |           
1039 |           return {
1040 |             content: [{
1041 |               type: "text",
1042 |               text: message
1043 |             }]
1044 |           };
1045 |         }
1046 |       }
1047 |     ]
1048 |   };
1049 | });
1050 | 
1051 | /**
1052 |  * Handler for implementing MCP tools.
1053 |  * Handles feature clarification, PRD generation, and more.
1054 |  */
1055 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
1056 |   try {
1057 |     switch (request.params.name) {
1058 |       case "start_feature_clarification": {
1059 |         const featureName = String(request.params.arguments?.featureName || "");
1060 |         const initialDescription = String(request.params.arguments?.initialDescription || "");
1061 |         
1062 |         // Validate inputs
1063 |         const nameValidation = validateRequiredText(featureName, "Feature name", 2, 100);
1064 |         if (!nameValidation.valid) {
1065 |           return {
1066 |             content: [{
1067 |               type: "text",
1068 |               text: `Error: ${nameValidation.message}`
1069 |             }]
1070 |           };
1071 |         }
1072 |         
1073 |         // Initial description is optional, but if provided, validate its length
1074 |         if (initialDescription && initialDescription.trim() !== "") {
1075 |           const descValidation = validateRequiredText(initialDescription, "Initial description", 1, 5000);
1076 |           if (!descValidation.valid) {
1077 |             return {
1078 |               content: [{
1079 |                 type: "text", 
1080 |                 text: `Error: ${descValidation.message}`
1081 |               }]
1082 |             };
1083 |           }
1084 |         }
1085 |         
1086 |         // Create a new feature
1087 |         const feature = createFeatureObject(nameValidation.data, initialDescription);
1088 |         storeFeature(feature);
1089 |         
1090 |         // Get the first clarification question
1091 |         const firstQuestion = getNextClarificationQuestion(feature);
1092 |         
1093 |         return {
1094 |           content: [{
1095 |             type: "text",
1096 |             text: `Feature ID: ${feature.id}\n\nLet's clarify your feature request. ${firstQuestion}`
1097 |           }]
1098 |         };
1099 |       }
1100 |       
1101 |       case "provide_clarification": {
1102 |         const featureId = String(request.params.arguments?.featureId || "");
1103 |         const question = String(request.params.arguments?.question || "");
1104 |         const answer = String(request.params.arguments?.answer || "");
1105 |         
1106 |         console.log(`\n[CLARIFICATION] Received request for feature ${featureId}\n  Question: "${question.substring(0, 50)}..."\n  Answer: "${answer.substring(0, 50)}..."`);
1107 |         
1108 |         // Basic validation
1109 |         if (!featureId || !answer) {
1110 |           console.log(`[CLARIFICATION] Missing required fields: featureId=${!!featureId}, answer=${!!answer}`);
1111 |           return {
1112 |             content: [{
1113 |               type: "text",
1114 |               text: "Error: Feature ID and answer are required"
1115 |             }]
1116 |           };
1117 |         }
1118 |         
1119 |         // Get the feature
1120 |         const feature = getFeature(featureId);
1121 |         if (!feature) {
1122 |           console.log(`[CLARIFICATION] Feature ID ${featureId} not found`);
1123 |           return {
1124 |             content: [{
1125 |               type: "text",
1126 |               text: `Error: Feature with ID ${featureId} not found`
1127 |             }]
1128 |           };
1129 |         }
1130 |         
1131 |         console.log(`[CLARIFICATION] Found feature: ${feature.name} with ${feature.clarificationResponses.length} existing responses`);
1132 |         
1133 |         // Add the clarification response to the feature
1134 |         feature.clarificationResponses.push({
1135 |           question,
1136 |           answer,
1137 |           timestamp: new Date()
1138 |         });
1139 |         
1140 |         console.log(`[CLARIFICATION] Added response, now has ${feature.clarificationResponses.length} responses`);
1141 |         
1142 |         // Save the feature with the updated clarification response
1143 |         updateFeature(featureId, feature);
1144 |         
1145 |         // Determine which question to ask next
1146 |         const nextQuestionIndex = feature.clarificationResponses.length;
1147 |         
1148 |         console.log(`[CLARIFICATION] Next question index would be: ${nextQuestionIndex}`);
1149 |         console.log(`[CLARIFICATION] Total questions available: ${CLARIFICATION_QUESTIONS.length}`);
1150 |         
1151 |         if (nextQuestionIndex < CLARIFICATION_QUESTIONS.length) {
1152 |           // We have more questions to ask
1153 |           const nextQuestion = CLARIFICATION_QUESTIONS[nextQuestionIndex];
1154 |           console.log(`[CLARIFICATION] Returning next question: "${nextQuestion.substring(0, 50)}..."`);
1155 |           return {
1156 |             content: [{
1157 |               type: "text",
1158 |               text: `Response recorded. ${nextQuestion}`
1159 |             }]
1160 |           };
1161 |         } else {
1162 |           // All questions answered
1163 |           console.log(`[CLARIFICATION] All questions answered`);
1164 |           return {
1165 |             content: [{
1166 |               type: "text",
1167 |               text: "All clarification questions have been answered. You can now generate a PRD for this feature."
1168 |             }]
1169 |           };
1170 |         }
1171 |       }
1172 |       
1173 |       case "generate_prd": {
1174 |         const featureId = String(request.params.arguments?.featureId || "");
1175 |         
1176 |         // Validate feature ID
1177 |         const featureResult = validateFeatureId(featureId);
1178 |         if (!featureResult.valid) {
1179 |           return {
1180 |             content: [{
1181 |               type: "text",
1182 |               text: `Error: ${featureResult.message}`
1183 |             }]
1184 |           };
1185 |         }
1186 |         
1187 |         const feature = featureResult.data;
1188 |         
1189 |         // Check if clarifications are complete
1190 |         if (!isClarificationComplete(feature)) {
1191 |           return {
1192 |             content: [{
1193 |               type: "text",
1194 |               text: "Error: Please complete all clarification questions before generating a PRD."
1195 |             }]
1196 |           };
1197 |         }
1198 |         
1199 |         // Generate PRD and implementation plan
1200 |         const prdDoc = generatePRD(feature);
1201 |         const implementationPlan = generateImplementationPlan(feature);
1202 |         
1203 |         // Store the documents
1204 |         feature.prdDoc = prdDoc;
1205 |         feature.implementationPlan = implementationPlan;
1206 |         
1207 |         return {
1208 |           content: [{
1209 |             type: "text",
1210 |             text: `PRD and Implementation Plan generated for feature ${feature.name}. You can view them using the resource URIs: feature://${feature.id}/prd and feature://${feature.id}/implementation`
1211 |           }]
1212 |         };
1213 |       }
1214 |       
1215 |       case "create_phase": {
1216 |         const featureId = String(request.params.arguments?.featureId || "");
1217 |         const phaseName = String(request.params.arguments?.name || "");
1218 |         const phaseDescription = String(request.params.arguments?.description || "");
1219 |         const tasksJson = String(request.params.arguments?.tasks || "[]");
1220 |         
1221 |         // Validate feature ID
1222 |         const featureResult = validateFeatureId(featureId);
1223 |         if (!featureResult.valid) {
1224 |           return {
1225 |             content: [{
1226 |               type: "text",
1227 |               text: `Error: ${featureResult.message}`
1228 |             }]
1229 |           };
1230 |         }
1231 |         
1232 |         // Validate phase name
1233 |         const nameValidation = validateRequiredText(phaseName, "Phase name", 2, 100);
1234 |         if (!nameValidation.valid) {
1235 |           return {
1236 |             content: [{
1237 |               type: "text",
1238 |               text: `Error: ${nameValidation.message}`
1239 |             }]
1240 |           };
1241 |         }
1242 |         
1243 |         // Validate phase description (optional but if provided, validate)
1244 |         if (phaseDescription && phaseDescription.trim() !== "") {
1245 |           const descValidation = validateRequiredText(phaseDescription, "Phase description", 5, 1000);
1246 |           if (!descValidation.valid) {
1247 |             return {
1248 |               content: [{
1249 |                 type: "text",
1250 |                 text: `Error: ${descValidation.message}`
1251 |               }]
1252 |             };
1253 |           }
1254 |         }
1255 |         
1256 |         // Parse and validate tasks
1257 |         let tasks = [];
1258 |         try {
1259 |           tasks = JSON.parse(tasksJson);
1260 |           if (!Array.isArray(tasks)) {
1261 |             return {
1262 |               content: [{
1263 |                 type: "text",
1264 |                 text: "Error: Tasks must be a valid JSON array of task descriptions"
1265 |               }]
1266 |             };
1267 |           }
1268 |           
1269 |           // Validate each task description
1270 |           for (let i = 0; i < tasks.length; i++) {
1271 |             const taskDesc = tasks[i];
1272 |             if (typeof taskDesc !== 'string' || taskDesc.trim().length < 3) {
1273 |               return {
1274 |                 content: [{
1275 |                   type: "text",
1276 |                   text: `Error: Task at index ${i} must be a string with at least 3 characters`
1277 |                 }]
1278 |               };
1279 |             }
1280 |           }
1281 |         } catch (e) {
1282 |           return {
1283 |             content: [{
1284 |               type: "text",
1285 |               text: "Error: Could not parse tasks JSON. Please provide a valid JSON array."
1286 |             }]
1287 |           };
1288 |         }
1289 |         
1290 |         const feature = featureResult.data;
1291 |         
1292 |         // Create the phase
1293 |         const phase = createPhase(featureId, nameValidation.data, phaseDescription);
1294 |         
1295 |         if (!phase) {
1296 |           return {
1297 |             content: [{
1298 |               type: "text",
1299 |               text: `Error: Failed to create phase for feature ${feature.name}`
1300 |             }]
1301 |           };
1302 |         }
1303 |         
1304 |         // Add tasks if provided
1305 |         if (tasks.length > 0) {
1306 |           tasks.forEach(taskDesc => {
1307 |             addTask(featureId, phase.id, taskDesc);
1308 |           });
1309 |         }
1310 |         
1311 |         return {
1312 |           content: [{
1313 |             type: "text",
1314 |             text: `Phase "${phaseName}" created with ID: ${phase.id}`
1315 |           }]
1316 |         };
1317 |       }
1318 |       
1319 |       case "update_phase_status": {
1320 |         const featureId = String(request.params.arguments?.featureId || "");
1321 |         const phaseId = String(request.params.arguments?.phaseId || "");
1322 |         const status = String(request.params.arguments?.status || "");
1323 |         
1324 |         // Validate feature and phase
1325 |         const validationResult = validateFeaturePhaseTask(featureId, phaseId);
1326 |         if (!validationResult.valid) {
1327 |           return {
1328 |             content: [{
1329 |               type: "text",
1330 |               text: `Error: ${validationResult.message}`
1331 |             }]
1332 |           };
1333 |         }
1334 |         
1335 |         // Validate status
1336 |         const statusValidation = validatePhaseStatusValue(status);
1337 |         if (!statusValidation.valid) {
1338 |           return {
1339 |             content: [{
1340 |               type: "text",
1341 |               text: `Error: ${statusValidation.message}`
1342 |             }]
1343 |           };
1344 |         }
1345 |         
1346 |         const { feature, phase } = validationResult.data;
1347 |         
1348 |         // Update the phase status
1349 |         const updatedPhase = updatePhaseStatus(featureId, phaseId, statusValidation.data);
1350 |         
1351 |         return {
1352 |           content: [{
1353 |             type: "text",
1354 |             text: `Phase status updated to "${status}"`
1355 |           }]
1356 |         };
1357 |       }
1358 |       
1359 |       case "add_task": {
1360 |         const featureId = String(request.params.arguments?.featureId || "");
1361 |         const phaseId = String(request.params.arguments?.phaseId || "");
1362 |         const taskDescription = String(request.params.arguments?.description || "");
1363 |         
1364 |         // Validate feature and phase
1365 |         const validationResult = validateFeaturePhaseTask(featureId, phaseId);
1366 |         if (!validationResult.valid) {
1367 |           return {
1368 |             content: [{
1369 |               type: "text",
1370 |               text: `Error: ${validationResult.message}`
1371 |             }]
1372 |           };
1373 |         }
1374 |         
1375 |         // Validate task description
1376 |         const descValidation = validateRequiredText(taskDescription, "Task description", 3, 500);
1377 |         if (!descValidation.valid) {
1378 |           return {
1379 |             content: [{
1380 |               type: "text",
1381 |               text: `Error: ${descValidation.message}`
1382 |             }]
1383 |           };
1384 |         }
1385 |         
1386 |         const { feature, phase } = validationResult.data;
1387 |         
1388 |         // Add the task
1389 |         const taskId = addTask(featureId, phaseId, descValidation.data);
1390 |         
1391 |         return {
1392 |           content: [{
1393 |             type: "text",
1394 |             text: `Task added to phase "${phase.name}" with ID: ${taskId}`
1395 |           }]
1396 |         };
1397 |       }
1398 |       
1399 |       case "update_task_status": {
1400 |         const featureId = String(request.params.arguments?.featureId || "");
1401 |         const phaseId = String(request.params.arguments?.phaseId || "");
1402 |         const taskId = String(request.params.arguments?.taskId || "");
1403 |         const completed = Boolean(request.params.arguments?.completed);
1404 |         
1405 |         // Validate feature, phase and task
1406 |         const validationResult = validateFeaturePhaseTask(featureId, phaseId, taskId);
1407 |         if (!validationResult.valid) {
1408 |           return {
1409 |             content: [{
1410 |               type: "text",
1411 |               text: `Error: ${validationResult.message}`
1412 |             }]
1413 |           };
1414 |         }
1415 |         
1416 |         const { feature, phase, task } = validationResult.data;
1417 |         
1418 |         // Update the task status
1419 |         const updatedTask = updateTaskStatus(featureId, phaseId, taskId, completed);
1420 |         
1421 |         // Check if all tasks are completed and suggest phase update if applicable
1422 |         let message = `Task status updated to ${completed ? 'completed' : 'not completed'}`;
1423 |         
1424 |         // @ts-ignore - We know the task structure from our validation
1425 |         if (completed && phase.tasks.every(t => t.id === taskId || t.completed)) {
1426 |           // All tasks are now completed
1427 |           message += `. All tasks in phase ${phase.name} are now completed. Consider updating the phase status to 'completed'.`;
1428 |         }
1429 |         
1430 |         return {
1431 |           content: [{
1432 |             type: "text",
1433 |             text: message
1434 |           }]
1435 |         };
1436 |       }
1437 |       
1438 |       case "get_next_phase_action": {
1439 |         const featureId = String(request.params.arguments?.featureId || "");
1440 |         
1441 |         // Validate feature ID
1442 |         const featureResult = validateFeatureId(featureId);
1443 |         if (!featureResult.valid) {
1444 |           return {
1445 |             content: [{
1446 |               type: "text",
1447 |               text: `Error: ${featureResult.message}`
1448 |             }]
1449 |           };
1450 |         }
1451 |         
1452 |         const feature = featureResult.data;
1453 |         
1454 |         // Find the current active phase (first non-completed/reviewed phase)
1455 |         // @ts-ignore - We know the phase structure from our Feature type
1456 |         const currentPhase = feature.phases.find(p => p.status === 'pending' || p.status === 'in_progress');
1457 |         
1458 |         if (!currentPhase) {
1459 |           // All phases are completed or reviewed
1460 |           return {
1461 |             content: [{
1462 |               type: "text",
1463 |               text: 'All phases are completed or reviewed. The feature implementation is done!'
1464 |             }]
1465 |           };
1466 |         }
1467 |         
1468 |         // Check task completion status
1469 |         // @ts-ignore - We know the task structure from our Phase type
1470 |         const completedTasks = currentPhase.tasks.filter(t => t.completed);
1471 |         // @ts-ignore - We know the task structure from our Phase type
1472 |         const pendingTasks = currentPhase.tasks.filter(t => !t.completed);
1473 |         
1474 |         // Determine next action based on phase and task status
1475 |         let message = '';
1476 |         
1477 |         if (currentPhase.status === 'pending') {
1478 |           message = `Phase "${currentPhase.name}" is pending. Start working on this phase by setting its status to "in_progress".`;
1479 |         } else if (currentPhase.status === 'in_progress') {
1480 |           if (pendingTasks.length > 0) {
1481 |             message = `${completedTasks.length}/${currentPhase.tasks.length} tasks are completed in phase "${currentPhase.name}". Continue working on pending tasks.`;
1482 |           } else if (currentPhase.tasks.length === 0) {
1483 |             message = `Phase "${currentPhase.name}" has no tasks defined. Add tasks or mark the phase as completed if appropriate.`;
1484 |           } else {
1485 |             // All tasks are completed
1486 |             message = `All tasks in phase "${currentPhase.name}" are completed. Consider marking this phase as completed.`;
1487 |           }
1488 |         }
1489 |         
1490 |         return {
1491 |           content: [{
1492 |             type: "text",
1493 |             text: message
1494 |           }]
1495 |         };
1496 |       }
1497 |       
1498 |       default:
1499 |         return {
1500 |           content: [{
1501 |             type: "text",
1502 |             text: `Error: Unknown tool "${request.params.name}"`
1503 |           }]
1504 |         };
1505 |     }
1506 |   } catch (error: any) {
1507 |     console.error('Error executing tool:', error);
1508 |     return {
1509 |       content: [{
1510 |         type: "text",
1511 |         text: `An unexpected error occurred: ${error.message || 'Unknown error'}`
1512 |       }]
1513 |     };
1514 |   }
1515 | });
1516 | 
1517 | /**
1518 |  * Handler that lists available prompts.
1519 |  */
1520 | server.setRequestHandler(ListPromptsRequestSchema, async () => {
1521 |   return {
1522 |     prompts: [
1523 |       {
1524 |         name: "clarify_feature",
1525 |         description: "Guide to clarify a feature request through questioning"
1526 |       }
1527 |     ]
1528 |   };
1529 | });
1530 | 
1531 | /**
1532 |  * Handler for the clarify_feature prompt.
1533 |  * Returns a prompt that guides feature clarification.
1534 |  */
1535 | server.setRequestHandler(GetPromptRequestSchema, async (request) => {
1536 |   if (request.params.name === "clarify_feature") {
1537 |     return {
1538 |       messages: [
1539 |         {
1540 |           role: "user",
1541 |           content: {
1542 |             type: "text",
1543 |             text: "Help me clarify this feature request by asking questions about:"
1544 |           }
1545 |         },
1546 |         {
1547 |           role: "user",
1548 |           content: {
1549 |             type: "text",
1550 |             text: "1. The specific problem it solves\n2. The target users\n3. Key requirements\n4. Success criteria\n5. Technical constraints\n\nAsk one question at a time, analyze the response, then proceed to the next most relevant question."
1551 |           }
1552 |         }
1553 |       ]
1554 |     };
1555 |   }
1556 |   
1557 |   throw new Error("Unknown prompt");
1558 | });
1559 | 
1560 | /**
1561 |  * Start the server using stdio transport.
1562 |  * This allows the server to communicate via standard input/output streams.
1563 |  */
1564 | async function main() {
1565 |   console.error("Starting Vibe-Coder MCP Server...");
1566 |   
1567 |   const transport = new StdioServerTransport();
1568 |   await server.connect(transport);
1569 | }
1570 | 
1571 | main().catch((error) => {
1572 |   console.error("Server error:", error);
1573 |   process.exit(1);
1574 | });
1575 | 
```
Page 2/4FirstPrevNextLast