get_project_timeline
Retrieve project timelines with milestones and key events using project ID, with options to filter 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 execution logic for the get_project_timeline tool. Fetches project data, constructs timeline events from tasks and documents, filters and sorts events, 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 input validation schema for the get_project_timeline tool parameters.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 object definition for get_project_timeline, including name, description, and input schema for MCP server registration.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-788 (registration)Handler mapping object that registers get_project_timeline to its handler function, imported and used in src/index.ts for 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, 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 }) }