Skip to main content
Glama

create-scheduled-message

Schedule messages to send later in Zulip channels or private conversations by specifying delivery time and recipient details.

Instructions

Schedule a message to be sent at a future time. For direct messages, use comma-separated email addresses or get user info from the users-directory resource (zulip://users).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
typeYesMessage type: 'stream' for channels, 'direct' for private messages
toYesFor streams: channel name (e.g., 'general'). For direct: comma-separated user emails (e.g., 'user@example.com,user2@example.com')
contentYesMessage content with Markdown formatting
topicNoTopic for stream messages
scheduled_delivery_timestampYesUnix timestamp when message should be sent (seconds since epoch)

Implementation Reference

  • The main handler function for the 'create-scheduled-message' MCP tool. It calls the ZulipClient, handles the response, and formats MCP-compliant success/error messages.
    async ({ type, to, content, topic, scheduled_delivery_timestamp }) => {
      try {
        const result = await zulipClient.createScheduledMessage({
          type,
          to,
          content,
          topic,
          scheduled_delivery_timestamp
        });
        return createSuccessResponse(JSON.stringify({
          success: true,
          scheduled_message_id: result.scheduled_message_id,
          delivery_time: new Date(scheduled_delivery_timestamp * 1000).toISOString(),
          message: `Message scheduled successfully! ID: ${result.scheduled_message_id}`
        }, null, 2));
      } catch (error) {
        return createErrorResponse(`Error creating scheduled message: ${error instanceof Error ? error.message : 'Unknown error'}`);
      }
    }
  • Zod schema defining the input parameters and validation for the create-scheduled-message tool.
    export const CreateScheduledMessageSchema = z.object({
      type: z.enum(["stream", "direct"]).describe("Message type: 'stream' for channels, 'direct' for private messages"),
      to: z.string().describe("For streams: channel name (e.g., 'general'). For direct: comma-separated user emails (e.g., 'user@example.com,user2@example.com')"),
      content: z.string().describe("Message content with Markdown formatting"),
      topic: z.string().optional().describe("Topic for stream messages"),
      scheduled_delivery_timestamp: z.number().describe("Unix timestamp when message should be sent (seconds since epoch)")
    });
  • src/server.ts:639-662 (registration)
    Registration of the 'create-scheduled-message' tool with the MCP server, specifying name, description, input schema, and handler function.
    server.tool(
      "create-scheduled-message",
      "Schedule a message to be sent at a future time. For direct messages, use comma-separated email addresses or get user info from the users-directory resource (zulip://users).",
      CreateScheduledMessageSchema.shape,
      async ({ type, to, content, topic, scheduled_delivery_timestamp }) => {
        try {
          const result = await zulipClient.createScheduledMessage({
            type,
            to,
            content,
            topic,
            scheduled_delivery_timestamp
          });
          return createSuccessResponse(JSON.stringify({
            success: true,
            scheduled_message_id: result.scheduled_message_id,
            delivery_time: new Date(scheduled_delivery_timestamp * 1000).toISOString(),
            message: `Message scheduled successfully! ID: ${result.scheduled_message_id}`
          }, null, 2));
        } catch (error) {
          return createErrorResponse(`Error creating scheduled message: ${error instanceof Error ? error.message : 'Unknown error'}`);
        }
      }
    );
  • ZulipClient helper method that performs the actual HTTP API call to Zulip's /scheduled_messages endpoint to create the scheduled message.
    async createScheduledMessage(params: {
      type: 'stream' | 'direct';
      to: string;
      content: string;
      topic?: string;
      scheduled_delivery_timestamp: number;
    }): Promise<{ scheduled_message_id: number }> {
      // Convert our types to Zulip API types
      const zulipType = params.type === 'direct' ? 'private' : 'stream';
      
      const payload: any = {
        type: zulipType,
        content: params.content,
        scheduled_delivery_timestamp: params.scheduled_delivery_timestamp
      };
    
      // Handle recipients based on message type
      if (params.type === 'direct') {
        // For private messages, 'to' should be JSON array of user emails/IDs
        const recipients = params.to.split(',').map(email => email.trim());
        payload.to = JSON.stringify(recipients);
      } else {
        // For stream messages, 'to' is the stream name
        payload.to = params.to;
        if (params.topic) {
          payload.topic = params.topic;
        }
      }
    
      const response = await this.client.post('/scheduled_messages', payload, {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        transformRequest: [(data) => {
          const params = new URLSearchParams();
          for (const key in data) {
            if (data[key] !== undefined) {
              params.append(key, String(data[key]));
            }
          }
          return params.toString();  // Return string, not URLSearchParams object
        }]
      });
      return response.data;
    }

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/avisekrath/zulip-mcp-server'

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