Skip to main content
Glama

vora_call

Make outbound phone calls with an autonomous voice agent that handles greetings, pitches, objections, and closing, returning structured results. Provide lead context for better conversations and receive outcomes via callback or polling.

Instructions

Make an outbound phone call using your voice agent. Your agent handles the entire conversation autonomously — greeting, pitch, objection handling, qualification, closing — and returns a structured outcome.

Calls typically take 1-5 minutes. You can poll vora_calls for the result or provide a callback_url for async delivery.

The more lead_context you provide, the better the conversation. Tell Vora everything you know about who it's calling.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
agent_idYesYour voice agent ID from vora_create_agent.
phoneYesPhone number in E.164 format. E.g., +15551234567, +971501234567, +919876543210.
lead_contextNoEverything you know about this lead. Name, title, company, size, how you found them, previous interactions, interests. Free-form text — the more the better.
specific_objectiveNoOverride or refine the agent's default objective for this call. E.g., 'They downloaded our pricing PDF yesterday — focus on closing, not educating.'
callback_urlNoWebhook URL for async result delivery. Vora POSTs the full call result when complete. If omitted, poll vora_calls with the call_id.

Implementation Reference

  • The main handler function for the 'vora_call' tool. Registers the tool with server.tool(), makes a POST /v1/agent-api/calls API call, handles async (dialing/ringing/in_progress) and synchronous (complete/failed) responses, and formats the result.
    export function registerVoraCall(server: McpServer): void {
      server.tool(
        "vora_call",
        `Make an outbound phone call using your voice agent. Your agent handles the entire conversation autonomously — greeting, pitch, objection handling, qualification, closing — and returns a structured outcome.
    
    Calls typically take 1-5 minutes. You can poll vora_calls for the result or provide a callback_url for async delivery.
    
    The more lead_context you provide, the better the conversation. Tell Vora everything you know about who it's calling.`,
        {
          agent_id: z
            .string()
            .describe("Your voice agent ID from vora_create_agent."),
          phone: z
            .string()
            .describe(
              "Phone number in E.164 format. E.g., +15551234567, +971501234567, +919876543210."
            ),
          lead_context: z
            .string()
            .optional()
            .describe(
              "Everything you know about this lead. Name, title, company, size, how you found them, previous interactions, interests. Free-form text — the more the better."
            ),
          specific_objective: z
            .string()
            .optional()
            .describe(
              "Override or refine the agent's default objective for this call. E.g., 'They downloaded our pricing PDF yesterday — focus on closing, not educating.'"
            ),
          callback_url: z
            .string()
            .optional()
            .describe(
              "Webhook URL for async result delivery. Vora POSTs the full call result when complete. If omitted, poll vora_calls with the call_id."
            ),
        },
        async (params) => {
          const client = getApiClient();
    
          try {
            const response = await client.post<CallResponse>(
              "/v1/agent-api/calls",
              {
                agent_id: params.agent_id,
                phone: params.phone,
                lead_context: params.lead_context,
                specific_objective: params.specific_objective,
                callback_url: params.callback_url,
              }
            );
    
            // Call is still in progress (async)
            if (
              response.status === "dialing" ||
              response.status === "ringing" ||
              response.status === "in_progress"
            ) {
              return {
                content: [
                  {
                    type: "text" as const,
                    text: `Call initiated!\n\nCall ID: ${response.call_id}\nStatus: ${response.status}\nEstimated duration: ${response.estimated_duration || "2-4 minutes"}\n\nPoll vora_calls({ call_id: "${response.call_id}" }) for the result.${params.callback_url ? `\nResult will also be sent to: ${params.callback_url}` : ""}`,
                  },
                ],
              };
            }
    
            // Call completed synchronously (short call or error)
            return formatCallResult(response);
          } catch (error) {
            return {
              content: [
                {
                  type: "text" as const,
                  text: `Call error: ${error instanceof Error ? error.message : String(error)}`,
                },
              ],
              isError: true,
            };
          }
        }
      );
  • Zod schema defining input parameters: agent_id (required string), phone (required E.164 string), lead_context (optional string), specific_objective (optional string), callback_url (optional webhook URL string).
    {
      agent_id: z
        .string()
        .describe("Your voice agent ID from vora_create_agent."),
      phone: z
        .string()
        .describe(
          "Phone number in E.164 format. E.g., +15551234567, +971501234567, +919876543210."
        ),
      lead_context: z
        .string()
        .optional()
        .describe(
          "Everything you know about this lead. Name, title, company, size, how you found them, previous interactions, interests. Free-form text — the more the better."
        ),
      specific_objective: z
        .string()
        .optional()
        .describe(
          "Override or refine the agent's default objective for this call. E.g., 'They downloaded our pricing PDF yesterday — focus on closing, not educating.'"
        ),
      callback_url: z
        .string()
        .optional()
        .describe(
          "Webhook URL for async result delivery. Vora POSTs the full call result when complete. If omitted, poll vora_calls with the call_id."
        ),
    },
  • Registration of the vora_call tool by calling registerVoraCall(server) within the centralized registerTools function.
    export function registerTools(server: McpServer): void {
      registerVoraRegister(server);
      registerVoraCreateAgent(server);
      registerVoraCall(server);
      registerVoraCalls(server);
      registerVoraUpdateAgent(server);
  • formatCallResult helper function that formats the CallResponse into a readable text output with call status, duration, outcome, lead score, sentiment, next steps, cost, transcript/recording URLs, and learnings.
    function formatCallResult(response: CallResponse) {
      const lines: string[] = [
        `Call ${response.call_id} — ${response.status}`,
        `Duration: ${response.duration_seconds}s`,
        `Outcome: ${response.outcome}`,
      ];
    
      if (response.outcome_details) {
        const d = response.outcome_details;
        lines.push(`Lead Score: ${d.lead_score}/100`);
        lines.push(`Interested: ${d.interested}`);
        lines.push(`Sentiment: ${d.sentiment}`);
        lines.push(`Next Step: ${d.next_step}`);
        if (d.meeting_time) lines.push(`Meeting Booked: ${d.meeting_time}`);
        if (d.objections_raised.length > 0)
          lines.push(`Objections: ${d.objections_raised.join(", ")}`);
      }
    
      if (response.cost_usdc) lines.push(`Cost: ${response.cost_usdc} USDC`);
      if (response.transcript_url)
        lines.push(`Transcript: ${response.transcript_url}`);
      if (response.recording_url)
        lines.push(`Recording: ${response.recording_url}`);
    
      if (response.learnings && response.learnings.length > 0) {
        lines.push(`\nLearnings:`);
        response.learnings.forEach((l) => lines.push(`  - ${l}`));
      }
    
      return {
        content: [{ type: "text" as const, text: lines.join("\n") }],
      };
    }
  • CallResponse TypeScript interface defining the shape of the API response: call_id, status enum, duration_seconds, outcome, outcome_details (with lead scoring), transcript_url, recording_url, cost_usdc, learnings, and estimated_duration.
    interface CallResponse {
      call_id: string;
      status: "dialing" | "ringing" | "in_progress" | "completed" | "failed" | "no_answer" | "voicemail";
      duration_seconds?: number;
      outcome?: string;
      outcome_details?: {
        interested: boolean;
        budget_confirmed?: boolean;
        decision_maker?: boolean;
        next_step: string;
        meeting_time?: string;
        objections_raised: string[];
        sentiment: string;
        lead_score: number;
      };
      transcript_url?: string;
      recording_url?: string;
      cost_usdc?: string;
      learnings?: string[];
      estimated_duration?: string;
    }
Behavior3/5

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

No annotations provided, so description carries full burden. It describes autonomous conversation, structured outcome, and async delivery, but does not disclose side effects, rate limits, cost, or auth requirements beyond the schema.

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 concise paragraphs, front-loaded with the main action. Every sentence adds value, with no fluff or redundancy.

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?

Fairly complete for a call initiation tool: covers async behavior, input hints, and duration. Missing detailed return value structure (no output schema), but mentions 'structured outcome' implicitly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the description adds value by explaining the role of lead_context ('Tell Vora everything you know') and specific_objective as a refinement. Does not redundantly repeat schema details.

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 verb 'Make an outbound phone call using your voice agent,' specifying the resource (phone call) and distinguishing it from siblings like vora_calls and vora_create_agent.

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

Usage Guidelines4/5

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

Provides guidance on call duration (1-5 minutes), two methods for result retrieval (polling vora_calls vs. callback_url), and emphasizes providing lead_context. Lacks explicit when-not-to-use or alternatives to other tools.

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/stefanstojanovicstefa-creator/vora-voice-mcp'

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