timeline_add_scheduled_event
Schedule social media posts across multiple platforms by adding events to organized tracks for content automation workflows.
Instructions
Add a scheduled event to a track. IMPORTANT: 1) Use the terminal MCP tool to get the current date/time (execute_command("date")) before scheduling events to ensure correct dates. 2) ALWAYS use timeline_list_tracks first to check existing tracks - if a track with a similar name or purpose already exists, use that instead of creating a new one. If unsure whether an existing track matches your needs, ask the user for clarification before proceeding.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| trackName | Yes | ||
| eventName | Yes | ||
| prompt | Yes | ||
| scheduledTime | Yes | ||
| platform | No | x | |
| agent | No | claude-sonnet-4-5-20250929 | |
| approvalVia | No | manual | |
| mcpTools | No | ||
| metadata | No | Platform-specific metadata (e.g., { targetSubreddit: "subredditname" } for Reddit posts) |
Implementation Reference
- timeline-fastmcp.ts:138-270 (handler)The execute function implementing the core logic for adding a scheduled event: validates input, finds or creates track, creates media directory and info.json, prepares and inserts event data into database, returns event details.execute: async (params) => { console.error('[Timeline MCP] Add scheduled event called with params:', JSON.stringify(params, null, 2)); const db = await getDb(); try { // Validate params const validatedParams = addScheduledEventParams.parse(params); console.error('[Timeline MCP] Validated params:', JSON.stringify(validatedParams, null, 2)); // Find or create track let track = await db.select().from(tracks) .where(and(eq(tracks.name, validatedParams.trackName), eq(tracks.type, 'planned'))) .limit(1); if (track.length === 0) { const maxOrder = await db.select({ maxOrder: tracks.order }) .from(tracks) .orderBy(desc(tracks.order)) .limit(1); const newOrder = (maxOrder[0]?.maxOrder || 0) + 1; const trackId = uuidv4(); const postyAccountId = await getDefaultPostyAccountId(); await db.insert(tracks).values({ id: trackId, postyAccountId, name: validatedParams.trackName, type: 'planned', order: newOrder }); const [newTrack] = await db.select().from(tracks).where(eq(tracks.id, trackId)); track = [newTrack]; } // Generate event ID first const eventId = uuidv4(); // Create media folder path const mediaPath = await createMediaPath(validatedParams.trackName, validatedParams.eventName); // Create the actual folder on disk const workspacePath = getWorkspacePath(); const fullMediaPath = path.join(workspacePath, mediaPath); console.error('[Timeline MCP] Creating media folder:', fullMediaPath); try { await fs.mkdir(fullMediaPath, { recursive: true }); // Create an info.json file with event metadata const infoFile = path.join(fullMediaPath, 'info.json'); const info = { eventId: eventId, eventName: validatedParams.eventName, trackId: track[0].id, createdAt: new Date().toISOString() }; await fs.writeFile(infoFile, JSON.stringify(info, null, 2)); console.error('[Timeline MCP] Media folder created successfully with info.json'); } catch (error) { console.error('[Timeline MCP] Error creating media folder:', error); // Continue even if folder creation fails } // Create event const scheduledTime = new Date(validatedParams.scheduledTime); const generationTime = calculateGenerationTime(scheduledTime); const postyAccountId = await getDefaultPostyAccountId(); const eventData = prepareEventForDb({ id: eventId, postyAccountId, trackId: track[0].id, name: validatedParams.eventName, platform: validatedParams.platform, scheduledTime: scheduledTime, generationTime: generationTime, prompt: validatedParams.prompt, // Store prompt string directly agent: validatedParams.agent, eventType: 'scheduled', mediaPath: mediaPath, mcpTools: JSON.stringify(validatedParams.mcpTools), approvalVia: validatedParams.approvalVia, metadata: JSON.stringify(validatedParams.metadata || {}), // Platform-specific metadata contentGenerated: false, approved: false, posted: false }); await db.insert(events).values(eventData); const [newEvent] = await db.select().from(events).where(eq(events.id, eventId)); const response = { success: true, event: { id: newEvent.id, trackId: newEvent.trackId, name: newEvent.name, scheduledTime: newEvent.scheduledTime, generationTime: newEvent.generationTime, mediaPath: newEvent.mediaPath, platform: newEvent.platform, metadata: newEvent.metadata ? JSON.parse(newEvent.metadata) : undefined } }; // Log event creation console.log('[MCP Timeline] Event created:', newEvent.id, newEvent.name); return JSON.stringify(response, null, 2); } catch (error) { console.error('[Timeline MCP] Error in add_scheduled_event:', error); if (error instanceof z.ZodError) { return JSON.stringify({ success: false, error: 'Validation error', details: error.errors }, null, 2); } return JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error occurred', stack: error instanceof Error ? error.stack : undefined }, null, 2); } }
- timeline-fastmcp.ts:120-130 (schema)Zod schema defining the input parameters for the timeline_add_scheduled_event tool, including validation rules for trackName, eventName, prompt, scheduledTime, platform, agent, etc.const addScheduledEventParams = z.object({ trackName: z.string().min(1, 'Track name cannot be empty').max(100, 'Track name too long'), eventName: z.string().min(1, 'Event name cannot be empty').max(200, 'Event name too long'), prompt: z.string().min(1, 'Prompt cannot be empty').max(5000, 'Prompt too long'), scheduledTime: isoDateTimeSchema, platform: platformSchema.default('x'), agent: agentSchema.optional().default('claude-sonnet-4-5-20250929'), approvalVia: z.string().optional().default('manual'), mcpTools: z.array(z.string()).optional().default(['timeline', 'fal', 'sqlite', 'playwright']), metadata: z.record(z.any()).optional().describe('Platform-specific metadata (e.g., { targetSubreddit: "subredditname" } for Reddit posts)') });
- timeline-fastmcp.ts:134-271 (registration)Registration of the timeline_add_scheduled_event tool with FastMCP using mcp.addTool(), including name, description, parameters schema, and execute handler.mcp.addTool({ name: 'timeline_add_scheduled_event', description: 'Add a scheduled event to a track. IMPORTANT: 1) Use the terminal MCP tool to get the current date/time (execute_command("date")) before scheduling events to ensure correct dates. 2) ALWAYS use timeline_list_tracks first to check existing tracks - if a track with a similar name or purpose already exists, use that instead of creating a new one. If unsure whether an existing track matches your needs, ask the user for clarification before proceeding.', parameters: addScheduledEventParams, execute: async (params) => { console.error('[Timeline MCP] Add scheduled event called with params:', JSON.stringify(params, null, 2)); const db = await getDb(); try { // Validate params const validatedParams = addScheduledEventParams.parse(params); console.error('[Timeline MCP] Validated params:', JSON.stringify(validatedParams, null, 2)); // Find or create track let track = await db.select().from(tracks) .where(and(eq(tracks.name, validatedParams.trackName), eq(tracks.type, 'planned'))) .limit(1); if (track.length === 0) { const maxOrder = await db.select({ maxOrder: tracks.order }) .from(tracks) .orderBy(desc(tracks.order)) .limit(1); const newOrder = (maxOrder[0]?.maxOrder || 0) + 1; const trackId = uuidv4(); const postyAccountId = await getDefaultPostyAccountId(); await db.insert(tracks).values({ id: trackId, postyAccountId, name: validatedParams.trackName, type: 'planned', order: newOrder }); const [newTrack] = await db.select().from(tracks).where(eq(tracks.id, trackId)); track = [newTrack]; } // Generate event ID first const eventId = uuidv4(); // Create media folder path const mediaPath = await createMediaPath(validatedParams.trackName, validatedParams.eventName); // Create the actual folder on disk const workspacePath = getWorkspacePath(); const fullMediaPath = path.join(workspacePath, mediaPath); console.error('[Timeline MCP] Creating media folder:', fullMediaPath); try { await fs.mkdir(fullMediaPath, { recursive: true }); // Create an info.json file with event metadata const infoFile = path.join(fullMediaPath, 'info.json'); const info = { eventId: eventId, eventName: validatedParams.eventName, trackId: track[0].id, createdAt: new Date().toISOString() }; await fs.writeFile(infoFile, JSON.stringify(info, null, 2)); console.error('[Timeline MCP] Media folder created successfully with info.json'); } catch (error) { console.error('[Timeline MCP] Error creating media folder:', error); // Continue even if folder creation fails } // Create event const scheduledTime = new Date(validatedParams.scheduledTime); const generationTime = calculateGenerationTime(scheduledTime); const postyAccountId = await getDefaultPostyAccountId(); const eventData = prepareEventForDb({ id: eventId, postyAccountId, trackId: track[0].id, name: validatedParams.eventName, platform: validatedParams.platform, scheduledTime: scheduledTime, generationTime: generationTime, prompt: validatedParams.prompt, // Store prompt string directly agent: validatedParams.agent, eventType: 'scheduled', mediaPath: mediaPath, mcpTools: JSON.stringify(validatedParams.mcpTools), approvalVia: validatedParams.approvalVia, metadata: JSON.stringify(validatedParams.metadata || {}), // Platform-specific metadata contentGenerated: false, approved: false, posted: false }); await db.insert(events).values(eventData); const [newEvent] = await db.select().from(events).where(eq(events.id, eventId)); const response = { success: true, event: { id: newEvent.id, trackId: newEvent.trackId, name: newEvent.name, scheduledTime: newEvent.scheduledTime, generationTime: newEvent.generationTime, mediaPath: newEvent.mediaPath, platform: newEvent.platform, metadata: newEvent.metadata ? JSON.parse(newEvent.metadata) : undefined } }; // Log event creation console.log('[MCP Timeline] Event created:', newEvent.id, newEvent.name); return JSON.stringify(response, null, 2); } catch (error) { console.error('[Timeline MCP] Error in add_scheduled_event:', error); if (error instanceof z.ZodError) { return JSON.stringify({ success: false, error: 'Validation error', details: error.errors }, null, 2); } return JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error occurred', stack: error instanceof Error ? error.stack : undefined }, null, 2); } } });