MCP server for reading WhatsApp data via the KaptionAI Chrome extension, with experimental support for WebMCP
The server demonstrates solid definition quality with 8 well-structured tools, comprehensive parameter descriptions, and explicit Zod schemas. Tool names follow verb-noun conventions (query, summarize_conversation, manage_*). Descriptions are substantive and include usage examples. However, output schemas are not documented, error handling guidance is minimal, and several tools bundle related actions into single tools rather than splitting concerns. The query tool in particular is feature-rich but somewhat monolithic. Tool annotations are declared but not fully populated across all tools.
Download media content (image, video, audio, document, sticker) from a WhatsApp message. Returns base64-encoded media data with metadata. Get message_id from query results. The message must be a media message. Examples: Download an image: { message_id: "[email protected]_3EB0...", conversation_id: "[email protected]" }
Get information about the local HTTP REST API endpoint, including URL, authentication token, and available endpoints.
Manage chat state: archive, unarchive, mark as read/unread, pin, unpin, mute, unmute, set/clear draft. Actions: archive - Archive a conversation unarchive - Unarchive a conversation mark_read - Mark a conversation as read mark_unread - Mark a conversation as unread pin - Pin a conversation (max 3 pinned) unpin - Unpin a conversation mute - Mute notifications (use mute_duration for duration) unmute - Unmute notifications set_draft - Set a draft message in the compose box (requires text) clear_draft - Clear the draft message
Manage WhatsApp Business labels. Requires a WhatsApp Business account. Actions: add - Add a label to a conversation (requires label_name/label_id + conversation_id) remove - Remove a label from a conversation (requires label_name/label_id + conversation_id) create - Create a new label (requires label_name) delete - Delete a label (requires label_name or label_id)
Output schemas not documented for any tool. LLMs cannot plan downstream calls without knowing what fields are returned. E.g., query returns conversation objects with what fields? Does download_media return just base64 or also metadata like filename, mimetype, size? Does summarize_conversation return a summary string, or an object with summary + metadata?
Multiple tools use manage_* naming (manage_labels, manage_notes, manage_chat, manage_reminders) bundling unrelated sub-actions (add, remove, create, delete, set, get, list, etc.). This violates single-responsibility. LLMs must reason about which action to pass, increasing cognitive load. Recommend splitting into atomic tools: create_label, add_label_to_conversation, delete_label, etc.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 56 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 37 | - | v1 |
Manage contact notes. Requires a WhatsApp Business account with notes enabled. Actions: get - Read the note for a contact set - Write/update the note for a contact
Manage personal reminders. Reminders are stored in the cloud and trigger notifications via the Kaption extension. Actions: list - List all reminders get - Get a specific reminder by ID create - Create a new reminder (requires title + datetime) update - Update a reminder (requires id, optional title/datetime) delete - Delete a reminder (requires id) complete - Mark a reminder as completed (requires id) uncomplete - Mark a reminder as not completed (requires id) Examples: List all: { action: "list" } Create: { action: "create", title: "Follow up with client", datetime: "2026-03-07T14:00:00Z" } Complete: { action: "complete", id: "rem_abc123" }
Query WhatsApp data: conversations, contacts, messages, transcriptions, labels, and communities. Supports listing, searching, filtering, and looking up by ID. IMPORTANT: Multiple WhatsApp accounts may be connected (e.g. personal + business). Always query entity="session" FIRST to see all connected accounts and their session IDs. Then use target_session to route queries to the correct account. Each account has different conversations, contacts, and messages. HOW TO READ MESSAGES: To get messages from a specific conversation, pass its id (e.g. "[email protected]"). This returns the conversation info WITH its messages. Use limit to control how many. Do NOT use entity="messages" for this — that is for global text search only. AUDIO TRANSCRIPTIONS: To get audio transcriptions, use entity="transcriptions" with an optional query. Or pass a conversation id to see messages (audio messages include transcription text). Examples: List sessions: { entity: "session" } List conversations: {} Target specific account: { entity: "conversations", target_session: "sess_abc123" } Read messages: { id: "[email protected]" } Read last 100 msgs: { id: "[email protected]", limit: 100 } Search globally: { query: "meeting" } Search in chat: { id: "[email protected]", query: "meeting" } Unread conversations: { unread: true } Search contacts: { query: "Alice", entity: "contacts" } List labels: { entity: "labels" } Filter by label: { label: "Important", entity: "conversations" } List communities: { entity: "communities" } Filter by community: { community: "My Community", entity: "conversations" } Find which groups a contact is in: { id: "[email protected]", entity: "contacts", include_participants: true } List members of a group: { entity: "contacts", group: "[email protected]" }
Get or generate a summary of a conversation
Error handling and recovery guidance is absent. No tool documents what happens on common failures (resource not found, permission denied, malformed input). E.g., manage_labels.add should document: 'If label not found, call query with entity=labels to list available labels.' No error classification (retryable vs user-fixable vs fatal).
They lack context on when to use these tools, what they return, and prerequisites. Descriptions should be 50-200 chars, explaining WHAT, WHEN, and PREREQUISITES.
Conditional parameter requirements are not enforced clearly in all cases. E.g., manage_chat.mute requires mute_duration, but schema does not mark mute_duration as conditionally required. manage_labels.add/remove require at least one of label_name or label_id, but this is not explicitly stated in schema constraints (only in description). LLMs may omit required params in certain action branches.
Tool annotations (readOnlyHint, destructiveHint, idempotentHint) are declared in the ToolAnnotations interface but not populated in the TOOLS array. Tools like delete_label (within manage_labels) should be marked destructiveHint: true; query and summarize_conversation should be marked readOnlyHint: true. Without these hints, LLMs cannot reason about side effects.
No pagination guidance for tools returning lists. query can return up to 5000 results (limit param cap). No documentation on whether results are always sorted, support cursor-based pagination (before/after params exist but are only for messages), or what happens when hitting the limit. Large result sets risk exhausting context windows.
get_api_info lacks context. The description does not explain why an LLM would call this tool, what 'available endpoints' means in the context of MCP (this server does not expose a REST API through MCP), or what the response structure is. This appears to be internal debugging; unclear if agents should ever call it.