send_message_with_buttons
Send WhatsApp messages with interactive reply buttons to collect user responses, enabling quick selection from up to three options with optional header and footer text.
Instructions
Send a message with reply buttons (up to 3).
CONSTRAINTS:
Maximum 3 buttons per message
Button title: max 20 characters
Button ID (callback_data): max 256 characters
Header text: max 60 characters (if provided)
Footer text: max 60 characters (if provided)
EXAMPLE: { "to": "+1234567890", "text": "Choose an option:", "buttons": [ {"id": "option_1", "title": "Yes"}, {"id": "option_2", "title": "No"}, {"id": "option_3", "title": "Maybe"} ], "header": "Quick Question", "footer": "Select one option" }
Args: to: Phone number (with country code) or WhatsApp ID text: Message body text (main message content) buttons: List of buttons with 'id' and 'title' keys (max 3) header: Optional header text (appears above main text) footer: Optional footer text (appears below buttons) reply_to_message_id: Message ID to reply to
Returns: Dictionary with success status and message ID
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | ||
| text | Yes | ||
| buttons | Yes | ||
| header | No | ||
| footer | No | ||
| reply_to_message_id | No |
Implementation Reference
- tools/interactive.py:14-100 (handler)The main implementation of send_message_with_buttons tool. This async function sends WhatsApp messages with up to 3 reply buttons. It validates constraints (button limits, title/id lengths, header/footer lengths), converts button dictionaries to PyWA Button objects, calls wa_client.send_message(), and returns success/error response with message ID.
@mcp.tool() async def send_message_with_buttons( to: str, text: str, buttons: List[Dict[str, str]], header: Optional[str] = None, footer: Optional[str] = None, *, reply_to_message_id: Optional[str] = None, ) -> dict: """ Send a message with reply buttons (up to 3). CONSTRAINTS: - Maximum 3 buttons per message - Button title: max 20 characters - Button ID (callback_data): max 256 characters - Header text: max 60 characters (if provided) - Footer text: max 60 characters (if provided) EXAMPLE: { "to": "+1234567890", "text": "Choose an option:", "buttons": [ {"id": "option_1", "title": "Yes"}, {"id": "option_2", "title": "No"}, {"id": "option_3", "title": "Maybe"} ], "header": "Quick Question", "footer": "Select one option" } Args: to: Phone number (with country code) or WhatsApp ID text: Message body text (main message content) buttons: List of buttons with 'id' and 'title' keys (max 3) header: Optional header text (appears above main text) footer: Optional footer text (appears below buttons) reply_to_message_id: Message ID to reply to Returns: Dictionary with success status and message ID """ try: # Validate constraints if len(buttons) > 3: return {"success": False, "error": "Maximum 3 buttons allowed"} if header and len(header) > 60: return {"success": False, "error": "Header text must be max 60 characters"} if footer and len(footer) > 60: return {"success": False, "error": "Footer text must be max 60 characters"} # Convert button dictionaries to PyWA Button objects button_objects = [] for btn in buttons: if "id" not in btn or "title" not in btn: return {"success": False, "error": "Each button must have 'id' and 'title' keys"} if len(btn["title"]) > 20: return {"success": False, "error": f"Button title '{btn['title']}' exceeds 20 characters"} if len(btn["id"]) > 256: return {"success": False, "error": f"Button ID '{btn['id']}' exceeds 256 characters"} button_objects.append(Button( title=btn["title"], callback_data=btn["id"] )) result = wa_client.send_message( to=to, text=text, buttons=button_objects, header=header, footer=footer, reply_to_message_id=reply_to_message_id, ) logger.info(f"Message with buttons sent to {to}") message_id = getattr(result, 'id', str(result)) if result else None return {"success": True, "message_id": message_id} except Exception as e: logger.error(f"Failed to send message with buttons: {str(e)}") return {"success": False, "error": str(e)} - tools/interactive.py:11-101 (registration)The register_interactive_tools function that registers the send_message_with_buttons tool using the @mcp.tool() decorator at line 14. This function is called from the main register_all_tools in __init__.py to register all interactive messaging tools.
def register_interactive_tools(mcp, wa_client: WhatsApp): """Register interactive messaging tools.""" @mcp.tool() async def send_message_with_buttons( to: str, text: str, buttons: List[Dict[str, str]], header: Optional[str] = None, footer: Optional[str] = None, *, reply_to_message_id: Optional[str] = None, ) -> dict: """ Send a message with reply buttons (up to 3). CONSTRAINTS: - Maximum 3 buttons per message - Button title: max 20 characters - Button ID (callback_data): max 256 characters - Header text: max 60 characters (if provided) - Footer text: max 60 characters (if provided) EXAMPLE: { "to": "+1234567890", "text": "Choose an option:", "buttons": [ {"id": "option_1", "title": "Yes"}, {"id": "option_2", "title": "No"}, {"id": "option_3", "title": "Maybe"} ], "header": "Quick Question", "footer": "Select one option" } Args: to: Phone number (with country code) or WhatsApp ID text: Message body text (main message content) buttons: List of buttons with 'id' and 'title' keys (max 3) header: Optional header text (appears above main text) footer: Optional footer text (appears below buttons) reply_to_message_id: Message ID to reply to Returns: Dictionary with success status and message ID """ try: # Validate constraints if len(buttons) > 3: return {"success": False, "error": "Maximum 3 buttons allowed"} if header and len(header) > 60: return {"success": False, "error": "Header text must be max 60 characters"} if footer and len(footer) > 60: return {"success": False, "error": "Footer text must be max 60 characters"} # Convert button dictionaries to PyWA Button objects button_objects = [] for btn in buttons: if "id" not in btn or "title" not in btn: return {"success": False, "error": "Each button must have 'id' and 'title' keys"} if len(btn["title"]) > 20: return {"success": False, "error": f"Button title '{btn['title']}' exceeds 20 characters"} if len(btn["id"]) > 256: return {"success": False, "error": f"Button ID '{btn['id']}' exceeds 256 characters"} button_objects.append(Button( title=btn["title"], callback_data=btn["id"] )) result = wa_client.send_message( to=to, text=text, buttons=button_objects, header=header, footer=footer, reply_to_message_id=reply_to_message_id, ) logger.info(f"Message with buttons sent to {to}") message_id = getattr(result, 'id', str(result)) if result else None return {"success": True, "message_id": message_id} except Exception as e: logger.error(f"Failed to send message with buttons: {str(e)}") return {"success": False, "error": str(e)} - tools/__init__.py:14-18 (registration)The register_all_tools function that orchestrates tool registration, calling register_interactive_tools(mcp, wa_client) at line 17 to register the send_message_with_buttons tool and other interactive tools.
def register_all_tools(mcp, wa_client): """Register all available tools with the MCP server.""" register_messaging_tools(mcp, wa_client) register_interactive_tools(mcp, wa_client) register_template_tools(mcp, wa_client)