Skip to main content
Glama
nasoma

Africa's Talking Airtime MCP

load_airtime

Send airtime to phone numbers using Africa's Talking API, format numbers correctly, and log transactions in a database for record-keeping.

Instructions

Sends airtime to a specified phone number and logs the transaction.

This tool formats the phone number, sends the airtime using the
Africa's Talking API, and saves a record of the transaction in the
database.

Args:
    phone_number (str): The recipient's phone number.
    amount (float): The amount of airtime to send.
    currency_code (str): The currency for the transaction (e.g., "KES").

Returns:
    str: A message indicating the status of the airtime transaction.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
phone_numberYes
amountYes
currency_codeYes

Implementation Reference

  • main.py:143-171 (handler)
    The main handler function for the 'load_airtime' tool, decorated with @mcp.tool() for registration. It formats the recipient's phone number, sends airtime using the Africa's Talking API, logs the transaction to a SQLite database, and returns a status message.
    @mcp.tool()
    async def load_airtime(phone_number: str, amount: float, currency_code: str) -> str:
        """Sends airtime to a specified phone number and logs the transaction.
    
        This tool formats the phone number, sends the airtime using the
        Africa's Talking API, and saves a record of the transaction in the
        database.
    
        Args:
            phone_number (str): The recipient's phone number.
            amount (float): The amount of airtime to send.
            currency_code (str): The currency for the transaction (e.g., "KES").
    
        Returns:
            str: A message indicating the status of the airtime transaction.
        """
        try:
            formatted_number = format_phone_number(phone_number)
            airtime.send(
                phone_number=formatted_number, amount=amount, currency_code=currency_code
            )
    
            save_transaction(formatted_number, amount, currency_code)
            return (
                f"Successfully sent {currency_code} {amount} airtime to {formatted_number}"
            )
    
        except Exception as e:
            return f"Encountered an error while sending airtime: {str(e)}"
  • main.py:68-98 (helper)
    Helper function used by load_airtime to format the phone number with the appropriate international country code based on the configured country.
    def format_phone_number(phone_number):
        """Formats a phone number to include the international country code.
    
        This function takes a phone number as a string and formats it based on
        the user's country, which is determined by the `user_country` global
        variable. It handles numbers that start with '0', '+', or a digit.
    
        Args:
            phone_number (str): The phone number to be formatted.
    
        Returns:
            str: The phone number with the country code prepended.
    
        Raises:
            ValueError: If the `user_country` is not in the `COUNTRY_CODES` map.
        """
        phone_number = str(phone_number).strip()
    
        if user_country not in COUNTRY_CODES:
            raise ValueError(
                f"Invalid or unset country: {user_country}. Supported countries: {list(COUNTRY_CODES.keys())}"
            )
    
        country_code = COUNTRY_CODES[user_country]
    
        if phone_number.startswith("0"):
            return country_code + phone_number[1:]
        elif phone_number.startswith("+"):
            return phone_number
        else:
            return country_code + phone_number
  • Helper function used by load_airtime to persist the transaction details into the SQLite database.
    def save_transaction(phone_number, amount, currency_code):
        """Saves a single airtime transaction to the SQLite database.
    
        Args:
            phone_number (str): The recipient's phone number.
            amount (float): The amount of airtime sent.
            currency_code (str): The currency of the transaction (e.g., "KES").
        """
        with sqlite3.connect(DB_PATH) as conn:
            cursor = conn.cursor()
            cursor.execute(
                """
                INSERT INTO transactions (phone_number, amount, currency_code, transaction_time)
                VALUES (?, ?, ?, ?)
                """,
                (phone_number, amount, currency_code, datetime.now()),
            )
            conn.commit()
Behavior3/5

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

With no annotations provided, the description carries full burden. It discloses key behaviors: formatting phone numbers, using Africa's Talking API, and logging to a database. However, it lacks details on error handling, rate limits, authentication needs, or what specific data is logged.

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

Conciseness5/5

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

The description is well-structured and front-loaded with the core purpose in the first sentence. Each subsequent sentence adds necessary detail without redundancy. The Args/Returns sections are clearly formatted and efficiently convey parameter and return value 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?

For a mutation tool with no annotations and no output schema, the description does a good job covering purpose, parameters, and basic behavior. However, it lacks details about the return message format, error conditions, or database logging specifics that would be helpful for an agent.

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 compensate. It provides clear semantic meaning for all three parameters: phone_number identifies the recipient, amount specifies airtime quantity, and currency_code defines transaction currency with an example ('KES'). This adds significant value beyond the bare schema.

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 with specific verbs ('sends airtime', 'logs the transaction') and identifies the resource (phone number). It distinguishes from sibling tools like check_balance or get_last_topups by focusing on sending rather than querying.

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?

The description implies usage for sending airtime via Africa's Talking API, but provides no explicit guidance on when to use this tool versus alternatives like count_topups_by_number or sum_last_n_topups. No prerequisites, exclusions, or comparison to siblings are mentioned.

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/nasoma/africastalking-airtime-mcp'

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