create-scheduled-message
Schedule a Zulip message for future delivery in a stream or as a direct message. Specify the channel or recipients, content, and delivery timestamp.
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
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | Message type: 'stream' for channels, 'direct' for private messages | |
| to | Yes | For streams: channel name (e.g., 'general'). For direct: comma-separated user emails (e.g., 'user@example.com,user2@example.com') | |
| content | Yes | Message content with Markdown formatting | |
| topic | No | Topic for stream messages | |
| scheduled_delivery_timestamp | Yes | Unix timestamp when message should be sent (seconds since epoch) |
Implementation Reference
- src/server.ts:639-660 (handler)MCP tool handler that receives validated input, calls the Zulip client to schedule a message, and returns success/error response.
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'}`); } - src/types.ts:147-153 (schema)Zod schema defining the input validation for the create-scheduled-message tool: type (stream/direct), to (string), content (string), optional topic, and scheduled_delivery_timestamp (number).
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:13-22 (registration)Import of CreateScheduledMessageSchema into server.ts, enabling registration of the tool.
import { ZulipConfig, SendMessageSchema, GetMessagesSchema, UploadFileSchema, EditMessageSchema, AddReactionSchema, RemoveReactionSchema, CreateScheduledMessageSchema, EditScheduledMessageSchema, - src/zulip/client.ts:250-294 (helper)ZulipClient helper method that maps the MCP tool's parameters to the Zulip API format (converts 'direct' to 'private', handles recipient parsing) and POSTs to /scheduled_messages.
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; } - src/types.ts:256-256 (helper)TypeScript type inferred from the schema for type-safe usage.
export type CreateScheduledMessageParams = z.infer<typeof CreateScheduledMessageSchema>;