get-messages
Retrieve Zulip messages in bulk with filtering, pagination, and search to browse conversations, find content, or access message history.
Instructions
š BULK RETRIEVAL: Get multiple messages with filtering, pagination, and search. Use this to browse conversations, search for content, or get message history. Returns array of messages with basic details.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| anchor | No | Starting point: message ID, 'newest', 'oldest', or 'first_unread' | |
| num_before | No | Number of messages before anchor (max 1000) | |
| num_after | No | Number of messages after anchor (max 1000) | |
| narrow | No | Filters: [['stream', 'channel-name'], ['topic', 'topic-name'], ['sender', 'email'], ['search', 'query']] | |
| message_id | No | Get specific message by ID instead of using anchor/num parameters |
Implementation Reference
- src/server.ts:434-460 (handler)The main handler function for the 'get-messages' tool. It invokes the ZulipClient.getMessages method with provided parameters, processes the response by mapping message fields and formatting timestamps, and returns a JSON-formatted success response or an error response.async ({ anchor, num_before, num_after, narrow, message_id }) => { try { const result = await zulipClient.getMessages({ anchor, num_before, num_after, narrow, message_id }); return createSuccessResponse(JSON.stringify({ message_count: result.messages.length, messages: result.messages.map(msg => ({ id: msg.id, sender: msg.sender_full_name, timestamp: new Date(msg.timestamp * 1000).toISOString(), content: msg.content, type: msg.type, topic: msg.topic || msg.subject, stream_id: msg.stream_id, reactions: msg.reactions })) }, null, 2)); } catch (error) { return createErrorResponse(`Error retrieving messages: ${error instanceof Error ? error.message : 'Unknown error'}`); } }
- src/types.ts:120-126 (schema)Zod schema defining the input validation for the 'get-messages' tool parameters including anchor, pagination options (num_before, num_after), filtering (narrow), and single message retrieval (message_id).export const GetMessagesSchema = z.object({ anchor: z.union([z.number(), z.enum(["newest", "oldest", "first_unread"])]).optional().describe("Starting point: message ID, 'newest', 'oldest', or 'first_unread'"), num_before: z.number().max(1000).optional().describe("Number of messages before anchor (max 1000)"), num_after: z.number().max(1000).optional().describe("Number of messages after anchor (max 1000)"), narrow: z.array(z.array(z.string())).optional().describe("Filters: [['stream', 'channel-name'], ['topic', 'topic-name'], ['sender', 'email'], ['search', 'query']]"), message_id: z.number().optional().describe("Get specific message by ID instead of using anchor/num parameters") });
- src/server.ts:430-461 (registration)MCP tool registration using server.tool(), including the tool name 'get-messages', description, input schema, and handler function.server.tool( "get-messages", "š BULK RETRIEVAL: Get multiple messages with filtering, pagination, and search. Use this to browse conversations, search for content, or get message history. Returns array of messages with basic details.", GetMessagesSchema.shape, async ({ anchor, num_before, num_after, narrow, message_id }) => { try { const result = await zulipClient.getMessages({ anchor, num_before, num_after, narrow, message_id }); return createSuccessResponse(JSON.stringify({ message_count: result.messages.length, messages: result.messages.map(msg => ({ id: msg.id, sender: msg.sender_full_name, timestamp: new Date(msg.timestamp * 1000).toISOString(), content: msg.content, type: msg.type, topic: msg.topic || msg.subject, stream_id: msg.stream_id, reactions: msg.reactions })) }, null, 2)); } catch (error) { return createErrorResponse(`Error retrieving messages: ${error instanceof Error ? error.message : 'Unknown error'}`); } } );
- src/zulip/client.ts:157-182 (helper)ZulipClient helper method that handles the actual HTTP API requests to Zulip's /messages endpoint, supporting both bulk retrieval with anchors/narrowing and single message by ID.async getMessages(params: { anchor?: number | string; num_before?: number; num_after?: number; narrow?: string[][]; message_id?: number; } = {}): Promise<{ messages: ZulipMessage[] }> { if (params.message_id) { const response = await this.client.get(`/messages/${params.message_id}`); return { messages: [response.data.message] }; } const queryParams: any = {}; // Only set parameters that are provided, with appropriate defaults queryParams.anchor = params.anchor !== undefined ? params.anchor : 'newest'; queryParams.num_before = params.num_before !== undefined ? params.num_before : 20; queryParams.num_after = params.num_after !== undefined ? params.num_after : 0; if (params.narrow) { queryParams.narrow = JSON.stringify(params.narrow); } const response = await this.client.get('/messages', { params: queryParams }); return response.data; }