list_unread_guest_threads
Retrieve recent guest conversations with unread messages and attention signals to monitor communication in hospitality management.
Instructions
List recent guest threads with raw unread metadata and derived attention signals.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| messageLimit | No |
Implementation Reference
- The handler implementation for the `list_unread_guest_threads` tool, which fetches conversations, resolves reservations and listings, builds summaries, and returns threads that need attention or have unread messages.
async ({ limit, messageLimit }) => { const reservationCache = new Map<string, Promise<RawHostawayReservationLike | null>>(); const listingCache = new Map<string, Promise<RawHostawayListing | null>>(); const conversations = await client.listConversations({ limit: limit ?? 10, includeResources: 1 }); async function getReservation(conversation: RawHostawayConversation) { if (conversation.Reservation) { return conversation.Reservation; } if (conversation.reservationId == null) { return null; } const key = `${conversation.reservationId}`; if (!reservationCache.has(key)) { reservationCache.set( key, client.getReservation(conversation.reservationId).catch(() => null) ); } return reservationCache.get(key)!; } async function getListing(conversation: RawHostawayConversation, reservation: RawHostawayReservationLike | null) { const listingId = listingIdFrom(conversation, reservation); if (listingId == null) { return null; } const key = `${listingId}`; if (!listingCache.has(key)) { listingCache.set(key, client.getListing(listingId).catch(() => null)); } return listingCache.get(key)!; } const summaries = []; for (const conversation of conversations) { if (conversation.isArchived) { continue; } const [messages, reservation] = await Promise.all([ client.getConversationMessages(conversation.id ?? "", { limit: messageLimit ?? 10 }), getReservation(conversation) ]); const listing = await getListing(conversation, reservation); const summary = buildUnreadThreadSummary({ conversation, messages, reservation, listing }); if (summary.rawHasUnreadMessages === true || summary.needsAttention) { summaries.push(summary); } } summaries.sort((left, right) => { if (left.needsAttention !== right.needsAttention) { return Number(right.needsAttention) - Number(left.needsAttention); } const leftTime = left.latestGuestMessageTimestamp ? new Date(left.latestGuestMessageTimestamp).getTime() : 0; const rightTime = right.latestGuestMessageTimestamp ? new Date(right.latestGuestMessageTimestamp).getTime() : 0; return rightTime - leftTime; }); return toolResult({ total: summaries.length, threads: summaries }); } ); - The Zod schemas defining the input parameters (limit, messageLimit) and the output structure for the tool.
inputSchema: { limit: z.number().int().min(1).max(50).optional(), messageLimit: z.number().int().min(1).max(50).optional() }, outputSchema: { total: z.number(), threads: z.array( z.object({ conversationId: z.string(), reservationId: z.string().nullable(), listingId: z.string().nullable(), listingName: z.string().nullable(), guestName: z.string(), channel: z.enum(["Airbnb", "Booking.com", "VRBO", "Direct"]), arrivalDate: z.string().nullable(), departureDate: z.string().nullable(), latestGuestMessageTimestamp: z.string().nullable(), rawHasUnreadMessages: z.boolean().nullable(), hostRepliedAfterLatestGuestMessage: z.boolean(), needsAttention: z.boolean(), preview: z.string() }) ) } - src/tools/list-unread-guest-threads.ts:24-27 (registration)The registration of the `list_unread_guest_threads` tool on the MCP server.
export function registerListUnreadGuestThreadsTool(server: McpServer, client: HostawayDataClient) { server.registerTool( "list_unread_guest_threads", {