#
tokens: 16078/50000 2/41 files (page 2/4)
lines: off (toggle) GitHub
raw markdown copy
This is page 2 of 4. Use http://codebase.md/crazyrabbitltc/mcp-vibecoder?lines=false&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/tool-handlers.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * @file tool-handlers.ts
 * @version 1.0.0
 * 
 * Provides handlers for the MCP tools exposed by the Vibe-Coder MCP Server.
 * These handlers are registered with the tool registry for consistent handling.
 */

import { z } from 'zod';
import { ToolHandler, toolRegistry } from './registry.js';
import { getFeature, updateFeature } from './storage.js';
import { 
  getNextClarificationQuestion,
  isClarificationComplete, 
  getClarificationStatus 
} from './clarification.js';
import { 
  generatePRD, 
  generateImplementationPlan 
} from './documentation.js';
import {
  createPhase,
  updatePhaseStatus,
  addTask,
  updateTaskStatus
} from './phases.js';
import {
  createFeatureObject
} from './utils.js';
import {
  validateFeatureId,
  validatePhaseId,
  validateTaskId,
  validateFeaturePhaseTask,
  validateRequiredText,
  validatePhaseStatusValue
} from './validators.js';
import { 
  createToolErrorResponse, 
  featureNotFoundError, 
  phaseNotFoundError, 
  taskNotFoundError, 
  invalidPhaseTransitionError, 
  clarificationIncompleteError 
} from './errors.js';
import { Phase, Task } from './types.js';

// Schema for start_feature_clarification
const StartFeatureClarificationSchema = z.object({
  featureName: z.string().min(2).max(100),
  initialDescription: z.string().optional().default("")
});

/**
 * Start feature clarification handler
 */
const startFeatureClarificationHandler: ToolHandler<z.infer<typeof StartFeatureClarificationSchema>> = async (params) => {
  try {
    const { featureName, initialDescription } = StartFeatureClarificationSchema.parse(params);
    
    // Create a new feature
    const feature = createFeatureObject(featureName, initialDescription);
    updateFeature(feature.id, feature);
    
    // Get the first clarification question
    const firstQuestion = getNextClarificationQuestion(feature);
    
    return {
      content: [{
        type: "text",
        text: `Feature ID: ${feature.id}\n\nLet's clarify your feature request. ${firstQuestion}`
      }]
    };
  } catch (error) {
    if (error instanceof z.ZodError) {
      const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
      return createToolErrorResponse(`Validation error: ${errorMessage}`);
    }
    return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
  }
};

// Schema for provide_clarification
const ProvideClarificationSchema = z.object({
  featureId: z.string().min(1),
  question: z.string().min(1),
  answer: z.string().min(1)
});

/**
 * Provide clarification handler
 */
const provideClarificationHandler: ToolHandler<z.infer<typeof ProvideClarificationSchema>> = async (params) => {
  try {
    const { featureId, question, answer } = ProvideClarificationSchema.parse(params);
    
    console.log(`\n[CLARIFICATION] Received request for feature ${featureId}\n  Question: "${question.substring(0, 50)}..."\n  Answer: "${answer.substring(0, 50)}..."`);
    
    // Get the feature
    const feature = getFeature(featureId);
    if (!feature) {
      console.log(`[CLARIFICATION] Feature ID ${featureId} not found`);
      return featureNotFoundError(featureId);
    }
    
    console.log(`[CLARIFICATION] Found feature: ${feature.name} with ${feature.clarificationResponses.length} existing responses`);
    
    // Add the clarification response to the feature
    feature.clarificationResponses.push({
      question,
      answer,
      timestamp: new Date()
    });
    
    console.log(`[CLARIFICATION] Added response, now has ${feature.clarificationResponses.length} responses`);
    
    // Save the feature with the updated clarification response
    updateFeature(featureId, feature);
    
    // Get the next question or indicate all questions are answered
    const nextQuestion = getNextClarificationQuestion(feature);
    
    if (nextQuestion) {
      // Check if nextQuestion is a string before using substring
      const questionPreview = typeof nextQuestion === 'string' 
        ? nextQuestion.substring(0, 50) + "..." 
        : "All questions answered";
      console.log(`[CLARIFICATION] Returning next question: "${questionPreview}"`);
      return {
        content: [{
          type: "text",
          text: `Response recorded. ${nextQuestion}`
        }]
      };
    } else {
      // All questions answered
      console.log(`[CLARIFICATION] All questions answered`);
      return {
        content: [{
          type: "text",
          text: "All clarification questions have been answered. You can now generate a PRD for this feature."
        }]
      };
    }
  } catch (error) {
    if (error instanceof z.ZodError) {
      const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
      return createToolErrorResponse(`Validation error: ${errorMessage}`);
    }
    return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
  }
};

// Schema for generate_prd
const GeneratePrdSchema = z.object({
  featureId: z.string().min(1)
});

/**
 * Generate PRD handler
 */
const generatePrdHandler: ToolHandler<z.infer<typeof GeneratePrdSchema>> = async (params) => {
  try {
    const { featureId } = GeneratePrdSchema.parse(params);
    
    // Validate feature ID
    const featureResult = validateFeatureId(featureId);
    if (!featureResult.valid) {
      return createToolErrorResponse(featureResult.message);
    }
    
    const feature = featureResult.data;
    
    // Check if clarifications are complete
    if (!isClarificationComplete(feature)) {
      return clarificationIncompleteError(getClarificationStatus(feature));
    }
    
    // Generate PRD
    const prdDoc = generatePRD(feature);
    
    // Store the document
    feature.prdDoc = prdDoc;
    updateFeature(featureId, feature);
    
    return {
      content: [{
        type: "text",
        text: `PRD generated for feature ${feature.name}. You can view it using the resource URI: feature://${feature.id}/prd`
      }]
    };
  } catch (error) {
    if (error instanceof z.ZodError) {
      const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
      return createToolErrorResponse(`Validation error: ${errorMessage}`);
    }
    return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
  }
};

// Schema for generate_implementation_plan
const GenerateImplementationPlanSchema = z.object({
  featureId: z.string().min(1)
});

/**
 * Generate implementation plan handler
 */
const generateImplementationPlanHandler: ToolHandler<z.infer<typeof GenerateImplementationPlanSchema>> = async (params) => {
  try {
    const { featureId } = GenerateImplementationPlanSchema.parse(params);
    
    // Validate feature ID
    const featureResult = validateFeatureId(featureId);
    if (!featureResult.valid) {
      return createToolErrorResponse(featureResult.message);
    }
    
    const feature = featureResult.data;
    
    // Check if clarifications are complete
    if (!isClarificationComplete(feature)) {
      return clarificationIncompleteError(getClarificationStatus(feature));
    }
    
    // Generate the implementation plan
    const implDoc = generateImplementationPlan(feature);
    
    // Store the document
    feature.implDoc = implDoc;
    updateFeature(featureId, feature);
    
    return {
      content: [{
        type: "text",
        text: `Implementation plan generated for feature ${feature.name}. You can view it using the resource URI: feature://${feature.id}/implementation`
      }]
    };
  } catch (error) {
    if (error instanceof z.ZodError) {
      const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
      return createToolErrorResponse(`Validation error: ${errorMessage}`);
    }
    return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
  }
};

// Schema for create_phase
const CreatePhaseSchema = z.object({
  featureId: z.string().min(1),
  name: z.string().min(2).max(100),
  description: z.string().min(1)
});

/**
 * Create phase handler
 */
const createPhaseHandler: ToolHandler<z.infer<typeof CreatePhaseSchema>> = async (params) => {
  try {
    const { featureId, name, description } = CreatePhaseSchema.parse(params);
    
    // Validate feature ID
    const featureResult = validateFeatureId(featureId);
    if (!featureResult.valid) {
      return createToolErrorResponse(featureResult.message);
    }
    
    const feature = featureResult.data;
    
    // Create the phase
    const phase = createPhase(featureId, name, description);
    
    if (!phase) {
      return createToolErrorResponse(`Failed to create phase for feature ${feature.name}`);
    }
    
    return {
      content: [{
        type: "text",
        text: `Phase "${name}" created with ID: ${phase.id}`
      }]
    };
  } catch (error) {
    if (error instanceof z.ZodError) {
      const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
      return createToolErrorResponse(`Validation error: ${errorMessage}`);
    }
    return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
  }
};

// Schema for update_phase_status
const UpdatePhaseStatusSchema = z.object({
  featureId: z.string().min(1),
  phaseId: z.string().min(1),
  status: z.enum(["pending", "in_progress", "completed", "reviewed"])
});

/**
 * Update phase status handler
 */
const updatePhaseStatusHandler: ToolHandler<z.infer<typeof UpdatePhaseStatusSchema>> = async (params) => {
  try {
    const { featureId, phaseId, status } = UpdatePhaseStatusSchema.parse(params);
    
    // Validate feature and phase
    const validationResult = validateFeaturePhaseTask(featureId, phaseId);
    if (!validationResult.valid) {
      return createToolErrorResponse(validationResult.message);
    }
    
    const { feature, phase } = validationResult.data;
    
    // Validate the status transition
    const transitionResult = phase.status !== status; 
    if (!transitionResult) {
      return invalidPhaseTransitionError(phase.status, status);
    }
    
    // Update the phase status
    const updatedPhase = updatePhaseStatus(featureId, phaseId, status);
    
    return {
      content: [{
        type: "text",
        text: `Phase status updated to "${status}"`
      }]
    };
  } catch (error) {
    if (error instanceof z.ZodError) {
      const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
      return createToolErrorResponse(`Validation error: ${errorMessage}`);
    }
    return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
  }
};

// Schema for add_task
const AddTaskSchema = z.object({
  featureId: z.string().min(1),
  phaseId: z.string().min(1),
  description: z.string().min(3).max(500)
});

/**
 * Add task handler
 */
const addTaskHandler: ToolHandler<z.infer<typeof AddTaskSchema>> = async (params) => {
  try {
    const { featureId, phaseId, description } = AddTaskSchema.parse(params);
    
    // Validate feature and phase
    const validationResult = validateFeaturePhaseTask(featureId, phaseId);
    if (!validationResult.valid) {
      return createToolErrorResponse(validationResult.message);
    }
    
    const { feature, phase } = validationResult.data;
    
    // Add the task
    const taskId = addTask(featureId, phaseId, description);
    
    return {
      content: [{
        type: "text",
        text: `Task added to phase "${phase.name}" with ID: ${taskId}`
      }]
    };
  } catch (error) {
    if (error instanceof z.ZodError) {
      const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
      return createToolErrorResponse(`Validation error: ${errorMessage}`);
    }
    return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
  }
};

// Schema for update_task_status
const UpdateTaskStatusSchema = z.object({
  featureId: z.string().min(1),
  phaseId: z.string().min(1),
  taskId: z.string().min(1),
  completed: z.boolean()
});

/**
 * Update task status handler
 */
const updateTaskStatusHandler: ToolHandler<z.infer<typeof UpdateTaskStatusSchema>> = async (params) => {
  try {
    const { featureId, phaseId, taskId, completed } = UpdateTaskStatusSchema.parse(params);
    
    // Validate feature, phase and task
    const validationResult = validateFeaturePhaseTask(featureId, phaseId, taskId);
    if (!validationResult.valid) {
      return createToolErrorResponse(validationResult.message);
    }
    
    const { feature, phase, task } = validationResult.data;
    
    // Update the task status
    const updatedTask = updateTaskStatus(featureId, phaseId, taskId, completed);
    
    // Check if all tasks in this phase are now completed
    if (completed && phase.tasks.every((t: Task) => t.id === taskId || t.completed)) {
      // Auto-advance the phase to 'completed' status
      return {
        content: [{
          type: "text",
          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.`
        }]
      };
    }
    
    // Check if all tasks are completed and suggest phase update if applicable
    let message = `Task status updated to ${completed ? 'completed' : 'not completed'}`;
    
    if (completed && phase.tasks.every((t: Task) => t.id === taskId || t.completed)) {
      // All tasks are now completed
      message += `. All tasks in phase ${phase.name} are now completed. Consider updating the phase status to 'completed'.`;
    }
    
    return {
      content: [{
        type: "text",
        text: message
      }]
    };
  } catch (error) {
    if (error instanceof z.ZodError) {
      const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
      return createToolErrorResponse(`Validation error: ${errorMessage}`);
    }
    return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
  }
};

// Schema for get_next_phase_action
const GetNextPhaseActionSchema = z.object({
  featureId: z.string().min(1)
});

/**
 * Get next phase action handler
 */
const getNextPhaseActionHandler: ToolHandler<z.infer<typeof GetNextPhaseActionSchema>> = async (params) => {
  try {
    const { featureId } = GetNextPhaseActionSchema.parse(params);
    
    // Validate feature ID
    const featureResult = validateFeatureId(featureId);
    if (!featureResult.valid) {
      return createToolErrorResponse(featureResult.message);
    }
    
    const feature = featureResult.data;
    
    // Find the current active phase (first non-completed/reviewed phase)
    const currentPhase = feature.phases.find((p: Phase) => p.status === 'pending' || p.status === 'in_progress');
    
    if (!currentPhase) {
      // All phases are completed or reviewed
      return {
        content: [{
          type: "text",
          text: 'All phases are completed or reviewed. The feature implementation is done!'
        }]
      };
    }
    
    // Check task completion status
    const completedTasks = currentPhase.tasks.filter((t: Task) => t.completed);
    const pendingTasks = currentPhase.tasks.filter((t: Task) => !t.completed);
    
    // Determine next action based on phase and task status
    let message = '';
    
    if (currentPhase.status === 'pending') {
      message = `Phase "${currentPhase.name}" is pending. Start working on this phase by setting its status to "in_progress".`;
    } else if (currentPhase.status === 'in_progress') {
      if (pendingTasks.length > 0) {
        message = `${completedTasks.length}/${currentPhase.tasks.length} tasks are completed in phase "${currentPhase.name}". Continue working on pending tasks.`;
      } else if (currentPhase.tasks.length === 0) {
        message = `Phase "${currentPhase.name}" has no tasks defined. Add tasks or mark the phase as completed if appropriate.`;
      } else {
        // All tasks are completed
        message = `All tasks in phase "${currentPhase.name}" are completed. Consider marking this phase as completed.`;
      }
    }
    
    return {
      content: [{
        type: "text",
        text: message
      }]
    };
  } catch (error) {
    if (error instanceof z.ZodError) {
      const errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
      return createToolErrorResponse(`Validation error: ${errorMessage}`);
    }
    return createToolErrorResponse(error instanceof Error ? error.message : "Unknown error");
  }
};

/**
 * Register all tool handlers with the tool registry
 */
export function registerToolHandlers() {
  toolRegistry.register(
    'start_feature_clarification', 
    startFeatureClarificationHandler,
    'Start the clarification process for a new feature',
    {
      type: "object",
      properties: {
        featureName: {
          type: "string",
          description: "Name of the feature"
        },
        initialDescription: {
          type: "string",
          description: "Initial description of the feature"
        }
      },
      required: ["featureName"]
    },
    [
      {
        featureName: "User Authentication",
        initialDescription: "Add login and registration functionality to the application"
      },
      {
        featureName: "Data Export",
        initialDescription: "Allow users to export their data in CSV and JSON formats"
      }
    ]
  );

  toolRegistry.register(
    'provide_clarification', 
    provideClarificationHandler,
    'Provide answer to a clarification question',
    {
      type: "object",
      properties: {
        featureId: {
          type: "string",
          description: "ID of the feature"
        },
        question: {
          type: "string",
          description: "Clarification question"
        },
        answer: {
          type: "string",
          description: "Answer to the clarification question"
        }
      },
      required: ["featureId", "question", "answer"]
    },
    [
      {
        featureId: "feature-123",
        question: "What problem does this feature solve?",
        answer: "This feature solves the problem of users forgetting their passwords by providing a secure password reset flow."
      },
      {
        featureId: "feature-456",
        question: "Who are the target users?",
        answer: "The target users are administrators who need to manage user accounts and permissions."
      }
    ]
  );

  toolRegistry.register(
    'generate_prd', 
    generatePrdHandler,
    'Generate a PRD document based on clarification responses',
    {
      type: "object",
      properties: {
        featureId: {
          type: "string",
          description: "ID of the feature"
        }
      },
      required: ["featureId"]
    },
    [
      { featureId: "feature-123" }
    ]
  );

  toolRegistry.register(
    'generate_implementation_plan', 
    generateImplementationPlanHandler,
    'Generate an implementation plan for a feature based on clarifications and PRD',
    {
      type: 'object',
      properties: {
        featureId: {
          type: 'string',
          description: 'The ID of the feature to generate an implementation plan for'
        }
      },
      required: ['featureId']
    }
  );

  toolRegistry.register(
    'create_phase', 
    createPhaseHandler,
    'Create a new development phase for a feature',
    {
      type: 'object',
      properties: {
        featureId: {
          type: 'string',
          description: 'ID of the feature to create a phase for'
        },
        name: {
          type: 'string',
          description: 'Name of the phase'
        },
        description: {
          type: 'string',
          description: 'Description of the phase'
        }
      },
      required: ['featureId', 'name', 'description']
    },
    [
      {
        featureId: "feature-123",
        name: "Requirements Analysis",
        description: "Gather and analyze requirements for the feature"
      },
      {
        featureId: "feature-123",
        name: "Implementation",
        description: "Implement the core functionality of the feature"
      }
    ]
  );

  toolRegistry.register(
    'update_phase_status', 
    updatePhaseStatusHandler,
    'Update the status of a development phase',
    {
      type: 'object',
      properties: {
        featureId: {
          type: 'string',
          description: 'ID of the feature containing the phase'
        },
        phaseId: {
          type: 'string',
          description: 'ID of the phase to update'
        },
        status: {
          type: 'string',
          description: 'New status for the phase (pending, in_progress, completed, reviewed)'
        }
      },
      required: ['featureId', 'phaseId', 'status']
    },
    [
      {
        featureId: "feature-123",
        phaseId: "phase-456",
        status: "in_progress"
      },
      {
        featureId: "feature-123",
        phaseId: "phase-456",
        status: "completed"
      }
    ]
  );

  toolRegistry.register(
    'add_task', 
    addTaskHandler,
    'Add a task to a development phase',
    {
      type: 'object',
      properties: {
        featureId: {
          type: 'string',
          description: 'ID of the feature containing the phase'
        },
        phaseId: {
          type: 'string',
          description: 'ID of the phase to add the task to'
        },
        description: {
          type: 'string',
          description: 'Description of the task'
        }
      },
      required: ['featureId', 'phaseId', 'description']
    },
    [
      {
        featureId: "feature-123",
        phaseId: "phase-456",
        description: "Create database migration scripts"
      },
      {
        featureId: "feature-123",
        phaseId: "phase-456",
        description: "Implement user interface components"
      }
    ]
  );

  toolRegistry.register(
    'update_task_status', 
    updateTaskStatusHandler,
    'Update the completion status of a task',
    {
      type: 'object',
      properties: {
        featureId: {
          type: 'string',
          description: 'ID of the feature containing the phase'
        },
        phaseId: {
          type: 'string',
          description: 'ID of the phase containing the task'
        },
        taskId: {
          type: 'string',
          description: 'ID of the task to update'
        },
        completed: {
          type: 'boolean',
          description: 'Whether the task is completed'
        }
      },
      required: ['featureId', 'phaseId', 'taskId', 'completed']
    },
    [
      {
        featureId: "feature-123",
        phaseId: "phase-456",
        taskId: "task-789",
        completed: true
      },
      {
        featureId: "feature-123",
        phaseId: "phase-456",
        taskId: "task-789",
        completed: false
      }
    ]
  );

  toolRegistry.register(
    'get_next_phase_action', 
    getNextPhaseActionHandler,
    'Get guidance on what to do next in the current phase or whether to move to the next phase',
    {
      type: 'object',
      properties: {
        featureId: {
          type: 'string',
          description: 'ID of the feature'
        }
      },
      required: ['featureId']
    },
    [
      { featureId: "feature-123" }
    ]
  );
}

// Export all handlers for testing or direct usage
export {
  startFeatureClarificationHandler,
  provideClarificationHandler,
  generatePrdHandler,
  generateImplementationPlanHandler,
  createPhaseHandler,
  updatePhaseStatusHandler,
  addTaskHandler,
  updateTaskStatusHandler,
  getNextPhaseActionHandler
}; 
```

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

```typescript
#!/usr/bin/env node

/**
 * @file Vibe-Coder MCP Server
 * @version 0.1.0
 * 
 * This MCP server implements a structured development workflow that helps
 * LLM-based coders build features in an organized, clean, and safe manner.
 * 
 * Core functionalities:
 * - Feature request clarification through iterative questioning
 * - PRD and implementation plan generation
 * - Phased development with tasks and status tracking
 */

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListResourcesRequestSchema,
  ListToolsRequestSchema,
  ReadResourceRequestSchema,
  ListPromptsRequestSchema,
  GetPromptRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

// Import core modules
import { Feature, FeatureStorage, PhaseStatus, Phase, Task, ClarificationResponse } from './types.js';
import { features, storeFeature, getFeature, updateFeature, listFeatures } from './storage.js';
import { 
  DEFAULT_CLARIFICATION_QUESTIONS as CLARIFICATION_QUESTIONS, 
  getNextClarificationQuestion, 
  addClarificationResponse,
  formatClarificationResponses,
  isClarificationComplete,
  getClarificationStatus
} from './clarification.js';
import {
  generatePRD,
  generateImplementationPlan,
  extractObjectivesFromClarifications,
  extractRequirementsFromClarifications,
  extractTechnicalSpecsFromClarifications
} from './documentation.js';
import { 
  createPhase, 
  getPhase, 
  updatePhaseStatus,
  getNextPhaseStatus,
  validatePhaseTransition,
  addTask,
  updateTaskStatus
} from './phases.js';
import { 
  generateId, 
  createFeatureObject,
  createPhaseObject,
  createTaskObject,
  generateFeatureProgressSummary,
  isValidPhaseStatus
} from './utils.js';
import { validateFeatureId, validatePhaseId, validateTaskId, validateFeaturePhaseTask, validateRequiredText, validatePhaseStatusValue } from './validators.js';

/**
 * Type alias for a note object.
 */
type Note = { title: string, content: string };

/**
 * Simple in-memory storage for notes.
 * In a real implementation, this would likely be backed by a database.
 */
const notes: { [id: string]: Note } = {
  "1": { title: "First Note", content: "This is note 1" },
  "2": { title: "Second Note", content: "This is note 2" }
};

/**
 * Create an MCP server with capabilities for resources, tools, and prompts
 */
const server = new Server(
  {
    name: "Vibe-Coder MCP Server",
    version: "0.1.0",
  },
  {
    capabilities: {
      resources: {}, // Expose resources for features, PRDs, and implementation plans
      tools: {},     // Provide tools for feature clarification and development
      prompts: {},   // Supply prompts for guiding the development process
    },
  }
);

/**
 * Handler for listing available resources.
 * Exposes:
 * - A list of all features
 * - Individual feature details
 * - PRD and implementation plan documents
 * - Phase and task details
 */
server.setRequestHandler(ListResourcesRequestSchema, async () => {
  return {
    resources: [
      {
        uri: "features://list",
        mimeType: "text/plain",
        name: "Features List",
        description: "Lists all features being developed"
      },
      {
        uri: "features://status",
        mimeType: "text/markdown",
        name: "Project Status",
        description: "Provides a summary of all features and their development status"
      },
      ...listFeatures().flatMap(feature => [
        {
          uri: `feature://${feature.id}`,
          mimeType: "text/plain", 
          name: feature.name,
          description: `Details about feature: ${feature.name}`
        },
        {
          uri: `feature://${feature.id}/progress`,
          mimeType: "text/markdown",
          name: `${feature.name} Progress Report`,
          description: `Detailed progress report for feature: ${feature.name}`
        },
        {
          uri: `feature://${feature.id}/prd`,
          mimeType: "text/markdown",
          name: `${feature.name} PRD`,
          description: `PRD document for feature: ${feature.name}`
        },
        {
          uri: `feature://${feature.id}/implementation`,
          mimeType: "text/markdown",
          name: `${feature.name} Implementation Plan`,
          description: `Implementation plan for feature: ${feature.name}`
        },
        {
          uri: `feature://${feature.id}/phases`,
          mimeType: "text/plain",
          name: `${feature.name} Phases`,
          description: `Lists all phases for feature: ${feature.name}`
        },
        {
          uri: `feature://${feature.id}/tasks`,
          mimeType: "text/plain",
          name: `${feature.name} All Tasks`,
          description: `Lists all tasks across all phases for feature: ${feature.name}`
        },
        ...feature.phases.flatMap(phase => [
          {
            uri: `feature://${feature.id}/phase/${phase.id}`,
            mimeType: "text/plain",
            name: `${feature.name} - ${phase.name}`,
            description: `Details about phase: ${phase.name} for feature: ${feature.name}`
          },
          {
            uri: `feature://${feature.id}/phase/${phase.id}/tasks`,
            mimeType: "text/plain",
            name: `${feature.name} - ${phase.name} Tasks`,
            description: `Lists all tasks for phase: ${phase.name}`
          },
          ...phase.tasks.map(task => ({
            uri: `feature://${feature.id}/phase/${phase.id}/task/${task.id}`,
            mimeType: "text/plain",
            name: `Task: ${task.description.substring(0, 30)}${task.description.length > 30 ? '...' : ''}`,
            description: `Details about task: ${task.description.substring(0, 50)}${task.description.length > 50 ? '...' : ''}`
          }))
        ])
      ])
    ]
  };
});

/**
 * Handler for reading feature resources.
 * Supports:
 * - List of all features
 * - Individual feature details
 * - PRD and implementation plan documents
 * - Phase and task details
 */
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  try {
    const url = new URL(request.params.uri);
    
    // Handle list of all features
    if (url.protocol === "features:") {
      if (url.pathname === "/list") {
        return {
          contents: [{
            uri: request.params.uri,
            mimeType: "text/plain",
            text: listFeatures().map(f => `${f.id}: ${f.name}`).join("\n")
          }]
        };
      }
      
      if (url.pathname === "/status") {
        const features = listFeatures();
        
        if (features.length === 0) {
          return {
            contents: [{
              uri: request.params.uri,
              mimeType: "text/markdown",
              text: "# Project Status\n\nNo features have been created yet."
            }]
          };
        }
        
        const featuresStatus = features.map(feature => {
          const totalPhases = feature.phases.length;
          const completedPhases = feature.phases.filter(p => p.status === 'completed' || p.status === 'reviewed').length;
          const totalTasks = feature.phases.reduce((acc, phase) => acc + phase.tasks.length, 0);
          const completedTasks = feature.phases.reduce(
            (acc, phase) => acc + phase.tasks.filter(t => t.completed).length, 0
          );
          
          return `## ${feature.name}
- ID: ${feature.id}
- Status: ${completedPhases === totalPhases && totalPhases > 0 ? 'Completed' : 'In Progress'}
- Phases: ${completedPhases}/${totalPhases} completed
- Tasks: ${completedTasks}/${totalTasks} completed
- [View Details](feature://${feature.id}/progress)
`;
        }).join('\n');
        
        return {
          contents: [{
            uri: request.params.uri,
            mimeType: "text/markdown",
            text: `# Project Status\n\n${featuresStatus}`
          }]
        };
      }
    }
    
    // Handle feature-specific resources
    if (url.protocol === "feature:") {
      // The hostname part is actually our feature ID in feature:// URLs
      let featureId = "";
      
      if (url.hostname) {
        featureId = url.hostname;
      } else {
        // Try to get feature ID from pathname for backward compatibility
        const parts = url.pathname.split('/').filter(Boolean);
        if (parts.length > 0) {
          featureId = parts[0];
        }
      }
      
      if (!featureId) {
        throw new Error(`Invalid feature URI: ${request.params.uri}. Missing feature ID.`);
      }
      
      const feature = getFeature(featureId);
      
      if (!feature) {
        throw new Error(`Feature ${featureId} not found`);
      }
      
      // Extract path parts, excluding empty strings
      const parts = url.pathname.split('/').filter(Boolean);
      
      // Return feature details - no additional path parts beyond the feature ID
      if (parts.length === 0) {
        const timestamp = feature.updatedAt.toISOString();
        const clarifications = formatClarificationResponses(feature.clarificationResponses);
        const phasesText = feature.phases.map(p => 
          `- ${p.name} (${p.status}): ${p.tasks.filter(t => t.completed).length}/${p.tasks.length} tasks completed`
        ).join('\n');
        
        const featureDetails = `
Feature: ${feature.name}
ID: ${feature.id}
Description: ${feature.description}
Last Updated: ${timestamp}

Clarification Responses:
${clarifications}

Phases (${feature.phases.length}):
${phasesText}
`;
        
        return {
          contents: [{
            uri: request.params.uri,
            mimeType: "text/plain",
            text: featureDetails
          }]
        };
      }
      
      // Resource is a sub-resource of the feature
      if (parts.length >= 1) {
        const subResource = parts[0];
        
        // Return feature progress report
        if (subResource === "progress") {
          const progressReport = generateFeatureProgressSummary(feature);
          
          return {
            contents: [{
              uri: request.params.uri,
              mimeType: "text/markdown",
              text: progressReport
            }]
          };
        }
        
        // Return PRD document
        if (subResource === "prd") {
          const prdContent = feature.prdDoc || generatePRD(feature);
          
          return {
            contents: [{
              uri: request.params.uri,
              mimeType: "text/markdown",
              text: prdContent
            }]
          };
        }
        
        // Return implementation plan document
        if (subResource === "implementation") {
          const implContent = feature.implDoc || generateImplementationPlan(feature);
          
          return {
            contents: [{
              uri: request.params.uri,
              mimeType: "text/markdown",
              text: implContent
            }]
          };
        }
        
        // Return phase listing
        if (subResource === "phases") {
          if (feature.phases.length === 0) {
            return {
              contents: [{
                uri: request.params.uri,
                mimeType: "text/plain",
                text: `No phases defined for feature: ${feature.name}`
              }]
            };
          }
          
          const phasesContent = feature.phases.map(phase => {
            const completedTasks = phase.tasks.filter(t => t.completed).length;
            const totalTasks = phase.tasks.length;
            return `Phase: ${phase.name} (ID: ${phase.id})
Status: ${phase.status}
Description: ${phase.description}
Progress: ${completedTasks}/${totalTasks} tasks completed
Last Updated: ${phase.updatedAt.toISOString()}
`;
          }).join('\n---\n\n');
          
          return {
            contents: [{
              uri: request.params.uri,
              mimeType: "text/plain",
              text: `# Phases for Feature: ${feature.name}\n\n${phasesContent}`
            }]
          };
        }
        
        // Handle list of all tasks for a feature
        if (subResource === "tasks") {
          const allTasks = feature.phases.flatMap(phase => 
            phase.tasks.map(task => ({
              ...task,
              phaseName: phase.name,
              phaseId: phase.id,
              phaseStatus: phase.status
            }))
          );
          
          if (allTasks.length === 0) {
            return {
              contents: [{
                uri: request.params.uri,
                mimeType: "text/plain",
                text: `No tasks defined for feature: ${feature.name}`
              }]
            };
          }
          
          const pendingTasks = allTasks.filter(t => !t.completed);
          const completedTasks = allTasks.filter(t => t.completed);
          
          const pendingTasksText = pendingTasks.length > 0 
            ? pendingTasks.map(task => `- [ ] ${task.description} (ID: ${task.id}, Phase: ${task.phaseName})`).join('\n')
            : "No pending tasks.";
            
          const completedTasksText = completedTasks.length > 0
            ? completedTasks.map(task => `- [x] ${task.description} (ID: ${task.id}, Phase: ${task.phaseName})`).join('\n')
            : "No completed tasks.";
          
          const tasksContent = `# All Tasks for Feature: ${feature.name}

## Pending Tasks (${pendingTasks.length})
${pendingTasksText}

## Completed Tasks (${completedTasks.length})
${completedTasksText}
`;
          
          return {
            contents: [{
              uri: request.params.uri,
              mimeType: "text/plain",
              text: tasksContent
            }]
          };
        }
        
        // Handle phase-specific resources
        if (subResource === "phase" && parts.length >= 2) {
          const phaseId = parts[1];
          const phase = feature.phases.find(p => p.id === phaseId);
          
          if (!phase) {
            throw new Error(`Phase ${phaseId} not found in feature ${feature.name}`);
          }
          
          // Return phase details
          if (parts.length === 2) {
            const completedTasks = phase.tasks.filter(t => t.completed).length;
            const totalTasks = phase.tasks.length;
            
            const taskList = phase.tasks.map(task => 
              `- [${task.completed ? 'x' : ' '}] ${task.description} (ID: ${task.id})`
            ).join('\n');
            
            const phaseDetails = `
Phase: ${phase.name}
ID: ${phase.id}
Status: ${phase.status}
Description: ${phase.description}
Created: ${phase.createdAt.toISOString()}
Last Updated: ${phase.updatedAt.toISOString()}
Progress: ${completedTasks}/${totalTasks} tasks completed

Tasks:
${taskList}
`;
            
            return {
              contents: [{
                uri: request.params.uri,
                mimeType: "text/plain",
                text: phaseDetails
              }]
            };
          }
          
          // Return task listing
          if (parts[2] === "tasks") {
            if (phase.tasks.length === 0) {
              return {
                contents: [{
                  uri: request.params.uri,
                  mimeType: "text/plain",
                  text: `No tasks defined for phase: ${phase.name}`
                }]
              };
            }
            
            const tasksContent = phase.tasks.map(task => `
Task: ${task.description}
ID: ${task.id}
Status: ${task.completed ? 'Completed' : 'Pending'}
Created: ${task.createdAt.toISOString()}
Last Updated: ${task.updatedAt.toISOString()}
`).join('\n---\n');
            
            return {
              contents: [{
                uri: request.params.uri,
                mimeType: "text/plain",
                text: `# Tasks for Phase: ${phase.name}\n\n${tasksContent}`
              }]
            };
          }
          
          // Return individual task details
          if (parts[2] === "task" && parts.length === 4) {
            const taskId = parts[3];
            const task = phase.tasks.find(t => t.id === taskId);
            
            if (!task) {
              throw new Error(`Task ${taskId} not found in phase ${phase.name}`);
            }
            
            const taskDetails = `
Task: ${task.description}
ID: ${task.id}
Status: ${task.completed ? 'Completed' : 'Pending'}
Created: ${task.createdAt.toISOString()}
Last Updated: ${task.updatedAt.toISOString()}
`;
            
            return {
              contents: [{
                uri: request.params.uri,
                mimeType: "text/plain",
                text: taskDetails
              }]
            };
          }
        }
      }
    }
    
    throw new Error(`Resource not found: ${request.params.uri}`);
  } catch (error: any) {
    console.error(`Error reading resource ${request.params.uri}:`, error);
    return {
      contents: [{
        uri: request.params.uri,
        mimeType: "text/plain",
        text: `Error: ${error.message || 'Unknown error'}`
      }]
    };
  }
});

/**
 * Handler that lists available tools.
 * Exposes tools for feature clarification and development.
 */
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "start_feature_clarification",
        description: "Start the clarification process for a new feature",
        inputSchema: {
          type: "object",
          properties: {
            featureName: {
              type: "string",
              description: "Name of the feature"
            },
            initialDescription: {
              type: "string",
              description: "Initial description of the feature"
            }
          },
          required: ["featureName"],
          examples: [
            {
              featureName: "User Authentication",
              initialDescription: "Add login and registration functionality to the application"
            },
            {
              featureName: "Data Export",
              initialDescription: "Allow users to export their data in CSV and JSON formats"
            }
          ]
        }
      },
      {
        name: "provide_clarification",
        description: "Provide answer to a clarification question",
        inputSchema: {
          type: "object",
          properties: {
            featureId: {
              type: "string",
              description: "ID of the feature"
            },
            question: {
              type: "string",
              description: "Clarification question"
            },
            answer: {
              type: "string",
              description: "Answer to the clarification question"
            }
          },
          required: ["featureId", "question", "answer"],
          examples: [
            {
              featureId: "feature-123",
              question: "What problem does this feature solve?",
              answer: "This feature solves the problem of users forgetting their passwords by providing a secure password reset flow."
            },
            {
              featureId: "feature-456",
              question: "Who are the target users?",
              answer: "The target users are administrators who need to manage user accounts and permissions."
            }
          ]
        }
      },
      {
        name: "generate_prd",
        description: "Generate a PRD document based on clarification responses",
        inputSchema: {
          type: "object",
          properties: {
            featureId: {
              type: "string",
              description: "ID of the feature"
            }
          },
          required: ["featureId"],
          examples: [
            {
              featureId: "feature-123"
            }
          ]
        },
        handler: async (params: {featureId: string}) => {
          const { featureId } = params;
          const feature = getFeature(featureId);
          
          if (!feature) {
            return {
              error: `Feature with ID ${featureId} not found`
            };
          }
          
          if (!isClarificationComplete(feature)) {
            return {
              error: 'Cannot generate PRD until clarification is complete',
              clarificationStatus: getClarificationStatus(feature)
            };
          }
          
          // Generate the PRD
          const prd = generatePRD(feature);
          
          // Update the feature with the PRD
          updateFeature(featureId, {
            ...feature,
            prd,
            updatedAt: new Date()
          });
          
          return {
            success: true,
            message: `PRD generated for feature ${feature.name}`,
            prd
          };
        }
      },
      {
        name: 'generate_implementation_plan',
        description: 'Generate an implementation plan for a feature based on clarifications and PRD',
        inputSchema: {
          type: 'object',
          properties: {
            featureId: {
              type: 'string',
              description: 'The ID of the feature to generate an implementation plan for'
            }
          },
          required: ['featureId']
        },
        handler: async (params: {featureId: string}) => {
          const { featureId } = params;
          const feature = getFeature(featureId);
          
          if (!feature) {
            return {
              error: `Feature with ID ${featureId} not found`
            };
          }
          
          if (!isClarificationComplete(feature)) {
            return {
              error: 'Cannot generate implementation plan until clarification is complete',
              clarificationStatus: getClarificationStatus(feature)
            };
          }
          
          // Generate the implementation plan
          const implementationPlan = generateImplementationPlan(feature);
          
          // Update the feature with the implementation plan
          updateFeature(featureId, {
            ...feature,
            implementationPlan,
            updatedAt: new Date()
          });
          
          return {
            success: true,
            message: `Implementation plan generated for feature ${feature.name}`,
            implementationPlan
          };
        }
      },
      {
        name: 'create_phase',
        description: 'Create a new development phase for a feature',
        inputSchema: {
          type: 'object',
          properties: {
            featureId: {
              type: 'string',
              description: 'ID of the feature to create a phase for'
            },
            name: {
              type: 'string',
              description: 'Name of the phase'
            },
            description: {
              type: 'string',
              description: 'Description of the phase'
            }
          },
          required: ['featureId', 'name', 'description'],
          examples: [
            {
              featureId: "feature-123",
              name: "Requirements Analysis",
              description: "Gather and analyze requirements for the feature"
            },
            {
              featureId: "feature-123",
              name: "Implementation",
              description: "Implement the core functionality of the feature"
            }
          ]
        },
        handler: async (params: {featureId: string, name: string, description: string}) => {
          const { featureId, name, description } = params;
          const feature = getFeature(featureId);
          
          if (!feature) {
            return {
              error: `Feature with ID ${featureId} not found`
            };
          }
          
          // Create the phase with validated inputs
          const phaseId = generateId();
          const phase = createPhase(feature.id, name, description);
          
          return {
            success: true,
            message: `Phase ${name} created for feature ${feature.name}`,
            phase
          };
        }
      },
      {
        name: 'update_phase_status',
        description: 'Update the status of a development phase',
        inputSchema: {
          type: 'object',
          properties: {
            featureId: {
              type: 'string',
              description: 'ID of the feature containing the phase'
            },
            phaseId: {
              type: 'string',
              description: 'ID of the phase to update'
            },
            status: {
              type: 'string',
              description: 'New status for the phase (pending, in_progress, completed, reviewed)'
            }
          },
          required: ['featureId', 'phaseId', 'status'],
          examples: [
            {
              featureId: "feature-123",
              phaseId: "phase-456",
              status: "in_progress"
            },
            {
              featureId: "feature-123",
              phaseId: "phase-456",
              status: "completed"
            }
          ]
        },
        handler: async (params: {featureId: string, phaseId: string, status: PhaseStatus}) => {
          const { featureId, phaseId, status } = params;
          const feature = getFeature(featureId);
          
          if (!feature) {
            return {
              error: `Feature with ID ${featureId} not found`
            };
          }
          
          const phase = feature.phases.find(p => p.id === phaseId);
          
          if (!phase) {
            return {
              error: `Phase with ID ${phaseId} not found in feature ${feature.name}`
            };
          }
          
          // Validate the status transition
          const validationResult = validatePhaseTransition(phase.status, status);
          
          if (!validationResult.valid) {
            return {
              error: validationResult.message
            };
          }
          
          // Update the phase status
          const updatedPhase = updatePhaseStatus(featureId, phaseId, status);
          
          return {
            success: true,
            message: `Phase ${phase.name} status updated to ${status}`,
            phase: updatedPhase
          };
        }
      },
      {
        name: 'add_task',
        description: 'Add a task to a development phase',
        inputSchema: {
          type: 'object',
          properties: {
            featureId: {
              type: 'string',
              description: 'ID of the feature containing the phase'
            },
            phaseId: {
              type: 'string',
              description: 'ID of the phase to add the task to'
            },
            description: {
              type: 'string',
              description: 'Description of the task'
            }
          },
          required: ['featureId', 'phaseId', 'description'],
          examples: [
            {
              featureId: "feature-123",
              phaseId: "phase-456",
              description: "Create database migration scripts"
            },
            {
              featureId: "feature-123",
              phaseId: "phase-456",
              description: "Implement user interface components"
            }
          ]
        },
        handler: async (params: {featureId: string, phaseId: string, description: string}) => {
          const { featureId, phaseId, description } = params;
          const feature = getFeature(featureId);
          
          if (!feature) {
            return {
              error: `Feature with ID ${featureId} not found`
            };
          }
          
          const phase = feature.phases.find(p => p.id === phaseId);
          
          if (!phase) {
            return {
              error: `Phase with ID ${phaseId} not found in feature ${feature.name}`
            };
          }
          
          // Add the task to the phase
          const updatedPhase = addTask(featureId, phaseId, description);
          
          return {
            success: true,
            message: `Task added to phase ${phase.name}`,
            phase: updatedPhase
          };
        }
      },
      {
        name: 'update_task_status',
        description: 'Update the completion status of a task',
        inputSchema: {
          type: 'object',
          properties: {
            featureId: {
              type: 'string',
              description: 'ID of the feature containing the phase'
            },
            phaseId: {
              type: 'string',
              description: 'ID of the phase containing the task'
            },
            taskId: {
              type: 'string',
              description: 'ID of the task to update'
            },
            completed: {
              type: 'boolean',
              description: 'Whether the task is completed'
            }
          },
          required: ['featureId', 'phaseId', 'taskId', 'completed'],
          examples: [
            {
              featureId: "feature-123",
              phaseId: "phase-456",
              taskId: "task-789",
              completed: true
            },
            {
              featureId: "feature-123",
              phaseId: "phase-456",
              taskId: "task-789",
              completed: false
            }
          ]
        },
        handler: async (params: {featureId: string, phaseId: string, taskId: string, completed: boolean}) => {
          const { featureId, phaseId, taskId, completed } = params;
          const feature = getFeature(featureId);
          
          if (!feature) {
            return {
              error: `Feature with ID ${featureId} not found`
            };
          }
          
          const phase = feature.phases.find(p => p.id === phaseId);
          
          if (!phase) {
            return {
              error: `Phase with ID ${phaseId} not found in feature ${feature.name}`
            };
          }
          
          const task = phase.tasks.find(t => t.id === taskId);
          
          if (!task) {
            return {
              error: `Task with ID ${taskId} not found in phase ${phase.name}`
            };
          }
          
          // Update the task status
          const updatedTask = updateTaskStatus(featureId, phaseId, taskId, completed);
          
          // Check if all tasks are completed and suggest phase update if applicable
          let message = `Task status updated to ${completed ? 'completed' : 'not completed'}`;
          
          // @ts-ignore - We know the task structure from our validation
          if (completed && phase.tasks.every(t => t.id === taskId || t.completed)) {
            // All tasks are now completed
            message += `. All tasks in phase ${phase.name} are now completed. Consider updating the phase status to 'completed'.`;
          }
          
          return {
            success: true,
            message,
            task: updatedTask
          };
        }
      },
      {
        name: 'get_next_phase_action',
        description: 'Get guidance on what to do next in the current phase or whether to move to the next phase',
        inputSchema: {
          type: 'object',
          properties: {
            featureId: {
              type: 'string',
              description: 'ID of the feature'
            }
          },
          required: ['featureId'],
          examples: [
            {
              featureId: "feature-123"
            }
          ]
        },
        handler: async (params: {featureId: string}) => {
          const { featureId } = params;
          const feature = getFeature(featureId);
          
          if (!feature) {
            return {
              error: `Feature with ID ${featureId} not found`
            };
          }
          
          // Find the current active phase (first non-completed/reviewed phase)
          // @ts-ignore - We know the phase structure from our Feature type
          const currentPhase = feature.phases.find(p => p.status === 'pending' || p.status === 'in_progress');
          
          if (!currentPhase) {
            // All phases are completed or reviewed
            return {
              content: [{
                type: "text",
                text: 'All phases are completed or reviewed. The feature implementation is done!'
              }]
            };
          }
          
          // Check task completion status
          // @ts-ignore - We know the task structure from our Phase type
          const completedTasks = currentPhase.tasks.filter(t => t.completed);
          // @ts-ignore - We know the task structure from our Phase type
          const pendingTasks = currentPhase.tasks.filter(t => !t.completed);
          
          // Determine next action based on phase and task status
          let message = '';
          
          if (currentPhase.status === 'pending') {
            message = `Phase "${currentPhase.name}" is pending. Start working on this phase by setting its status to "in_progress".`;
          } else if (currentPhase.status === 'in_progress') {
            if (pendingTasks.length > 0) {
              message = `${completedTasks.length}/${currentPhase.tasks.length} tasks are completed in phase "${currentPhase.name}". Continue working on pending tasks.`;
            } else if (currentPhase.tasks.length === 0) {
              message = `Phase "${currentPhase.name}" has no tasks defined. Add tasks or mark the phase as completed if appropriate.`;
            } else {
              // All tasks are completed
              message = `All tasks in phase "${currentPhase.name}" are completed. Consider marking this phase as completed.`;
            }
          }
          
          return {
            content: [{
              type: "text",
              text: message
            }]
          };
        }
      }
    ]
  };
});

/**
 * Handler for implementing MCP tools.
 * Handles feature clarification, PRD generation, and more.
 */
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  try {
    switch (request.params.name) {
      case "start_feature_clarification": {
        const featureName = String(request.params.arguments?.featureName || "");
        const initialDescription = String(request.params.arguments?.initialDescription || "");
        
        // Validate inputs
        const nameValidation = validateRequiredText(featureName, "Feature name", 2, 100);
        if (!nameValidation.valid) {
          return {
            content: [{
              type: "text",
              text: `Error: ${nameValidation.message}`
            }]
          };
        }
        
        // Initial description is optional, but if provided, validate its length
        if (initialDescription && initialDescription.trim() !== "") {
          const descValidation = validateRequiredText(initialDescription, "Initial description", 1, 5000);
          if (!descValidation.valid) {
            return {
              content: [{
                type: "text", 
                text: `Error: ${descValidation.message}`
              }]
            };
          }
        }
        
        // Create a new feature
        const feature = createFeatureObject(nameValidation.data, initialDescription);
        storeFeature(feature);
        
        // Get the first clarification question
        const firstQuestion = getNextClarificationQuestion(feature);
        
        return {
          content: [{
            type: "text",
            text: `Feature ID: ${feature.id}\n\nLet's clarify your feature request. ${firstQuestion}`
          }]
        };
      }
      
      case "provide_clarification": {
        const featureId = String(request.params.arguments?.featureId || "");
        const question = String(request.params.arguments?.question || "");
        const answer = String(request.params.arguments?.answer || "");
        
        console.log(`\n[CLARIFICATION] Received request for feature ${featureId}\n  Question: "${question.substring(0, 50)}..."\n  Answer: "${answer.substring(0, 50)}..."`);
        
        // Basic validation
        if (!featureId || !answer) {
          console.log(`[CLARIFICATION] Missing required fields: featureId=${!!featureId}, answer=${!!answer}`);
          return {
            content: [{
              type: "text",
              text: "Error: Feature ID and answer are required"
            }]
          };
        }
        
        // Get the feature
        const feature = getFeature(featureId);
        if (!feature) {
          console.log(`[CLARIFICATION] Feature ID ${featureId} not found`);
          return {
            content: [{
              type: "text",
              text: `Error: Feature with ID ${featureId} not found`
            }]
          };
        }
        
        console.log(`[CLARIFICATION] Found feature: ${feature.name} with ${feature.clarificationResponses.length} existing responses`);
        
        // Add the clarification response to the feature
        feature.clarificationResponses.push({
          question,
          answer,
          timestamp: new Date()
        });
        
        console.log(`[CLARIFICATION] Added response, now has ${feature.clarificationResponses.length} responses`);
        
        // Save the feature with the updated clarification response
        updateFeature(featureId, feature);
        
        // Determine which question to ask next
        const nextQuestionIndex = feature.clarificationResponses.length;
        
        console.log(`[CLARIFICATION] Next question index would be: ${nextQuestionIndex}`);
        console.log(`[CLARIFICATION] Total questions available: ${CLARIFICATION_QUESTIONS.length}`);
        
        if (nextQuestionIndex < CLARIFICATION_QUESTIONS.length) {
          // We have more questions to ask
          const nextQuestion = CLARIFICATION_QUESTIONS[nextQuestionIndex];
          console.log(`[CLARIFICATION] Returning next question: "${nextQuestion.substring(0, 50)}..."`);
          return {
            content: [{
              type: "text",
              text: `Response recorded. ${nextQuestion}`
            }]
          };
        } else {
          // All questions answered
          console.log(`[CLARIFICATION] All questions answered`);
          return {
            content: [{
              type: "text",
              text: "All clarification questions have been answered. You can now generate a PRD for this feature."
            }]
          };
        }
      }
      
      case "generate_prd": {
        const featureId = String(request.params.arguments?.featureId || "");
        
        // Validate feature ID
        const featureResult = validateFeatureId(featureId);
        if (!featureResult.valid) {
          return {
            content: [{
              type: "text",
              text: `Error: ${featureResult.message}`
            }]
          };
        }
        
        const feature = featureResult.data;
        
        // Check if clarifications are complete
        if (!isClarificationComplete(feature)) {
          return {
            content: [{
              type: "text",
              text: "Error: Please complete all clarification questions before generating a PRD."
            }]
          };
        }
        
        // Generate PRD and implementation plan
        const prdDoc = generatePRD(feature);
        const implementationPlan = generateImplementationPlan(feature);
        
        // Store the documents
        feature.prdDoc = prdDoc;
        feature.implementationPlan = implementationPlan;
        
        return {
          content: [{
            type: "text",
            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`
          }]
        };
      }
      
      case "create_phase": {
        const featureId = String(request.params.arguments?.featureId || "");
        const phaseName = String(request.params.arguments?.name || "");
        const phaseDescription = String(request.params.arguments?.description || "");
        const tasksJson = String(request.params.arguments?.tasks || "[]");
        
        // Validate feature ID
        const featureResult = validateFeatureId(featureId);
        if (!featureResult.valid) {
          return {
            content: [{
              type: "text",
              text: `Error: ${featureResult.message}`
            }]
          };
        }
        
        // Validate phase name
        const nameValidation = validateRequiredText(phaseName, "Phase name", 2, 100);
        if (!nameValidation.valid) {
          return {
            content: [{
              type: "text",
              text: `Error: ${nameValidation.message}`
            }]
          };
        }
        
        // Validate phase description (optional but if provided, validate)
        if (phaseDescription && phaseDescription.trim() !== "") {
          const descValidation = validateRequiredText(phaseDescription, "Phase description", 5, 1000);
          if (!descValidation.valid) {
            return {
              content: [{
                type: "text",
                text: `Error: ${descValidation.message}`
              }]
            };
          }
        }
        
        // Parse and validate tasks
        let tasks = [];
        try {
          tasks = JSON.parse(tasksJson);
          if (!Array.isArray(tasks)) {
            return {
              content: [{
                type: "text",
                text: "Error: Tasks must be a valid JSON array of task descriptions"
              }]
            };
          }
          
          // Validate each task description
          for (let i = 0; i < tasks.length; i++) {
            const taskDesc = tasks[i];
            if (typeof taskDesc !== 'string' || taskDesc.trim().length < 3) {
              return {
                content: [{
                  type: "text",
                  text: `Error: Task at index ${i} must be a string with at least 3 characters`
                }]
              };
            }
          }
        } catch (e) {
          return {
            content: [{
              type: "text",
              text: "Error: Could not parse tasks JSON. Please provide a valid JSON array."
            }]
          };
        }
        
        const feature = featureResult.data;
        
        // Create the phase
        const phase = createPhase(featureId, nameValidation.data, phaseDescription);
        
        if (!phase) {
          return {
            content: [{
              type: "text",
              text: `Error: Failed to create phase for feature ${feature.name}`
            }]
          };
        }
        
        // Add tasks if provided
        if (tasks.length > 0) {
          tasks.forEach(taskDesc => {
            addTask(featureId, phase.id, taskDesc);
          });
        }
        
        return {
          content: [{
            type: "text",
            text: `Phase "${phaseName}" created with ID: ${phase.id}`
          }]
        };
      }
      
      case "update_phase_status": {
        const featureId = String(request.params.arguments?.featureId || "");
        const phaseId = String(request.params.arguments?.phaseId || "");
        const status = String(request.params.arguments?.status || "");
        
        // Validate feature and phase
        const validationResult = validateFeaturePhaseTask(featureId, phaseId);
        if (!validationResult.valid) {
          return {
            content: [{
              type: "text",
              text: `Error: ${validationResult.message}`
            }]
          };
        }
        
        // Validate status
        const statusValidation = validatePhaseStatusValue(status);
        if (!statusValidation.valid) {
          return {
            content: [{
              type: "text",
              text: `Error: ${statusValidation.message}`
            }]
          };
        }
        
        const { feature, phase } = validationResult.data;
        
        // Update the phase status
        const updatedPhase = updatePhaseStatus(featureId, phaseId, statusValidation.data);
        
        return {
          content: [{
            type: "text",
            text: `Phase status updated to "${status}"`
          }]
        };
      }
      
      case "add_task": {
        const featureId = String(request.params.arguments?.featureId || "");
        const phaseId = String(request.params.arguments?.phaseId || "");
        const taskDescription = String(request.params.arguments?.description || "");
        
        // Validate feature and phase
        const validationResult = validateFeaturePhaseTask(featureId, phaseId);
        if (!validationResult.valid) {
          return {
            content: [{
              type: "text",
              text: `Error: ${validationResult.message}`
            }]
          };
        }
        
        // Validate task description
        const descValidation = validateRequiredText(taskDescription, "Task description", 3, 500);
        if (!descValidation.valid) {
          return {
            content: [{
              type: "text",
              text: `Error: ${descValidation.message}`
            }]
          };
        }
        
        const { feature, phase } = validationResult.data;
        
        // Add the task
        const taskId = addTask(featureId, phaseId, descValidation.data);
        
        return {
          content: [{
            type: "text",
            text: `Task added to phase "${phase.name}" with ID: ${taskId}`
          }]
        };
      }
      
      case "update_task_status": {
        const featureId = String(request.params.arguments?.featureId || "");
        const phaseId = String(request.params.arguments?.phaseId || "");
        const taskId = String(request.params.arguments?.taskId || "");
        const completed = Boolean(request.params.arguments?.completed);
        
        // Validate feature, phase and task
        const validationResult = validateFeaturePhaseTask(featureId, phaseId, taskId);
        if (!validationResult.valid) {
          return {
            content: [{
              type: "text",
              text: `Error: ${validationResult.message}`
            }]
          };
        }
        
        const { feature, phase, task } = validationResult.data;
        
        // Update the task status
        const updatedTask = updateTaskStatus(featureId, phaseId, taskId, completed);
        
        // Check if all tasks are completed and suggest phase update if applicable
        let message = `Task status updated to ${completed ? 'completed' : 'not completed'}`;
        
        // @ts-ignore - We know the task structure from our validation
        if (completed && phase.tasks.every(t => t.id === taskId || t.completed)) {
          // All tasks are now completed
          message += `. All tasks in phase ${phase.name} are now completed. Consider updating the phase status to 'completed'.`;
        }
        
        return {
          content: [{
            type: "text",
            text: message
          }]
        };
      }
      
      case "get_next_phase_action": {
        const featureId = String(request.params.arguments?.featureId || "");
        
        // Validate feature ID
        const featureResult = validateFeatureId(featureId);
        if (!featureResult.valid) {
          return {
            content: [{
              type: "text",
              text: `Error: ${featureResult.message}`
            }]
          };
        }
        
        const feature = featureResult.data;
        
        // Find the current active phase (first non-completed/reviewed phase)
        // @ts-ignore - We know the phase structure from our Feature type
        const currentPhase = feature.phases.find(p => p.status === 'pending' || p.status === 'in_progress');
        
        if (!currentPhase) {
          // All phases are completed or reviewed
          return {
            content: [{
              type: "text",
              text: 'All phases are completed or reviewed. The feature implementation is done!'
            }]
          };
        }
        
        // Check task completion status
        // @ts-ignore - We know the task structure from our Phase type
        const completedTasks = currentPhase.tasks.filter(t => t.completed);
        // @ts-ignore - We know the task structure from our Phase type
        const pendingTasks = currentPhase.tasks.filter(t => !t.completed);
        
        // Determine next action based on phase and task status
        let message = '';
        
        if (currentPhase.status === 'pending') {
          message = `Phase "${currentPhase.name}" is pending. Start working on this phase by setting its status to "in_progress".`;
        } else if (currentPhase.status === 'in_progress') {
          if (pendingTasks.length > 0) {
            message = `${completedTasks.length}/${currentPhase.tasks.length} tasks are completed in phase "${currentPhase.name}". Continue working on pending tasks.`;
          } else if (currentPhase.tasks.length === 0) {
            message = `Phase "${currentPhase.name}" has no tasks defined. Add tasks or mark the phase as completed if appropriate.`;
          } else {
            // All tasks are completed
            message = `All tasks in phase "${currentPhase.name}" are completed. Consider marking this phase as completed.`;
          }
        }
        
        return {
          content: [{
            type: "text",
            text: message
          }]
        };
      }
      
      default:
        return {
          content: [{
            type: "text",
            text: `Error: Unknown tool "${request.params.name}"`
          }]
        };
    }
  } catch (error: any) {
    console.error('Error executing tool:', error);
    return {
      content: [{
        type: "text",
        text: `An unexpected error occurred: ${error.message || 'Unknown error'}`
      }]
    };
  }
});

/**
 * Handler that lists available prompts.
 */
server.setRequestHandler(ListPromptsRequestSchema, async () => {
  return {
    prompts: [
      {
        name: "clarify_feature",
        description: "Guide to clarify a feature request through questioning"
      }
    ]
  };
});

/**
 * Handler for the clarify_feature prompt.
 * Returns a prompt that guides feature clarification.
 */
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
  if (request.params.name === "clarify_feature") {
    return {
      messages: [
        {
          role: "user",
          content: {
            type: "text",
            text: "Help me clarify this feature request by asking questions about:"
          }
        },
        {
          role: "user",
          content: {
            type: "text",
            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."
          }
        }
      ]
    };
  }
  
  throw new Error("Unknown prompt");
});

/**
 * Start the server using stdio transport.
 * This allows the server to communicate via standard input/output streams.
 */
async function main() {
  console.error("Starting Vibe-Coder MCP Server...");
  
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main().catch((error) => {
  console.error("Server error:", error);
  process.exit(1);
});

```
Page 2/4FirstPrevNextLast