get_project_timeline
Retrieve project timeline with milestones and key events for a specific project ID, filtering by time range and completion status.
Instructions
Get project timeline with milestones and key events
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | Yes | ID of the project | |
| include_completed | No | Whether to include completed items | |
| time_range | No | Time range filter | all |
Implementation Reference
- src/tools/projects.ts:511-608 (handler)Main handler function for get_project_timeline tool. Parses input, fetches project, tasks, and documents, constructs timeline events, applies time filtering, identifies milestones, and returns structured timeline data.export const getProjectTimeline = requireAuth(async (args: any) => { const { project_id, include_completed, time_range } = GetProjectTimelineSchema.parse(args) logger.info('Getting project timeline', { project_id, time_range }) const project = await supabaseService.getProject(project_id) if (!project) { throw new Error('Project not found') } // Get tasks and documents with dates const tasks = await supabaseService.getTasks({ project_id }) const documents = await supabaseService.getDocuments({ project_id }) // Create timeline events const timelineEvents = [] // Add project creation timelineEvents.push({ date: project.created_at, type: 'project_created', title: 'Project Created', description: `Project "${project.name}" was created`, metadata: { project_id } }) // Add task events tasks.forEach(task => { if (task.created_at) { timelineEvents.push({ date: task.created_at, type: 'task_created', title: `Task Created: ${task.title}`, description: task.description, metadata: { task_id: task.id, status: task.status } }) } // started_at property doesn't exist in the database schema // completed_at property doesn't exist in the database schema if (task.due_date) { timelineEvents.push({ date: task.due_date, type: 'task_due', title: `Task Due: ${task.title}`, description: task.status === 'done' ? 'Completed on time' : 'Due date', metadata: { task_id: task.id, is_overdue: new Date(task.due_date) < new Date() && task.status !== 'done' } }) } }) // Add document events documents.forEach(doc => { timelineEvents.push({ date: doc.created_at, type: 'document_created', title: `Document Created: ${doc.title}`, metadata: { document_id: doc.id, document_type: doc.document_type } }) if (doc.updated_at !== doc.created_at) { timelineEvents.push({ date: doc.updated_at, type: 'document_updated', title: `Document Updated: ${doc.title}`, metadata: { document_id: doc.id } }) } }) // Filter by time range const filteredEvents = filterTimelineByRange(timelineEvents, time_range) // Sort by date filteredEvents.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()) // Identify milestones (significant events) const milestones = identifyMilestones(filteredEvents, tasks) return { project: { id: project.id, name: project.name, status: project.status }, timeline: filteredEvents, milestones, summary: { total_events: filteredEvents.length, tasks_created: filteredEvents.filter(e => e.type === 'task_created').length, tasks_completed: filteredEvents.filter(e => e.type === 'task_completed').length, documents_created: filteredEvents.filter(e => e.type === 'document_created').length, overdue_tasks: filteredEvents.filter(e => e.type === 'task_due' && e.metadata?.is_overdue).length } } })
- src/tools/projects.ts:505-509 (schema)Zod schema for validating input parameters: project_id (required), include_completed (boolean, default true), time_range (enum, default 'all').const GetProjectTimelineSchema = z.object({ project_id: z.string().min(1), include_completed: z.boolean().default(true), time_range: z.enum(['all', 'past_month', 'next_month', 'current_quarter']).default('all') })
- src/tools/projects.ts:479-503 (registration)MCPTool registration object defining the tool name, description, and input schema for MCP protocol.export const getProjectTimelineTool: MCPTool = { name: 'get_project_timeline', description: 'Get project timeline with milestones and key events', inputSchema: { type: 'object', properties: { project_id: { type: 'string', description: 'ID of the project' }, include_completed: { type: 'boolean', default: true, description: 'Whether to include completed items' }, time_range: { type: 'string', enum: ['all', 'past_month', 'next_month', 'current_quarter'], default: 'all', description: 'Time range filter' } }, required: ['project_id'] } }
- src/tools/projects.ts:778-787 (registration)Object exporting all project handlers, including get_project_timeline mapped to its handler function for registration in the MCP server.export const projectHandlers = { list_projects: listProjects, get_project: getProject, create_project: createProject, update_project: updateProject, get_project_context: getProjectContext, archive_project: archiveProject, duplicate_project: duplicateProject, get_project_timeline: getProjectTimeline, bulk_update_projects: bulkUpdateProjects
- src/tools/projects.ts:698-726 (helper)Helper function to filter timeline events by specified time range (all, past_month, next_month, current_quarter). Used in the handler.function filterTimelineByRange(events: any[], timeRange: string): any[] { if (timeRange === 'all') return events const now = new Date() let startDate: Date let endDate: Date = now switch (timeRange) { case 'past_month': startDate = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate()) break case 'next_month': startDate = now endDate = new Date(now.getFullYear(), now.getMonth() + 1, now.getDate()) break case 'current_quarter': const quarter = Math.floor(now.getMonth() / 3) startDate = new Date(now.getFullYear(), quarter * 3, 1) endDate = new Date(now.getFullYear(), quarter * 3 + 3, 0) break default: return events } return events.filter(event => { const eventDate = new Date(event.date) return eventDate >= startDate && eventDate <= endDate }) }