Skip to main content
Glama
Jem-HR
by Jem-HR

send_message_with_list

Send WhatsApp messages with interactive selection lists to present options, gather responses, and organize information in structured sections.

Instructions

Send a message with a selection list.

CONSTRAINTS:

  • Maximum 10 sections per list

  • Maximum 10 rows total across all sections

  • Button text: max 20 characters

  • Section title: max 24 characters

  • Row title: max 24 characters

  • Row description: max 72 characters

  • Row ID (callback_data): max 200 characters

  • Header text: max 60 characters (if provided)

  • Footer text: max 60 characters (if provided)

EXAMPLE: { "to": "+1234567890", "text": "Choose from our menu:", "button_text": "View Menu", "sections": [ { "title": "Main Courses", "rows": [ {"id": "burger", "title": "Burger", "description": "Beef burger with fries"}, {"id": "pizza", "title": "Pizza", "description": "Margherita pizza"} ] }, { "title": "Beverages", "rows": [ {"id": "coke", "title": "Coca Cola", "description": "Cold refreshing drink"}, {"id": "water", "title": "Water", "description": "Still or sparkling"} ] } ], "header": "Restaurant Menu", "footer": "All items available today" }

Args: to: Phone number (with country code) or WhatsApp ID
text: Message body text (main message content) button_text: Text shown on the list button (triggers the list) sections: List of sections, each with 'title' and 'rows' arrays header: Optional header text (appears above main text) footer: Optional footer text (appears below list button) reply_to_message_id: Message ID to reply to

Returns: Dictionary with success status and message ID

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
toYes
textYes
button_textYes
sectionsYes
headerNo
footerNo
reply_to_message_idNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The main implementation of send_message_with_list function that sends WhatsApp messages with interactive list sections. It includes comprehensive validation for all WhatsApp list constraints (max 10 sections, 10 rows total, character limits for titles, descriptions, etc.), constructs SectionList objects using PyWA library types, and sends the message via wa_client.send_message().
    async def send_message_with_list(
        to: str,
        text: str,
        button_text: str,
        sections: List[Dict[str, Any]],
        header: Optional[str] = None,
        footer: Optional[str] = None,
        *,
        reply_to_message_id: Optional[str] = None,
    ) -> dict:
        """
        Send a message with a selection list.
        
        CONSTRAINTS:
        - Maximum 10 sections per list
        - Maximum 10 rows total across all sections
        - Button text: max 20 characters
        - Section title: max 24 characters
        - Row title: max 24 characters  
        - Row description: max 72 characters
        - Row ID (callback_data): max 200 characters
        - Header text: max 60 characters (if provided)
        - Footer text: max 60 characters (if provided)
        
        EXAMPLE:
        {
          "to": "+1234567890",
          "text": "Choose from our menu:",
          "button_text": "View Menu",
          "sections": [
            {
              "title": "Main Courses",
              "rows": [
                {"id": "burger", "title": "Burger", "description": "Beef burger with fries"},
                {"id": "pizza", "title": "Pizza", "description": "Margherita pizza"}
              ]
            },
            {
              "title": "Beverages", 
              "rows": [
                {"id": "coke", "title": "Coca Cola", "description": "Cold refreshing drink"},
                {"id": "water", "title": "Water", "description": "Still or sparkling"}
              ]
            }
          ],
          "header": "Restaurant Menu",
          "footer": "All items available today"
        }
        
        Args:
            to: Phone number (with country code) or WhatsApp ID  
            text: Message body text (main message content)
            button_text: Text shown on the list button (triggers the list)
            sections: List of sections, each with 'title' and 'rows' arrays
            header: Optional header text (appears above main text)
            footer: Optional footer text (appears below list button)
            reply_to_message_id: Message ID to reply to
        
        Returns:
            Dictionary with success status and message ID
        """
        try:
            # Validate constraints
            if len(sections) > 10:
                return {"success": False, "error": "Maximum 10 sections allowed"}
                
            if len(button_text) > 20:
                return {"success": False, "error": "Button text must be max 20 characters"}
                
            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"}
            
            # Count total rows across all sections
            total_row_count = sum(len(section.get("rows", [])) for section in sections)
            if total_row_count > 10:
                return {"success": False, "error": "Maximum 10 rows total across all sections"}
            
            # Convert sections to PyWA Section objects
            section_objects = []
            
            for section_data in sections:
                if "rows" not in section_data:
                    return {"success": False, "error": "Each section must have a 'rows' array"}
                
                section_title = section_data.get("title", "")
                if len(section_title) > 24:
                    return {"success": False, "error": f"Section title '{section_title}' exceeds 24 characters"}
                
                rows = []
                for row_data in section_data["rows"]:
                    # Validate required fields
                    if "id" not in row_data or "title" not in row_data:
                        return {"success": False, "error": "Each row must have 'id' and 'title' keys"}
                    
                    # Validate constraints
                    if len(row_data["id"]) > 200:
                        return {"success": False, "error": f"Row ID '{row_data['id']}' exceeds 200 characters"}
                        
                    if len(row_data["title"]) > 24:
                        return {"success": False, "error": f"Row title '{row_data['title']}' exceeds 24 characters"}
                    
                    description = row_data.get("description", "")
                    if len(description) > 72:
                        return {"success": False, "error": f"Row description '{description}' exceeds 72 characters"}
                    
                    rows.append(SectionRow(
                        title=row_data["title"],
                        callback_data=row_data["id"],
                        description=description if description else None
                    ))
                
                if rows:  # Only add section if it has rows
                    section_objects.append(Section(
                        title=section_title,
                        rows=rows
                    ))
            
            # Create SectionList
            section_list = SectionList(
                button_title=button_text,
                sections=section_objects
            )
            
            result = wa_client.send_message(
                to=to,
                text=text,
                buttons=section_list,
                header=header,
                footer=footer,
                reply_to_message_id=reply_to_message_id,
            )
            
            logger.info(f"Message with list 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 list: {str(e)}")
            return {"success": False, "error": str(e)}
  • The @mcp.tool() decorator that registers the send_message_with_list function as an MCP tool, making it available for use through the Model Context Protocol.
    @mcp.tool()
  • The register_interactive_tools function that contains the send_message_with_list tool definition and registers it with the MCP server instance.
    def register_interactive_tools(mcp, wa_client: WhatsApp):
        """Register interactive messaging tools."""
  • Function signature and type definitions for send_message_with_list, defining the input parameters including required fields (to, text, button_text, sections) and optional fields (header, footer, reply_to_message_id) with their types.
    async def send_message_with_list(
        to: str,
        text: str,
        button_text: str,
        sections: List[Dict[str, Any]],
        header: Optional[str] = None,
        footer: Optional[str] = None,
        *,
  • Import of PyWA types (SectionList, Section, SectionRow) used within the send_message_with_list function to construct the interactive list structure.
    from pywa.types import Button, SectionList, Section, SectionRow
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively describes key behavioral traits: it's a sending operation (implies mutation/creation), includes detailed constraints (e.g., max sections, character limits), provides a comprehensive example showing the structure, and specifies the return format. However, it doesn't mention potential side effects like rate limits or authentication needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with clear sections (CONSTRAINTS, EXAMPLE, Args, Returns) and front-loaded purpose. However, it's somewhat lengthy due to the detailed example and constraints list. Every sentence adds value, but it could be more concise by integrating constraints into the Args section more tightly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (7 parameters, nested structures in sections), no annotations, and an output schema (Returns section), the description is largely complete. It covers purpose, constraints, example usage, parameter details, and return values. The main gap is the lack of usage guidelines compared to sibling tools, but it compensates well with detailed behavioral and parameter information.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must fully compensate. It provides extensive parameter semantics: detailed constraints for each field (e.g., 'Button text: max 20 characters'), clear explanations in the example and Args section (e.g., 'to: Phone number (with country code) or WhatsApp ID'), and distinguishes required vs. optional parameters. This goes well beyond what the bare schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Send a message with a selection list.' It specifies the exact action (send) and resource (message with selection list), distinguishing it from sibling tools like send_message or send_message_with_buttons. The title is null, so the description fully carries this burden.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives like send_message or send_message_with_buttons. It lists constraints and an example but doesn't explain the appropriate context or prerequisites for sending a selection list versus other message types.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jem-HR/pywa-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server