Skip to main content
Glama

get_phone_number

Read-onlyIdempotent

Retrieve configuration details and AI agent settings for a specific phone number by ID. Access voice agent assignments, routing rules, and telephony data to manage communications.

Instructions

Get details and AI agent configuration for a phone number.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
phone_number_idYesThe phone number ID

Implementation Reference

  • The handler function for 'get_phone_number' tool. It receives params with phone_number_id, calls the API via client.get(), and returns the phone number details and AI agent configuration.
    server.registerTool(
      "get_phone_number",
      {
        description: "Get details and AI agent configuration for a phone number.",
        inputSchema: {
          phone_number_id: z.string().describe("The phone number ID"),
        },
        annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
      },
      async (params) => callTool(() => client.get(`/phone-numbers/${params.phone_number_id}`))
    );
  • Input schema definition for 'get_phone_number' using Zod. Validates that phone_number_id is a required string.
      description: "Get details and AI agent configuration for a phone number.",
      inputSchema: {
        phone_number_id: z.string().describe("The phone number ID"),
      },
      annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
    },
  • Registration function 'registerPhoneNumberTools' that registers all phone number tools including 'get_phone_number' with the MCP server. Includes tool metadata like description, input schema, and behavior annotations.
    export function registerPhoneNumberTools(server: McpServer, client: BubblyPhoneClient) {
      server.registerTool(
        "search_phone_numbers",
        {
          description:
            "Search for available phone numbers to purchase. Filter by country, area code, or locality. " +
            "Returns numbers with pricing information.",
          inputSchema: {
            country_code: z.string().length(2).optional().describe("Two-letter country code (default: US)"),
            area_code: z.string().optional().describe("Area code to filter by"),
            locality: z.string().optional().describe("City or locality name"),
            number_type: z.enum(["local", "mobile", "toll_free", "national"]).optional().describe("Type of number (default: local)"),
            contains: z.string().optional().describe("Search for numbers containing this string"),
            limit: z.number().min(1).max(50).optional().describe("Max results (default: 20, max: 50)"),
          },
          annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
        },
        async (params) => {
          const query: Record<string, string> = {};
          if (params.country_code) query.country = params.country_code;
          if (params.area_code) query.area_code = params.area_code;
          if (params.locality) query.locality = params.locality;
          if (params.number_type) query.number_type = params.number_type;
          if (params.contains) query.contains = params.contains;
          if (params.limit) query.limit = String(params.limit);
          return callTool(() => client.get("/phone-numbers/available", query));
        }
      );
    
      server.registerTool(
        "list_phone_numbers",
        {
          description: "List your owned phone numbers with their status and configuration.",
          inputSchema: {},
          annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
        },
        async () => callTool(() => client.get("/phone-numbers"))
      );
    
      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));
        }
      );
    
      server.registerTool(
        "get_phone_number",
        {
          description: "Get details and AI agent configuration for a phone number.",
          inputSchema: {
            phone_number_id: z.string().describe("The phone number ID"),
          },
          annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
        },
        async (params) => callTool(() => client.get(`/phone-numbers/${params.phone_number_id}`))
      );
  • Helper function 'callTool' that wraps API calls with error handling. Catches ApiError exceptions and returns formatted error responses or successful tool 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}`);
      }
    }
  • BubblyPhoneClient class providing HTTP methods (get, post, patch, delete) with authentication. The get() method is used by get_phone_number handler to fetch phone number details from the API.
    export class BubblyPhoneClient {
      private apiKey: string;
      private baseUrl: string;
    
      constructor(options: ApiClientOptions) {
        this.apiKey = options.apiKey;
        this.baseUrl = options.baseUrl ?? "https://agents.bubblyphone.com/api/v1";
      }
    
      async get<T = unknown>(path: string, params?: Record<string, string>): Promise<T> {
        const url = new URL(`${this.baseUrl}${path}`);
        if (params) {
          for (const [key, value] of Object.entries(params)) {
            if (value !== undefined && value !== "") {
              url.searchParams.set(key, value);
            }
          }
        }
        return this.request<T>(url.toString(), { method: "GET" });
      }
    
      async post<T = unknown>(path: string, body?: Record<string, unknown>): Promise<T> {
        return this.request<T>(`${this.baseUrl}${path}`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: body ? JSON.stringify(body) : undefined,
        });
      }
    
      async patch<T = unknown>(path: string, body: Record<string, unknown>): Promise<T> {
        return this.request<T>(`${this.baseUrl}${path}`, {
          method: "PATCH",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(body),
        });
      }
    
      async delete<T = unknown>(path: string): Promise<T> {
        return this.request<T>(`${this.baseUrl}${path}`, { method: "DELETE" });
      }
    
      private async request<T>(url: string, init: RequestInit): Promise<T> {
        const response = await fetch(url, {
          ...init,
          headers: {
            ...init.headers as Record<string, string>,
            Authorization: `Bearer ${this.apiKey}`,
            Accept: "application/json",
          },
        });
    
        if (!response.ok) {
          const text = await response.text();
          let message: string;
          try {
            const json = JSON.parse(text);
            message = json.message ?? json.error ?? text;
          } catch {
            message = text;
          }
          const error: ApiError = { status: response.status, message };
          throw error;
        }
    
        const text = await response.text();
        if (!text) return undefined as T;
        return JSON.parse(text) as T;
      }
    }
Behavior3/5

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

Annotations already declare readOnlyHint=true and idempotentHint=true, establishing the safety profile. The description adds valuable scope context by specifying 'AI agent configuration' as part of the retrieved data, which explains the specific nature of the details returned. However, it omits additional behavioral traits like response format or caching behavior.

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 a single, efficient sentence with the action front-loaded. While 'details' is slightly generic, the addition of 'AI agent configuration' provides necessary specificity. No redundant or wasted words.

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

Completeness3/5

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

Given the low complexity (single string parameter) and strong annotation coverage, the description adequately explains the retrieval scope. However, with no output schema provided, the description could better specify the structure or content of the returned details beyond mentioning 'AI agent configuration'.

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?

With 100% schema description coverage, the schema fully documents the phone_number_id parameter. The description adds no explicit parameter guidance, meeting the baseline expectation for high-coverage schemas. No additional syntax or format details are provided.

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 uses specific verb 'Get' with clear resource scope ('details and AI agent configuration for a phone number'). It effectively distinguishes from siblings: vs list_phone_numbers (single retrieval vs list), vs buy_phone_number (retrieval vs acquisition), vs get_call (phone config vs call instance), and vs update_phone_number (read vs write).

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 states what the tool retrieves but provides no explicit guidance on when to use it versus alternatives like list_phone_numbers or search_phone_numbers. There are no 'when-not-to-use' exclusions or prerequisites 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/JobXDubai/mcp-server'

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