Skip to main content
Glama

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

TableJSON Schema
NameRequiredDescriptionDefault
endDateNoEnd date for filtering (YYYY-MM-DD). Date-only comparison - time is ignored.
limitNoMaximum number of events to return
offsetNoOffset for pagination
platformNoFilter by platform (x, reddit, linkedin, instagram, tiktok, youtube)
startDateNoStart date for filtering (YYYY-MM-DD). Date-only comparison - time is ignored.
statusNoFilter by event statusall
trackIdNoFilter by track ID

Implementation Reference

  • 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); }
  • 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') }),
  • 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); } });

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/derekalia/timeline-mcp'

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