Skip to main content
Glama

parse_prd

Transform Product Requirements Documents (PRDs) into structured tasks with dependencies, priorities, and complexity estimates. Automatically generate actionable task breakdowns for efficient project management.

Instructions

Parse a Product Requirements Document (PRD) and automatically generate structured tasks with dependencies, priorities, and complexity estimates. Transform high-level requirements into actionable task breakdowns with intelligent analysis.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
defaultPriorityNoDefault priority for generated tasks (1-10)
estimateComplexityNoWhether to estimate complexity for tasks
generateSubtasksNoWhether to generate subtasks for complex tasks
prdContentYesContent of the Product Requirements Document to parse
projectIdYesID of the project to add tasks to
workingDirectoryYesThe full absolute path to the working directory where data is stored. MUST be an absolute path, never relative. Windows: "C:\Users\username\project" or "D:\projects\my-app". Unix/Linux/macOS: "/home/username/project" or "/Users/username/project". Do NOT use: ".", "..", "~", "./folder", "../folder" or any relative paths. Ensure the path exists and is accessible before calling this tool. NOTE: When server is started with --claude flag, this parameter is ignored and a global user directory is used instead.

Implementation Reference

  • src/server.ts:903-936 (registration)
    Registration of the 'parse_prd' tool in the MCP server using server.tool(), which creates a ParsePRDTool instance via createParsePRDTool and wraps its handler.
    server.tool( 'parse_prd', 'Parse a Product Requirements Document (PRD) and automatically generate structured tasks with dependencies, priorities, and complexity estimates. Transform high-level requirements into actionable task breakdowns with intelligent analysis.', { workingDirectory: z.string().describe(getWorkingDirectoryDescription(config)), projectId: z.string().describe('ID of the project to add tasks to'), prdContent: z.string().describe('Content of the Product Requirements Document to parse'), generateSubtasks: z.boolean().optional().default(true).describe('Whether to generate subtasks for complex tasks'), defaultPriority: z.number().min(1).max(10).optional().default(5).describe('Default priority for generated tasks (1-10)'), estimateComplexity: z.boolean().optional().default(true).describe('Whether to estimate complexity for tasks') }, async ({ workingDirectory, projectId, prdContent, generateSubtasks, defaultPriority, estimateComplexity }: { workingDirectory: string; projectId: string; prdContent: string; generateSubtasks?: boolean; defaultPriority?: number; estimateComplexity?: boolean; }) => { try { const storage = await createStorage(workingDirectory, config); const tool = createParsePRDTool(storage, getWorkingDirectoryDescription, config); return await tool.handler({ workingDirectory, projectId, prdContent, generateSubtasks, defaultPriority, estimateComplexity }); } catch (error) { return { content: [{ type: 'text' as const, text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } );
  • The main execution logic of the parse_prd tool: validates project, parses PRD content into tasks using helper, creates tasks in storage, handles dependencies, builds hierarchical response with generated tasks summary and next action suggestions.
    handler: async (args: any) => { try { const { workingDirectory, projectId, prdContent, generateSubtasks, defaultPriority, estimateComplexity } = args; // Validate project exists const project = await storage.getProject(projectId); if (!project) { return { content: [{ type: 'text' as const, text: `Error: Project with ID "${projectId}" not found.` }], isError: true }; } // Parse PRD content and extract tasks const parsedTasks = await parsePRDContent(prdContent, projectId, defaultPriority, estimateComplexity); // Create tasks in storage const createdTasks: Task[] = []; const taskDependencyMap = new Map<string, string[]>(); for (const taskData of parsedTasks) { const now = new Date().toISOString(); const task: Task = { id: randomUUID(), name: taskData.name, details: taskData.details, projectId, parentId: taskData.parentId, completed: false, createdAt: now, updatedAt: now, dependsOn: taskData.dependsOn || [], priority: taskData.priority || defaultPriority, complexity: taskData.complexity, status: 'pending', tags: taskData.tags || [], estimatedHours: taskData.estimatedHours }; const createdTask = await storage.createTask(task); createdTasks.push(createdTask); if (taskData.dependsOn && taskData.dependsOn.length > 0) { taskDependencyMap.set(createdTask.id, taskData.dependsOn); } } // Update dependencies with actual task IDs await updateTaskDependencies(storage, createdTasks, taskDependencyMap); // Build response text safely let responseText = `✅ PRD parsed successfully! Generated ${createdTasks.length} tasks for project "${project.name}". 📋 **Generated Tasks:**\n`; for (const task of createdTasks) { const levelIndicator = ' '.repeat(task.level || 0) + '→'; responseText += `${levelIndicator} **${task.name}** (Priority: ${task.priority}, Complexity: ${task.complexity || 'N/A'}) ${task.details.substring(0, 100)}${task.details.length > 100 ? '...' : ''} Dependencies: ${task.dependsOn?.length ? task.dependsOn.join(', ') : 'None'} Tags: ${task.tags?.join(', ') || 'None'}\n\n`; } responseText += `👉 **Your Actions: Review Tasks and Determine Next Steps** 1. **Review and Refine Generated Tasks:** Carefully examine each task generated from the PRD. If you need to adjust names, details, priorities, complexity, or dependencies, use the \`update_task\` tool. * Example: \`update_task({ id: "task_id_to_update", name: "new_task_name", details: "updated_details", priority: 7 })\` 2. **Create Nested Tasks:** For complex tasks, you can break them down further using \`create_task\` with parentId. * Example: \`create_task({ projectId: "${project.id}", parentId: "parent_task_id", name: "subtask_name", details: "subtask_details" })\` 3. **Identify Starting Task:** Once you are satisfied with the task definitions, use the \`get_next_task_recommendation\` tool to identify the best task to begin with in this project. * Example: \`get_next_task_recommendation({ projectId: "${project.id}" })\` 4. **Begin Implementation:** After getting a recommendation, you can start working on the suggested task. Remember to update its status using \`update_task\` (e.g., set to 'in-progress').`; return { content: [{ type: 'text' as const, text: responseText }] }; } catch (error: any) { return { content: [{ type: 'text' as const, text: `Error parsing PRD: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } }
  • Zod schema defining the input parameters for the parse_prd tool, matching the one used in server registration.
    inputSchema: z.object({ workingDirectory: z.string().describe(getWorkingDirectoryDescription(config)), projectId: z.string().describe('ID of the project to add tasks to'), prdContent: z.string().describe('Content of the Product Requirements Document to parse'), generateSubtasks: z.boolean().optional().default(true).describe('Whether to generate subtasks for complex tasks'), defaultPriority: z.number().min(1).max(10).optional().default(5).describe('Default priority for generated tasks (1-10)'), estimateComplexity: z.boolean().optional().default(true).describe('Whether to estimate complexity for tasks') }),
  • Helper function that implements the PRD parsing logic: splits content into sections, matches task patterns (bullets, numbered, action verbs), estimates complexity/tags/hours based on keywords, provides fallback task.
    async function parsePRDContent(prdContent: string, projectId: string, defaultPriority: number, estimateComplexity: boolean): Promise<CreateTaskInput[]> { const tasks: CreateTaskInput[] = []; // Simple parsing logic - look for common patterns in PRDs const sections = prdContent.split(/\n\s*\n/); for (const section of sections) { const lines = section.trim().split('\n'); if (lines.length === 0) continue; // Look for task-like patterns const taskPatterns = [ /^[-*]\s+(.+)/, // Bullet points /^\d+\.\s+(.+)/, // Numbered lists /^(implement|create|build|develop|design|add|setup|configure)\s+(.+)/i, // Action verbs /^(feature|requirement|task):\s*(.+)/i // Explicit task markers ]; for (const line of lines) { for (const pattern of taskPatterns) { const match = line.match(pattern); if (match) { const taskName = match[1] || match[2]; if (taskName && taskName.length > 5) { // Filter out very short matches // Estimate complexity based on keywords let complexity = undefined; if (estimateComplexity) { complexity = estimateTaskComplexity(taskName, section); } // Extract tags from content const tags = extractTags(taskName, section); // Estimate hours based on complexity and content const estimatedHours = estimateHours(complexity, taskName, section); const taskDetails = section.substring(0, 500) + (section.length > 500 ? '...' : ''); tasks.push({ name: taskName.trim(), details: taskDetails, projectId, priority: defaultPriority, complexity, tags, estimatedHours }); } } } } } // If no tasks found, create a general implementation task if (tasks.length === 0) { tasks.push({ name: 'Implement PRD Requirements', details: prdContent.substring(0, 1000), projectId, priority: defaultPriority, complexity: estimateComplexity ? 7 : undefined, tags: ['implementation', 'prd'], estimatedHours: 40 }); } return tasks; }
  • Helper function to score task complexity (1-10) based on keyword analysis in high/medium/low complexity categories.
    function estimateTaskComplexity(taskName: string, context: string): number { const complexityKeywords = { high: ['architecture', 'system', 'integration', 'security', 'performance', 'scalability', 'database', 'api', 'framework'], medium: ['component', 'feature', 'interface', 'validation', 'testing', 'configuration'], low: ['button', 'text', 'style', 'color', 'layout', 'simple', 'basic'] }; const content = (taskName + ' ' + context).toLowerCase(); let score = 5; // Default medium complexity for (const keyword of complexityKeywords.high) { if (content.includes(keyword)) score += 2; } for (const keyword of complexityKeywords.medium) { if (content.includes(keyword)) score += 1; } for (const keyword of complexityKeywords.low) { if (content.includes(keyword)) score -= 1; } return Math.max(1, Math.min(10, score)); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Pimzino/agentic-tools-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server