|
| 1 | +#!/usr/bin/env node |
| 2 | + |
| 3 | +import { Client } from '@modelcontextprotocol/sdk/client/index.js'; |
| 4 | +import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'; |
| 5 | +import dotenv from 'dotenv'; |
| 6 | +import { parseToolResponse } from '../src/utils/response.js'; |
| 7 | + |
| 8 | +// Load environment variables from .env file |
| 9 | +dotenv.config(); |
| 10 | + |
| 11 | +// Ensure API key is available |
| 12 | +if (!process.env.VAPI_TOKEN) { |
| 13 | + console.error('Error: VAPI_TOKEN environment variable is required'); |
| 14 | + process.exit(1); |
| 15 | +} |
| 16 | + |
| 17 | +async function main() { |
| 18 | + try { |
| 19 | + // Initialize MCP client |
| 20 | + const mcpClient = new Client({ |
| 21 | + name: 'vapi-client-example', |
| 22 | + version: '1.0.0', |
| 23 | + }); |
| 24 | + |
| 25 | + // Create SSE transport for connection to remote Vapi MCP server |
| 26 | + const serverUrl = 'https://mcp.vapi.ai/sse'; |
| 27 | + const headers = { |
| 28 | + Authorization: `Bearer ${process.env.VAPI_TOKEN}`, |
| 29 | + }; |
| 30 | + const options: Record<string, any> = { |
| 31 | + requestInit: { headers: headers }, |
| 32 | + eventSourceInit: { |
| 33 | + fetch: (url: string, init?: RequestInit) => { |
| 34 | + return fetch(url, { |
| 35 | + ...(init || {}), |
| 36 | + headers: { |
| 37 | + ...(init?.headers || {}), |
| 38 | + ...headers, |
| 39 | + }, |
| 40 | + }); |
| 41 | + }, |
| 42 | + }, |
| 43 | + }; |
| 44 | + const transport = new SSEClientTransport(new URL(serverUrl), options); |
| 45 | + |
| 46 | + console.log('Connecting to Vapi MCP server via SSE...'); |
| 47 | + await mcpClient.connect(transport); |
| 48 | + console.log('Connected successfully'); |
| 49 | + |
| 50 | + try { |
| 51 | + // List available tools |
| 52 | + const toolsResult = await mcpClient.listTools(); |
| 53 | + console.log('Available tools:'); |
| 54 | + toolsResult.tools.forEach((tool) => { |
| 55 | + console.log(`- ${tool.name}: ${tool.description}`); |
| 56 | + }); |
| 57 | + |
| 58 | + // List assistants |
| 59 | + console.log('\nListing assistants...'); |
| 60 | + const assistantsResponse = await mcpClient.callTool({ |
| 61 | + name: 'list_assistants', |
| 62 | + arguments: {}, |
| 63 | + }); |
| 64 | + |
| 65 | + const assistants = parseToolResponse(assistantsResponse); |
| 66 | + |
| 67 | + if (!(Array.isArray(assistants) && assistants.length > 0)) { |
| 68 | + console.log( |
| 69 | + 'No assistants found. Please create an assistant in the Vapi dashboard first.' |
| 70 | + ); |
| 71 | + return; |
| 72 | + } |
| 73 | + |
| 74 | + console.log('Your assistants:'); |
| 75 | + assistants.forEach((assistant: any) => { |
| 76 | + console.log(`- ${assistant.name} (${assistant.id})`); |
| 77 | + }); |
| 78 | + |
| 79 | + // List phone numbers |
| 80 | + console.log('\nListing phone numbers...'); |
| 81 | + const phoneNumbersResponse = await mcpClient.callTool({ |
| 82 | + name: 'list_phone_numbers', |
| 83 | + arguments: {}, |
| 84 | + }); |
| 85 | + |
| 86 | + const phoneNumbers = parseToolResponse(phoneNumbersResponse); |
| 87 | + |
| 88 | + if (!(Array.isArray(phoneNumbers) && phoneNumbers.length > 0)) { |
| 89 | + console.log( |
| 90 | + 'No phone numbers found. Please add a phone number in the Vapi dashboard first.' |
| 91 | + ); |
| 92 | + return; |
| 93 | + } |
| 94 | + |
| 95 | + console.log('Your phone numbers:'); |
| 96 | + phoneNumbers.forEach((phoneNumber: any) => { |
| 97 | + console.log(`- ${phoneNumber.phoneNumber} (${phoneNumber.id})`); |
| 98 | + }); |
| 99 | + |
| 100 | + // Create a call using the first assistant and first phone number |
| 101 | + const phoneNumberId = phoneNumbers[0].id; |
| 102 | + const assistantId = assistants[0].id; |
| 103 | + |
| 104 | + console.log( |
| 105 | + `\nCreating a call using assistant (${assistantId}) and phone number (${phoneNumberId})...` |
| 106 | + ); |
| 107 | + const createCallResponse = await mcpClient.callTool({ |
| 108 | + name: 'create_call', |
| 109 | + arguments: { |
| 110 | + assistantId: assistantId, |
| 111 | + phoneNumberId: phoneNumberId, |
| 112 | + customer: { |
| 113 | + phoneNumber: '+1234567890', // Replace with actual customer phone number |
| 114 | + }, |
| 115 | + // Optional: schedule a call for the future |
| 116 | + // scheduledAt: "2025-04-15T15:30:00Z" |
| 117 | + }, |
| 118 | + }); |
| 119 | + |
| 120 | + const createdCall = parseToolResponse(createCallResponse); |
| 121 | + console.log('Call created:', JSON.stringify(createdCall, null, 2)); |
| 122 | + |
| 123 | + // List calls |
| 124 | + console.log('\nListing calls...'); |
| 125 | + const callsResponse = await mcpClient.callTool({ |
| 126 | + name: 'list_calls', |
| 127 | + arguments: {}, |
| 128 | + }); |
| 129 | + |
| 130 | + const calls = parseToolResponse(callsResponse); |
| 131 | + |
| 132 | + if (Array.isArray(calls) && calls.length > 0) { |
| 133 | + console.log('Your calls:'); |
| 134 | + calls.forEach((call: any) => { |
| 135 | + const createdAt = call.createdAt ? new Date(call.createdAt).toLocaleString() : 'N/A'; |
| 136 | + const customerPhone = call.customer?.phoneNumber || 'N/A'; |
| 137 | + const endedReason = call.endedReason || 'N/A'; |
| 138 | + |
| 139 | + console.log(`- ID: ${call.id} | Status: ${call.status} | Created: ${createdAt} | Customer: ${customerPhone} | Ended reason: ${endedReason}`); |
| 140 | + }); |
| 141 | + } else { |
| 142 | + console.log('No calls found. Try creating a call first.'); |
| 143 | + } |
| 144 | + |
| 145 | + } finally { |
| 146 | + console.log('\nDisconnecting from server...'); |
| 147 | + await mcpClient.close(); |
| 148 | + console.log('Disconnected'); |
| 149 | + } |
| 150 | + } catch (error) { |
| 151 | + console.error('Error:', error); |
| 152 | + process.exit(1); |
| 153 | + } |
| 154 | +} |
| 155 | + |
| 156 | +main(); |
0 commit comments