get_phone_number
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
| Name | Required | Description | Default |
|---|---|---|---|
| phone_number_id | Yes | The phone number ID |
Implementation Reference
- src/tools/phone-numbers.ts:86-96 (handler)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}`)) ); - src/tools/phone-numbers.ts:89-94 (schema)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 }, }, - src/tools/phone-numbers.ts:22-96 (registration)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}`)) ); - src/tools/phone-numbers.ts:13-20 (helper)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}`); } } - src/client.ts:12-80 (helper)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; } }