timeline_list_scheduled_events
Retrieve scheduled social media events with filters for platform, status, date range, and campaign track to monitor content automation workflows.
Instructions
List scheduled events with optional filtering by track, status, platform, and date range.
STATUS FILTERING:
'all': Returns all events regardless of status
'pending': Returns events that haven't been generated yet (contentGenerated = false)
'generated': Returns events that have been generated but not posted yet (contentGenerated = true, posted = false)
'posted': Returns events that have been posted (posted = true)
DATE FILTERING:
startDate/endDate use DATE ONLY comparison (time is ignored)
Format: YYYY-MM-DD or ISO 8601 datetime string
Example: startDate="2025-10-14" matches ALL events scheduled on Oct 14, regardless of time
To get events for a single day, use the same date for both startDate and endDate
EXAMPLES:
Get all posted events from today: { "startDate": "2025-10-14", "endDate": "2025-10-14", "status": "posted" }
Get all Reddit events this week: { "platform": "reddit", "startDate": "2025-10-14", "endDate": "2025-10-20" }
Get pending events in a specific track: { "trackId": "track-uuid", "status": "pending" }
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| endDate | No | End date for filtering (YYYY-MM-DD). Date-only comparison - time is ignored. | |
| limit | No | Maximum number of events to return | |
| offset | No | Offset for pagination | |
| platform | No | Filter by platform (x, reddit, linkedin, instagram, tiktok, youtube) | |
| startDate | No | Start date for filtering (YYYY-MM-DD). Date-only comparison - time is ignored. | |
| status | No | Filter by event status | all |
| trackId | No | Filter by track ID |
Implementation Reference
- timeline-fastmcp.ts:477-569 (handler)The execute function that queries the database for scheduled events, joins with tracks, applies status, platform, and date range filters (date-only comparison), parses events, and returns a paginated list of events.execute: async (params) => { const db = await getDb(); let whereConditions = [eq(events.eventType, 'scheduled')]; if (params.trackId) { whereConditions.push(eq(events.trackId, params.trackId)); } if (params.platform) { whereConditions.push(eq(events.platform, params.platform)); } const results = await db.select({ event: events, track: tracks }) .from(events) .innerJoin(tracks, eq(events.trackId, tracks.id)) .where(and(...whereConditions)) .orderBy(asc(events.scheduledTime)) .limit(params.limit) .offset(params.offset); // Apply additional filters const filtered = results.filter(({ event }) => { // Status filter if (params.status !== 'all') { if (params.status === 'posted' && !event.posted) return false; if (params.status === 'generated' && (!event.contentGenerated || event.posted)) return false; if (params.status === 'pending' && event.contentGenerated) return false; } // Date filters - compare dates only, not times if (params.startDate) { const eventDate = new Date(event.scheduledTime); eventDate.setHours(0, 0, 0, 0); // Parse the filter date in local timezone by extracting YYYY-MM-DD const dateMatch = params.startDate.match(/^(\d{4})-(\d{2})-(\d{2})/); if (!dateMatch) return false; const startDate = new Date(parseInt(dateMatch[1]), parseInt(dateMatch[2]) - 1, parseInt(dateMatch[3]), 0, 0, 0, 0); if (eventDate < startDate) return false; } if (params.endDate) { const eventDate = new Date(event.scheduledTime); eventDate.setHours(0, 0, 0, 0); // Parse the filter date in local timezone by extracting YYYY-MM-DD const dateMatch = params.endDate.match(/^(\d{4})-(\d{2})-(\d{2})/); if (!dateMatch) return false; const endDate = new Date(parseInt(dateMatch[1]), parseInt(dateMatch[2]) - 1, parseInt(dateMatch[3]), 0, 0, 0, 0); if (eventDate > endDate) return false; } return true; }); const response = { events: filtered.map(({ event, track }) => { const parsedEvent = parseEventFromDb(event); return eventResponseSchema.parse({ id: parsedEvent.id, trackId: parsedEvent.trackId, trackName: track.name, name: parsedEvent.name, prompt: parsedEvent.prompt, // Now using prompt field platform: parsedEvent.platform, scheduledTime: parsedEvent.scheduledTime?.toISOString(), generationTime: parsedEvent.generationTime?.toISOString(), status: parsedEvent.posted ? 'posted' : (parsedEvent.contentGenerated ? 'generated' : 'pending'), mediaPath: parsedEvent.mediaPath, metadata: parsedEvent.metadata ? JSON.parse(parsedEvent.metadata) : undefined, generationSessionId: parsedEvent.generationSessionId, postingSessionId: parsedEvent.postingSessionId, generationStartedAt: parsedEvent.generationStartedAt?.toISOString(), approvalRequestedAt: parsedEvent.approvalRequestedAt?.toISOString(), error: parsedEvent.error, postedUrl: parsedEvent.postedUrl }); }), pagination: { limit: params.limit, offset: params.offset, total: filtered.length } }; return JSON.stringify(response, null, 2); }
- timeline-fastmcp.ts:468-476 (schema)Zod schema defining the input parameters for the tool, including optional filters for trackId, status, platform, date range (startDate/endDate), and pagination (limit/offset).parameters: z.object({ trackId: z.string().uuid().optional().describe('Filter by track ID'), status: z.enum(['all', 'pending', 'generated', 'posted']).optional().default('all').describe('Filter by event status'), platform: platformSchema.optional().describe('Filter by platform (x, reddit, linkedin, instagram, tiktok, youtube)'), startDate: isoDateTimeSchema.optional().describe('Start date for filtering (YYYY-MM-DD). Date-only comparison - time is ignored.'), endDate: isoDateTimeSchema.optional().describe('End date for filtering (YYYY-MM-DD). Date-only comparison - time is ignored.'), limit: z.number().int().positive().max(100).optional().default(50).describe('Maximum number of events to return'), offset: z.number().int().nonnegative().optional().default(0).describe('Offset for pagination') }),
- timeline-fastmcp.ts:448-570 (registration)Registration of the 'timeline_list_scheduled_events' tool using FastMCP's addTool method, including name, detailed description with examples, input schema, and execute handler.mcp.addTool({ name: 'timeline_list_scheduled_events', description: `List scheduled events with optional filtering by track, status, platform, and date range. STATUS FILTERING: - 'all': Returns all events regardless of status - 'pending': Returns events that haven't been generated yet (contentGenerated = false) - 'generated': Returns events that have been generated but not posted yet (contentGenerated = true, posted = false) - 'posted': Returns events that have been posted (posted = true) DATE FILTERING: - startDate/endDate use DATE ONLY comparison (time is ignored) - Format: YYYY-MM-DD or ISO 8601 datetime string - Example: startDate="2025-10-14" matches ALL events scheduled on Oct 14, regardless of time - To get events for a single day, use the same date for both startDate and endDate EXAMPLES: - Get all posted events from today: { "startDate": "2025-10-14", "endDate": "2025-10-14", "status": "posted" } - Get all Reddit events this week: { "platform": "reddit", "startDate": "2025-10-14", "endDate": "2025-10-20" } - Get pending events in a specific track: { "trackId": "track-uuid", "status": "pending" }`, parameters: z.object({ trackId: z.string().uuid().optional().describe('Filter by track ID'), status: z.enum(['all', 'pending', 'generated', 'posted']).optional().default('all').describe('Filter by event status'), platform: platformSchema.optional().describe('Filter by platform (x, reddit, linkedin, instagram, tiktok, youtube)'), startDate: isoDateTimeSchema.optional().describe('Start date for filtering (YYYY-MM-DD). Date-only comparison - time is ignored.'), endDate: isoDateTimeSchema.optional().describe('End date for filtering (YYYY-MM-DD). Date-only comparison - time is ignored.'), limit: z.number().int().positive().max(100).optional().default(50).describe('Maximum number of events to return'), offset: z.number().int().nonnegative().optional().default(0).describe('Offset for pagination') }), execute: async (params) => { const db = await getDb(); let whereConditions = [eq(events.eventType, 'scheduled')]; if (params.trackId) { whereConditions.push(eq(events.trackId, params.trackId)); } if (params.platform) { whereConditions.push(eq(events.platform, params.platform)); } const results = await db.select({ event: events, track: tracks }) .from(events) .innerJoin(tracks, eq(events.trackId, tracks.id)) .where(and(...whereConditions)) .orderBy(asc(events.scheduledTime)) .limit(params.limit) .offset(params.offset); // Apply additional filters const filtered = results.filter(({ event }) => { // Status filter if (params.status !== 'all') { if (params.status === 'posted' && !event.posted) return false; if (params.status === 'generated' && (!event.contentGenerated || event.posted)) return false; if (params.status === 'pending' && event.contentGenerated) return false; } // Date filters - compare dates only, not times if (params.startDate) { const eventDate = new Date(event.scheduledTime); eventDate.setHours(0, 0, 0, 0); // Parse the filter date in local timezone by extracting YYYY-MM-DD const dateMatch = params.startDate.match(/^(\d{4})-(\d{2})-(\d{2})/); if (!dateMatch) return false; const startDate = new Date(parseInt(dateMatch[1]), parseInt(dateMatch[2]) - 1, parseInt(dateMatch[3]), 0, 0, 0, 0); if (eventDate < startDate) return false; } if (params.endDate) { const eventDate = new Date(event.scheduledTime); eventDate.setHours(0, 0, 0, 0); // Parse the filter date in local timezone by extracting YYYY-MM-DD const dateMatch = params.endDate.match(/^(\d{4})-(\d{2})-(\d{2})/); if (!dateMatch) return false; const endDate = new Date(parseInt(dateMatch[1]), parseInt(dateMatch[2]) - 1, parseInt(dateMatch[3]), 0, 0, 0, 0); if (eventDate > endDate) return false; } return true; }); const response = { events: filtered.map(({ event, track }) => { const parsedEvent = parseEventFromDb(event); return eventResponseSchema.parse({ id: parsedEvent.id, trackId: parsedEvent.trackId, trackName: track.name, name: parsedEvent.name, prompt: parsedEvent.prompt, // Now using prompt field platform: parsedEvent.platform, scheduledTime: parsedEvent.scheduledTime?.toISOString(), generationTime: parsedEvent.generationTime?.toISOString(), status: parsedEvent.posted ? 'posted' : (parsedEvent.contentGenerated ? 'generated' : 'pending'), mediaPath: parsedEvent.mediaPath, metadata: parsedEvent.metadata ? JSON.parse(parsedEvent.metadata) : undefined, generationSessionId: parsedEvent.generationSessionId, postingSessionId: parsedEvent.postingSessionId, generationStartedAt: parsedEvent.generationStartedAt?.toISOString(), approvalRequestedAt: parsedEvent.approvalRequestedAt?.toISOString(), error: parsedEvent.error, postedUrl: parsedEvent.postedUrl }); }), pagination: { limit: params.limit, offset: params.offset, total: filtered.length } }; return JSON.stringify(response, null, 2); } });