Skip to main content
Glama

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

TableJSON Schema
NameRequiredDescriptionDefault
trackNameYes
eventNameYes
promptYes
scheduledTimeYes
platformNox
agentNoclaude-sonnet-4-5-20250929
approvalViaNomanual
mcpToolsNo
metadataNoPlatform-specific metadata (e.g., { targetSubreddit: "subredditname" } for Reddit posts)

Implementation Reference

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

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