list_chats
Retrieve and organize WhatsApp conversations with pagination, sorting, and search filters to manage chat history.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max chats per page (default 20) | |
| page | No | Page number (0-indexed, default 0) | |
| sort_by | No | Sort order: 'last_active' (default) or 'name' | last_active |
| query | No | Optional filter by chat name or JID | |
| include_last_message | No | Include last message details (default true) |
Implementation Reference
- src/mcp.ts:217-267 (handler)Handler function that executes the list_chats tool. Calls getChats with parameters, handles empty results, formats chats using formatDbChatForJson, returns JSON text content or error.mcpLogger.info( `[MCP Tool] Executing list_chats: limit=${limit}, page=${page}, sort=${sort_by}, query=${query}, lastMsg=${include_last_message}`, ); try { const chats = getChats( limit, page, sort_by, query ?? null, include_last_message, ); if (!chats.length && page === 0) { return { content: [ { type: "text", text: `No chats found${query ? ` matching "${query}"` : ""}.`, }, ], }; } else if (!chats.length) { return { content: [ { type: "text", text: `No more chats found on page ${page}${ query ? ` matching "${query}"` : "" }.`, }, ], }; } const formattedChats = chats.map(formatDbChatForJson); return { content: [ { type: "text", text: JSON.stringify(formattedChats, null, 2), }, ], }; } catch (error: any) { mcpLogger.error(`[MCP Tool Error] list_chats failed: ${error.message}`); return { isError: true, content: [ { type: "text", text: `Error listing chats: ${error.message}` }, ], }; } },
- src/mcp.ts:186-216 (schema)Zod input schema defining parameters for the list_chats tool: pagination (limit, page), sorting (sort_by), filtering (query), and last message inclusion.{ limit: z .number() .int() .positive() .optional() .default(20) .describe("Max chats per page (default 20)"), page: z .number() .int() .nonnegative() .optional() .default(0) .describe("Page number (0-indexed, default 0)"), sort_by: z .enum(["last_active", "name"]) .optional() .default("last_active") .describe("Sort order: 'last_active' (default) or 'name'"), query: z .string() .optional() .describe("Optional filter by chat name or JID"), include_last_message: z .boolean() .optional() .default(true) .describe("Include last message details (default true)"), }, async ({ limit, page, sort_by, query, include_last_message }) => {
- src/mcp.ts:184-268 (registration)Registration of the list_chats tool on the MCP server using server.tool(name, inputSchema, handlerFn).server.tool( "list_chats", { limit: z .number() .int() .positive() .optional() .default(20) .describe("Max chats per page (default 20)"), page: z .number() .int() .nonnegative() .optional() .default(0) .describe("Page number (0-indexed, default 0)"), sort_by: z .enum(["last_active", "name"]) .optional() .default("last_active") .describe("Sort order: 'last_active' (default) or 'name'"), query: z .string() .optional() .describe("Optional filter by chat name or JID"), include_last_message: z .boolean() .optional() .default(true) .describe("Include last message details (default true)"), }, async ({ limit, page, sort_by, query, include_last_message }) => { mcpLogger.info( `[MCP Tool] Executing list_chats: limit=${limit}, page=${page}, sort=${sort_by}, query=${query}, lastMsg=${include_last_message}`, ); try { const chats = getChats( limit, page, sort_by, query ?? null, include_last_message, ); if (!chats.length && page === 0) { return { content: [ { type: "text", text: `No chats found${query ? ` matching "${query}"` : ""}.`, }, ], }; } else if (!chats.length) { return { content: [ { type: "text", text: `No more chats found on page ${page}${ query ? ` matching "${query}"` : "" }.`, }, ], }; } const formattedChats = chats.map(formatDbChatForJson); return { content: [ { type: "text", text: JSON.stringify(formattedChats, null, 2), }, ], }; } catch (error: any) { mcpLogger.error(`[MCP Tool Error] list_chats failed: ${error.message}`); return { isError: true, content: [ { type: "text", text: `Error listing chats: ${error.message}` }, ], }; } }, );
- src/database.ts:207-257 (helper)Core database query function getChats() that retrieves paginated, sorted, filtered list of chats with optional last message details. Called by the list_chats handler.export function getChats( limit: number = 20, page: number = 0, sortBy: "last_active" | "name" = "last_active", query?: string | null, includeLastMessage: boolean = true, ): Chat[] { const db = getDb(); try { const offset = page * limit; let sql = ` SELECT c.jid, c.name, c.last_message_time ${ includeLastMessage ? `, (SELECT m.content FROM messages m WHERE m.chat_jid = c.jid ORDER BY m.timestamp DESC LIMIT 1) as last_message, (SELECT m.sender FROM messages m WHERE m.chat_jid = c.jid ORDER BY m.timestamp DESC LIMIT 1) as last_sender, (SELECT m.is_from_me FROM messages m WHERE m.chat_jid = c.jid ORDER BY m.timestamp DESC LIMIT 1) as last_is_from_me ` : "" } FROM chats c `; const params: (string | number)[] = []; if (query) { sql += ` WHERE (LOWER(c.name) LIKE LOWER(?) OR c.jid LIKE ?)`; params.push(`%${query}%`, `%${query}%`); } const orderByClause = sortBy === "last_active" ? "c.last_message_time DESC NULLS LAST" : "c.name ASC"; sql += ` ORDER BY ${orderByClause}, c.jid ASC`; sql += ` LIMIT ? OFFSET ?`; params.push(limit, offset); const stmt = db.prepare(sql); const rows = stmt.all(...params) as any[]; return rows.map(rowToChat); } catch (error) { console.error("Error getting chats:", error); return []; } }
- src/mcp.ts:37-52 (helper)Utility function to format database Chat objects into a JSON-friendly structure suitable for tool output, used in list_chats handler.function formatDbChatForJson(chat: DbChat) { return { jid: chat.jid, name: chat.name ?? chat.jid.split("@")[0] ?? "Unknown Chat", is_group: chat.jid.endsWith("@g.us"), last_message_time: chat.last_message_time?.toISOString() ?? null, last_message_preview: chat.last_message ?? null, last_sender_jid: chat.last_sender ?? null, last_sender_display: chat.last_sender ? chat.last_sender.split("@")[0] : chat.last_is_from_me ? "Me" : null, last_is_from_me: chat.last_is_from_me ?? null, }; }