Skip to main content
Glama
BulkClix MCP Server

BulkClix MCP Server

Ananse MCP Server (Python FastMCP)

A Python-based MCP (Model Context Protocol) server that gives AI agents (LibreChat, Claude Desktop, Cursor, etc.) full access to ghanaian platforms via natural language.

Developed with FastMCP for simple tool declarations.


Features

  • Food & Catalog Ordering: Search food menus across Accra/Bolt Food catalog, place merchant orders via SMS, collect MoMo payments.

  • MongoDB Order Tracking: Save user profiles, delivery addresses, and track live order lifecycle states (PENDING, CONFIRMED, IN_TRANSIT, DELIVERED).

  • SMS: Send bulk SMS, fetch campaign reports, request/list Sender IDs.

  • OTP: Send and verify OTPs via SMS and Email.

  • Airtime: List networks, purchase airtime via momo, and send airtime from wallet balance.

  • Mobile Money: MoMo payment collections, status checks, disbursements.

  • Bank Transfer: Disburse to bank accounts, list banks.

  • Data Bundles: Fetch bundles, purchase data packages.

  • KYC: MSISDN owner name lookups.

  • Contacts: Full CRUD for contact groups & contacts.

  • Account: Check wallet balance.


Related MCP server: AgentPhone MCP Server

Installation & Running

Run the server along with the mini MongoDB instance for tracking orders and storing user profiles:

docker-compose up -d

Option 2: Standalone via uv

Using uv is highly recommended as it automatically manages dependencies:

# Run server using uv
uv run server.py

If you want the server to use a default BulkClix key, set BULKCLIX_API_KEY before starting it:

export BULKCLIX_API_KEY="your-bulkclix-api-key"
uv run server.py mcp

To expose admin-only workflows like contact management, enable internal tools on the server:

export BULKCLIX_ENABLE_INTERNAL_TOOLS=true

The public chat-facing tools now work without caller-supplied keys. SMS and OTP tools automatically pick the first sender ID returned by BulkClix. Airtime and data purchases first collect payment through MoMo, then complete the fulfillment after payment is confirmed.


Configuration in LibreChat

Option 1: stdio transport (default)

Add this under mcpServers in your librechat.yaml:

mcpServers:
  ananse:
    command: uv
    args:
      - run
      - --directory
      - /path/to/ananse-mcp
      - server.py
    type: stdio

Option 2: HTTP / MCP transport (Remote/Streamable)

Run the server on a port (e.g. port 8000):

cd ananse-mcp
uv run server.py mcp

Then configure LibreChat to use the MCP-over-HTTP endpoint:

mcpServers:
  bulkclix:
    url: http://localhost:8000/
    type: sse

You can then tunnel that port with localtunnel:

npx localtunnel --port 8000

If BULKCLIX_API_KEY is set on the machine running the server, the client can use the public tools without providing any per-call key. Admin-only tools are hidden unless BULKCLIX_ENABLE_INTERNAL_TOOLS=true is set on the server.


License

This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License (CC BY-NC-ND 4.0). See the LICENSE file for details.

Available Tools

25 tools
airtime_get_networksA
Read-only

Get supported networks for airtime top-up.

Inputs: no named parameters. Returns: object

airtime_purchaseC

Start an airtime purchase using the BulkClix purchase route. :param destination: Recipient phone number receiving the airtime. :param phone_number: MoMo phone number being charged for payment. :param network: Payer network code (e.g., 'MTN', 'VDF', 'ATL'). :param amount: Airtime purchase amount in GHS. :param network_id: Network UUID from airtime_get_networks. :param payment_type: Payment type (usually 'momo').

Inputs: amount (required), network (required), network_id (required), destination (required), +8 more. Returns: object

create_verified_vendors_orderA

Place an order with a food/goods vendor and initiate mobile money payment via BulkClix. IMPORTANT: Before calling this tool you MUST have collected ALL required fields from the user: (1) if order_type='inhouse' — you MUST ask the user for their table_number first; (2) if order_type='delivery' — you MUST ask the user for their delivery_address first. Do NOT call this tool without those values — the tool will fail. :param vendor_id: Vendor's UUID. :param items: List of items to order, with dish_id, quantity, and addon_ids. :param payment_number: Mobile money number to charge (e.g. '0544929180'). :param network: Mobile money network code (e.g. 'MTN'). :param order_type: 'inhouse' or 'delivery' — must be one of the vendor's supported order_types. :param table_number: Table number string. REQUIRED when order_type is 'inhouse' — ask the user before calling. :param delivery_address: Delivery address string. REQUIRED when order_type is 'delivery' — ask the user before calling. :returns: dict with success, order_id, payment status, and vendor confirmation.

Inputs: items (required), network (required), vendor_id (required), payment_number (required), +3 more. Returns: object

data_check_statusA
Read-only

Check the status of a data bundle payment or purchase by order ID.

Inputs: order_id (required), payment_id, transaction_id. Returns: object

data_get_bundlesC
Read-only

List available data bundle services.

Inputs: network_id. Returns: object

data_get_offersA
Read-only

List available data bundle offers for a service and phone number. :param service_id: Data service UUID. :param phone_number: Recipient phone number.

Inputs: service_id (required), phone_number (required). Returns: object

data_purchaseC

Start a data bundle purchase using the BulkClix purchase route.

Inputs: network (required), bundle_id (required), network_id (required), service_id (required), +8 more. Returns: object

find_food_itemsA
Read-only

Search for food items, dishes, pizza, rice, chicken, or menus across all verified vendors or a specific vendor. Use this when asking 'what food is available', 'show me the menu', 'do you have pizza', 'search menu for burger'.

Inputs: query (required), vendor_id. Returns: object

get_customer_profileA
Read-only

Retrieve a saved customer profile from MongoDB by phone number to get delivery address and payment preferences.

Inputs: phone_number (required). Returns: object

get_token_infoB
Read-only

Returns information about the Auth0 token.

Inputs: no named parameters. Returns: object

get_verified_vendorsA
Read-only

List available vendors to purchase goods from using BulkClix payment. :param vendor_id: Vendor's UUID. If given, returns just that vendor. :param category: Vendor's category of goods (e.g. 'restaurant', 'food', 'airtime'). If given, filters vendors using case-insensitive substring and synonym expansion.

Inputs: category, vendor_id. Returns: object

get_verified_vendors_menuA
Read-only

List available menu items for a vendor, flattened and checkout-ready — each item has dish_id, name, price, is_available, and addons. No nested categories. :param vendor_id: Vendor's UUID. :param query: Optional case-insensitive substring filter on dish name.

Inputs: vendor_id (required), query. Returns: object

list_vendor_categoriesA
Read-only

List all categories of goods (e.g. 'restaurant', 'food', 'airtime', 'data') supported by the verified vendors.

Inputs: no named parameters. Returns: object

momo_check_statusA
Read-only

Check the status of a Mobile Money collection or transaction. :param transaction_id: The transaction ID returned during collection. :param payment_id: Optional payment record ID if you already have it.

Inputs: transaction_id (required), payment_id. Returns: object

otp_send_emailA

Send an OTP (One-Time Password) via Email. CRITICAL: The message parameter MUST contain the exact placeholder <%otp_code%>. If this placeholder is missing, the API call will fail with a 422 error. :param email: Recipient email address. :param subject: Email subject. :param message: Email body containing <%otp_code%> template (e.g. 'Your verification code is: <%otp_code%>'). :param expiry: OTP validity duration in minutes (default 5). :param length: Digit length of the OTP (default 4).

Inputs: email (required), message (required), subject (required), expiry, +1 more. Returns: object

otp_send_smsA

Send an OTP (One-Time Password) via SMS. CRITICAL: The message parameter MUST contain the exact placeholder <%otp_code%>. If this placeholder is missing, the API call will fail with a 422 error. :param phone_number: Recipient phone number (e.g. '0541000000'). :param message: Message template containing <%otp_code%> (e.g. 'Your verification code is: <%otp_code%>'). :param expiry: OTP validity duration in minutes (default 5). :param length: Digit length of the OTP (default 4).

Inputs: message (required), phone_number (required), expiry, length. Returns: object

otp_verify_emailA

Verify an OTP code that was sent via Email. :param request_id: The requestId returned from sending the OTP. :param email: The email address the OTP was sent to. :param code: The verification code to verify.

Inputs: code (required), email (required), request_id (required). Returns: object

otp_verify_smsA

Verify an OTP code that was sent via SMS. :param request_id: The requestId returned from sending the OTP. :param phone_number: The phone number the OTP was sent to. :param code: The code input by the user to check.

Inputs: code (required), request_id (required), phone_number (required). Returns: object

pay_verify_otpA
Destructive

Verify a payment OTP after the customer reads the code from their phone and sends it in chat. CRITICAL: This is ONLY for validating payment-related transactions. The request_id MUST be the one returned in the response of a payment/purchase initiation tool (e.g., airtime_purchase, data_purchase, or momo_collect), NOT from otp_send_sms. Providing a standard SMS OTP request ID will result in a 404 Error. :param code: OTP code entered by the customer from their phone. :param request_id: Request ID returned from the payment/purchase initiation response. :param phone_number: The phone number used for the payment transaction.

Inputs: code (required), request_id (required), phone_number (required). Returns: object

place_merchant_orderA

Place a food order directly with a restaurant merchant. Creates an order record in MongoDB, triggers MoMo payment collection from customer, and sends an order SMS dispatch to the merchant.

Inputs: items (required), amount_ghc (required), customer_name (required), customer_phone (required), +4 more. Returns: object

save_customer_profileA

Save or update a customer profile in MongoDB, including delivery address, landmark, and default MoMo payment number.

Inputs: address (required), phone_number (required), customer_name (required), landmark, +1 more. Returns: object

search_food_menusB
Read-only

Search food dishes and restaurants across available catalogs in a specified city (e.g. Accra). Currently searches verified vendors matching categories or name.

Inputs: query (required), city. Returns: object

track_orderC

Track real-time status and delivery details of an order from MongoDB.

Inputs: order_id (required). Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.3/5.0

    Scored across 25 tools

    Disambiguation3/5

    Tools have distinct purposes overall, but there is overlap among search tools (find_food_items, search_food_menus, search) and between order placement tools (create_verified_vendors_order, place_merchant_order). Descriptions help differentiate, but an agent might still misselect.

    Naming Consistency4/5

    Most tools follow a verb_noun snake_case pattern (e.g., airtime_get_networks, data_purchase). However, there are minor deviations: 'pay_verify_otp' uses two verbs, and 'search' lacks a noun. Overall, the convention is fairly consistent.

    Tool Count3/5

    With 25 tools, the server covers multiple domains (airtime, data, food ordering, OTP, profiles, search). This is slightly heavy but not excessive given the scope. Some tools could be consolidated (e.g., merging similar search tools).

    Completeness4/5

    The tool surface supports core workflows: airtime/data top-up, food ordering with payment, OTP verification, and customer profiles. Missing update/delete operations for orders and profiles are minor gaps; no dead ends for main use cases.

    Maintenance

    ActivityNo data
    ResponsivenessSyncing

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Enables AI assistants to send SMS, manage contacts, verify numbers, and query campaigns via SMS Masivos platform using natural language.
      30
      255 npm
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Connects any MCP-compatible AI assistant to the MojaWave SMS Gateway, enabling sending SMS, checking credit balances, and managing bulk SMS jobs.
      10
      MIT