Skip to main content
Glama
ilhankilic

YaparAI MCP Server

by ilhankilic

bulk_message

Send a message to multiple customers at once by targeting specific IDs, tags, or platforms. Broadcast promotions, announcements, or updates via social platforms like Instagram, Facebook, or WhatsApp.

Instructions

Send a message to multiple customers at once.

Broadcast promotions, announcements, or updates to a list of customers via their respective social platforms. You can target by specific IDs, a customer tag, or a platform.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
messageYesMessage text to send
customer_idsNoList of specific customer IDs to message
tagNoSend to all customers with this tag (e.g., "vip", "returning")
platformNoSend only to customers from this platform
media_urlsNoOptional list of image/video URLs to attach
org_idNoOrganization ID (uses YAPARAI_ORG_ID env var if not provided)

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The bulk_message async function — the actual tool handler. It accepts a message, optional customer_ids, tag, platform, media_urls, and org_id. It builds a payload dict and delegates to client.crm_bulk_message().
    async def bulk_message(
        message: str,
        customer_ids: list[str] | None = None,
        tag: str | None = None,
        platform: Literal["instagram", "facebook", "whatsapp"] | None = None,
        media_urls: list[str] | None = None,
        org_id: str | None = None,
    ) -> dict:
        """
        Send a message to multiple customers at once.
    
        Broadcast promotions, announcements, or updates to a list of
        customers via their respective social platforms. You can target by
        specific IDs, a customer tag, or a platform.
    
        Args:
            message: Message text to send
            customer_ids: List of specific customer IDs to message
            tag: Send to all customers with this tag (e.g., "vip", "returning")
            platform: Send only to customers from this platform
            media_urls: Optional list of image/video URLs to attach
            org_id: Organization ID (uses YAPARAI_ORG_ID env var if not provided)
    
        Returns:
            Dict with sent count, failed count, and error details.
        """
        oid = resolve_org_id(org_id)
        client = YaparAIClient()
        payload: dict = {"message": message}
        if customer_ids:
            payload["customer_ids"] = customer_ids
        if tag:
            payload["tag"] = tag
        if platform:
            payload["platform"] = platform
        if media_urls:
            payload["media_urls"] = media_urls
        return await client.crm_bulk_message(oid, payload)
  • Import of bulk_message from yaparai.tools.crm into the server module.
    bulk_message,
  • Registration of bulk_message as an MCP tool via mcp.tool(bulk_message).
    mcp.tool(bulk_message)
  • The crm_bulk_message method on YaparAIClient that makes the actual HTTP POST request to /api/enterprise/orgs/{org_id}/crm/bulk-message.
    async def crm_bulk_message(self, org_id: str, payload: dict) -> dict:
        """Send bulk message to customers."""
        return await self._request(
            "POST", f"/api/enterprise/orgs/{org_id}/crm/bulk-message", json=payload
        )
  • Tests for bulk_message: test_bulk_message_by_ids (line 9), test_bulk_message_by_tag (line 21), and test_bulk_message_by_platform (line 33).
    from yaparai.tools.crm import bulk_message
    
    
    @pytest.mark.asyncio
    async def test_bulk_message_by_ids():
        with patch("yaparai.tools.crm.YaparAIClient") as M, \
             patch("yaparai.tools.crm.resolve_org_id", return_value="org1"):
            inst = M.return_value
            inst.crm_bulk_message = AsyncMock(return_value={"sent": 3, "failed": 0})
            await bulk_message(message="Hi!", customer_ids=["c1", "c2"])
            payload = inst.crm_bulk_message.call_args[0][1]
            assert payload["customer_ids"] == ["c1", "c2"]
            assert "tag" not in payload
    
    
    @pytest.mark.asyncio
    async def test_bulk_message_by_tag():
        with patch("yaparai.tools.crm.YaparAIClient") as M, \
             patch("yaparai.tools.crm.resolve_org_id", return_value="org1"):
            inst = M.return_value
            inst.crm_bulk_message = AsyncMock(return_value={"sent": 5, "failed": 0})
            await bulk_message(message="VIP offer!", tag="vip")
            payload = inst.crm_bulk_message.call_args[0][1]
            assert payload["tag"] == "vip"
            assert "customer_ids" not in payload
    
    
    @pytest.mark.asyncio
    async def test_bulk_message_by_platform():
        with patch("yaparai.tools.crm.YaparAIClient") as M, \
             patch("yaparai.tools.crm.resolve_org_id", return_value="org1"):
            inst = M.return_value
            inst.crm_bulk_message = AsyncMock(return_value={"sent": 2, "failed": 0})
            await bulk_message(message="promo", platform="instagram")
            payload = inst.crm_bulk_message.call_args[0][1]
            assert payload["platform"] == "instagram"
Behavior3/5

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

With no annotations, description should disclose behaviors like async execution, rate limits, or error handling. It only describes what the tool does, not its behavioral traits.

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?

Concise two-sentence description with a clear first sentence. Could be slightly more structured but no unnecessary information.

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 output schema exists and schema coverage is 100%, description is mostly complete for purpose and targeting. Missing behavioral details are notable but not critical for basic usage.

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

Parameters3/5

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

Schema has 100% description coverage, so baseline is 3. Description reiterates targeting options but does not add significant meaning beyond schema. It mentions media_urls but no extra nuance.

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?

Description clearly states the tool sends messages to multiple customers at once, with use cases (promotions, announcements) and targeting methods (IDs, tag, platform). Distinguishes well from siblings like reply_to_message and send_shipping_info.

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

Usage Guidelines3/5

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

Description gives general usage scenarios but lacks explicit guidance on when not to use or comparison with alternatives. It does not mention that sending to specific IDs vs tag vs platform are mutually exclusive or how they interact.

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/ilhankilic/yaparai-mcp'

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