Skip to main content
Glama
jakedx6
by jakedx6
prompt-to-project.ts13.9 kB
import { z } from 'zod'; import { apiClient } from '../lib/api-client.js'; import { logger } from '../lib/logger.js'; import { authManager } from '../lib/auth.js'; import { initiativeHandlers } from './initiatives.js'; import { projectHandlers } from './projects.js'; import { taskHandlers } from './tasks.js'; import { documentHandlers } from './documents.js'; const ExecutionMode = z.enum(['analyze', 'create']); const TaskPlanSchema = z.object({ title: z.string(), description: z.string().optional(), priority: z.enum(['low', 'medium', 'high']).default('medium'), status: z.enum(['todo', 'in_progress', 'done']).default('todo'), assignee_id: z.string().optional(), due_date: z.string().optional() }); const InitiativePlanSchema = z.object({ name: z.string(), objective: z.string(), description: z.string().optional(), priority: z.enum(['critical', 'high', 'medium', 'low']).default('medium'), status: z.enum(['planning', 'active', 'on_hold', 'completed', 'cancelled']).default('planning'), start_date: z.string().optional(), target_date: z.string().optional(), tasks: z.array(TaskPlanSchema).default([]) }); const ProjectPlanSchema = z.object({ project: z.object({ name: z.string(), description: z.string().optional(), status: z.enum(['active', 'completed', 'archived']).default('active') }), initiatives: z.array(InitiativePlanSchema).default([]), documents: z.array(z.object({ title: z.string(), content: z.string(), document_type: z.enum(['requirement', 'design', 'technical', 'meeting_notes', 'other']) })).optional() }); const PromptToProjectArgsSchema = z.object({ prompt: z.string().describe('Natural language description of the project to create'), execution_mode: ExecutionMode.describe('analyze: return structured requirements for agent to process, create: execute agent-provided plan'), project_plan: ProjectPlanSchema.optional().describe('Required when execution_mode is "create" - the structured plan to execute') }); function extractKeyRequirements(prompt: string) { const requirements = { mentions_timeline: /deadline|timeline|due|by|until|before|sprint|milestone/i.test(prompt), mentions_team: /team|developer|designer|engineer|member|person|people/i.test(prompt), mentions_technology: /react|node|python|java|database|api|frontend|backend|fullstack/i.test(prompt), mentions_features: /feature|functionality|capability|requirement|user story/i.test(prompt), mentions_priority: /urgent|critical|high priority|important|asap|immediately/i.test(prompt), is_technical: /api|database|frontend|backend|integration|deployment|testing/i.test(prompt), is_business: /customer|user|market|revenue|sales|marketing|business/i.test(prompt) }; return requirements; } function generateProjectTemplate(prompt: string) { const requirements = extractKeyRequirements(prompt); const template = { project: { name: "[Project name based on the prompt]", description: "[Comprehensive project description expanding on: " + prompt + "]", status: "active" as const }, initiatives: [ { name: "[Core Feature/Initiative 1]", objective: "[What this initiative aims to achieve]", description: "[Detailed description]", priority: requirements.mentions_priority ? "high" as const : "medium" as const, status: "planning" as const, tasks: [ { title: "[Specific task 1]", description: "[Task details]", priority: "medium" as const, status: "todo" as const } ] } ], documents: requirements.is_technical ? [ { title: "Technical Specification", content: "[Technical documentation for the project]", document_type: "technical" as const }, { title: "Project Requirements", content: "[Detailed requirements document]", document_type: "requirement" as const } ] : [] }; return template; } function generateAnalysisGuidance(prompt: string) { const requirements = extractKeyRequirements(prompt); const guidance = { instructions: "Please analyze the project request and create a comprehensive project plan. Fill out the template below with specific details based on the requirements.", key_considerations: [ "Break down the project into 2-4 strategic initiatives", "Each initiative should have 3-7 specific, actionable tasks", "Consider dependencies between tasks", "Set realistic priorities based on project goals", requirements.mentions_timeline && "Include timeline considerations in task planning", requirements.mentions_team && "Consider team allocation and skills needed", requirements.mentions_technology && "Include technical implementation tasks", requirements.is_business && "Include business/user-facing deliverables" ].filter(Boolean), suggested_initiatives: requirements.is_technical ? [ "Core Infrastructure Setup", "Feature Development", "Testing & Quality Assurance", "Documentation & Deployment" ] : [ "Planning & Requirements", "Implementation", "Review & Iteration" ], questions_to_consider: [ "What are the main objectives of this project?", "What are the critical success factors?", "What could be the potential risks or blockers?", requirements.mentions_timeline && "What are the key milestones and deadlines?", requirements.mentions_team && "What skills and resources are needed?", "How should the work be prioritized?" ].filter(Boolean) }; return guidance; } export const promptToProjectTools = [ { name: 'prompt_to_project', description: 'Convert a natural language project description into structured project entities. In analyze mode, returns a template for the AI agent to fill. In create mode, executes the agent-provided plan.', inputSchema: { type: 'object' as const, properties: PromptToProjectArgsSchema.shape, required: ['prompt', 'execution_mode'] as const, additionalProperties: false }, handler: async (args: unknown) => { try { const validatedArgs = PromptToProjectArgsSchema.parse(args); if (validatedArgs.execution_mode === 'analyze') { logger.info('Analyzing project prompt for agent processing', { prompt: validatedArgs.prompt }); const template = generateProjectTemplate(validatedArgs.prompt); const guidance = generateAnalysisGuidance(validatedArgs.prompt); const requirements = extractKeyRequirements(validatedArgs.prompt); return { content: [ { type: 'text' as const, text: JSON.stringify({ mode: 'analyze', guidance, template, requirements, original_prompt: validatedArgs.prompt, next_step: "Fill out the template with specific details and call this tool again with execution_mode='create' and the filled project_plan" }, null, 2) } ] }; } else if (validatedArgs.execution_mode === 'create') { if (!validatedArgs.project_plan) { throw new Error('project_plan is required when execution_mode is "create"'); } logger.info('Creating project from agent-provided plan', { projectName: validatedArgs.project_plan.project.name }); // Get the authenticated user context // For MCP keys, we need a valid UUID. Use a placeholder UUID let userId = '00000000-0000-0000-0000-000000000000'; // Null UUID as placeholder try { const authContext = authManager.getAuthContext(); if (authContext.userId && authContext.userId !== 'mcp-pending') { userId = authContext.userId; } else { logger.info('Using placeholder UUID for MCP context owner_id'); } } catch (e) { // If not authenticated yet, use placeholder logger.info('Using placeholder UUID for MCP context owner_id'); } // Use the MCP handlers directly to ensure proper authentication and association // Create the project using the MCP handler const projectResult = await projectHandlers.create_project({ name: validatedArgs.project_plan.project.name, description: validatedArgs.project_plan.project.description, status: validatedArgs.project_plan.project.status }); const createdProject = projectResult.project; const createdInitiatives = []; const createdTasks = []; const createdDocuments = []; // Create initiatives and their tasks for (const initiative of validatedArgs.project_plan.initiatives) { try { // Use the MCP handler which properly handles project association const initiativeResult = await initiativeHandlers.create_initiative({ name: initiative.name, objective: initiative.objective, description: initiative.description, priority: initiative.priority, status: initiative.status, owner_id: userId, // Required field project_ids: [createdProject.id], // Associate with the created project start_date: initiative.start_date, target_date: initiative.target_date, metadata: {}, tags: [] }); const createdInitiative = initiativeResult.initiative; createdInitiatives.push(createdInitiative); // Create tasks for this initiative for (const task of initiative.tasks) { try { const taskResult = await taskHandlers.create_task({ project_id: createdProject.id, initiative_id: createdInitiative.id, title: task.title, description: task.description, priority: task.priority, status: task.status, assignee_id: task.assignee_id, due_date: task.due_date }); createdTasks.push(taskResult.task); } catch (taskError) { logger.error('Failed to create task', { task: task.title, error: taskError }); } } } catch (initiativeError) { logger.error('Failed to create initiative', { initiative: initiative.name, error: initiativeError }); } } // Create documents if provided if (validatedArgs.project_plan.documents) { for (const doc of validatedArgs.project_plan.documents) { try { const docResult = await documentHandlers.create_document({ project_id: createdProject.id, title: doc.title, content: doc.content, document_type: doc.document_type }); createdDocuments.push(docResult.document); } catch (docError) { logger.error('Failed to create document', { document: doc.title, error: docError }); } } } return { content: [ { type: 'text' as const, text: JSON.stringify({ mode: 'create', success: true, created: { project: { id: createdProject.id, name: createdProject.name, description: createdProject.description }, initiatives: createdInitiatives.map(i => ({ id: i.id, name: i.name, objective: i.objective })), tasks: createdTasks.map(t => ({ id: t.id, title: t.title, initiative_id: t.initiative_id })), documents: createdDocuments.map(d => ({ id: d.id, title: d.title, type: d.document_type })) }, summary: `Successfully created project "${createdProject.name}" with ${createdInitiatives.length} initiatives, ${createdTasks.length} tasks, and ${createdDocuments.length} documents.` }, null, 2) } ] }; } else { throw new Error(`Invalid execution_mode: ${validatedArgs.execution_mode}`); } } catch (error) { logger.error('Error in prompt_to_project tool', { error }); const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return { content: [ { type: 'text' as const, text: JSON.stringify({ error: errorMessage, details: error instanceof z.ZodError ? error.errors : undefined }, null, 2) } ], isError: true }; } } } ];

Implementation Reference

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/jakedx6/helios9-MCP-Server'

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