Skip to main content
Glama

buy_phone_number

Destructive

Purchase phone numbers for AI voice agents. Configure webhooks for incoming calls, set labels, and choose from local, mobile, toll-free, or national types across 30+ countries. Requires searching available numbers first. Setup and monthly fees apply.

Instructions

Purchase a phone number. This costs money from your balance (setup fee + monthly). Use search_phone_numbers first to find available numbers.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
phone_numberYesThe phone number to purchase in E.164 format (e.g. +12125551234)
labelNoFriendly label for this number
webhook_urlNoWebhook URL for incoming call events
country_codeNoTwo-letter country code (default: US)
number_typeNoNumber type

Implementation Reference

  • The handler function for buy_phone_number tool. It constructs the request body from parameters and calls client.post() to purchase the phone number via the API.
    async (params) => {
      const body: Record<string, unknown> = { phone_number: params.phone_number };
      if (params.label) body.label = params.label;
      if (params.webhook_url) body.webhook_url = params.webhook_url;
      if (params.country_code) body.country_code = params.country_code;
      if (params.number_type) body.number_type = params.number_type;
      return callTool(() => client.post("/phone-numbers", body));
    }
  • Input schema validation for buy_phone_number using Zod. Defines phone_number (required), label, webhook_url, country_code, and number_type parameters with their descriptions and constraints.
    {
      description:
        "Purchase a phone number. This costs money from your balance (setup fee + monthly). " +
        "Use search_phone_numbers first to find available numbers.",
      inputSchema: {
        phone_number: z.string().describe("The phone number to purchase in E.164 format (e.g. +12125551234)"),
        label: z.string().optional().describe("Friendly label for this number"),
        webhook_url: z.string().url().optional().describe("Webhook URL for incoming call events"),
        country_code: z.string().length(2).optional().describe("Two-letter country code (default: US)"),
        number_type: z.enum(["local", "mobile", "toll_free", "national"]).optional().describe("Number type"),
      },
      annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
  • Registration of the buy_phone_number tool with the MCP server. Includes tool name, description, input schema, annotations, and the handler function.
    server.registerTool(
      "buy_phone_number",
      {
        description:
          "Purchase a phone number. This costs money from your balance (setup fee + monthly). " +
          "Use search_phone_numbers first to find available numbers.",
        inputSchema: {
          phone_number: z.string().describe("The phone number to purchase in E.164 format (e.g. +12125551234)"),
          label: z.string().optional().describe("Friendly label for this number"),
          webhook_url: z.string().url().optional().describe("Webhook URL for incoming call events"),
          country_code: z.string().length(2).optional().describe("Two-letter country code (default: US)"),
          number_type: z.enum(["local", "mobile", "toll_free", "national"]).optional().describe("Number type"),
        },
        annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
      },
      async (params) => {
        const body: Record<string, unknown> = { phone_number: params.phone_number };
        if (params.label) body.label = params.label;
        if (params.webhook_url) body.webhook_url = params.webhook_url;
        if (params.country_code) body.country_code = params.country_code;
        if (params.number_type) body.number_type = params.number_type;
        return callTool(() => client.post("/phone-numbers", body));
      }
    );
  • Helper function callTool that wraps async tool calls with error handling. Catches ApiError and returns formatted error responses, or returns JSON-stringified success results.
    async function callTool<T>(fn: () => Promise<T>) {
      try {
        return toolResult(await fn());
      } catch (err) {
        const apiErr = err as ApiError;
        return toolError(`API error (${apiErr.status}): ${apiErr.message}`);
      }
    }
Behavior4/5

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

Adds crucial cost structure details ('setup fee + monthly') beyond the annotations' destructiveHint=true, helping the agent understand the financial commitment. Does not contradict annotations (destructiveHint aligns with 'costs money'). Minor gap: doesn't clarify failure modes or whether purchase is reversible.

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?

Three sentences with zero waste: action declaration, cost warning, and prerequisite instruction. Information is front-loaded and each sentence earns its place.

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 financial transaction tool with no output schema, the description adequately covers the workflow (search first), cost structure, and side effects. Slight gap: doesn't describe what the tool returns on success or specific error conditions (e.g., number already purchased).

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 description coverage is 100%, so the baseline is 3. The description doesn't add parameter-specific guidance (e.g., webhook behavior, number_type implications) but the schema is self-sufficient. No additional semantic context provided beyond the 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 opens with the specific verb 'Purchase' and clear resource 'phone number', immediately distinguishing this from sibling tools like search_phone_numbers (finding) or get_phone_number (retrieving). It establishes the commercial nature of the operation up front.

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

Usage Guidelines5/5

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

Explicitly states the prerequisite workflow ('Use search_phone_numbers first to find available numbers') and warns about financial implications ('costs money from your balance'), giving the agent clear signals on when to invoke this versus the search tool and when to avoid it (insufficient balance).

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/JobXDubai/mcp-server'

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