Skip to content

Commit 143568e

Browse files
committed
updated examples
1 parent 6274b8a commit 143568e

File tree

7 files changed

+253
-10
lines changed

7 files changed

+253
-10
lines changed

examples/sse-client.ts

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
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();

examples/client.ts renamed to examples/stdio-client.ts

+84
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,90 @@ async function main() {
125125
'\nString LLM Assistant:',
126126
JSON.stringify(stringLLMAssistant, null, 2)
127127
);
128+
129+
// List phone numbers
130+
console.log('\nListing phone numbers...');
131+
const phoneNumbersResponse = await mcpClient.callTool({
132+
name: 'list_phone_numbers',
133+
arguments: {},
134+
});
135+
136+
const phoneNumbers = parseToolResponse(phoneNumbersResponse);
137+
138+
if (Array.isArray(phoneNumbers) && phoneNumbers.length > 0) {
139+
console.log('Your phone numbers:');
140+
phoneNumbers.forEach((phoneNumber: any) => {
141+
console.log(`- ${phoneNumber.phoneNumber} (${phoneNumber.id})`);
142+
});
143+
} else {
144+
console.log('No phone numbers found. Please add a phone number in the Vapi dashboard first.');
145+
}
146+
147+
// List calls
148+
console.log('\nListing calls...');
149+
const callsResponse = await mcpClient.callTool({
150+
name: 'list_calls',
151+
arguments: {},
152+
});
153+
154+
const calls = parseToolResponse(callsResponse);
155+
156+
if (Array.isArray(calls) && calls.length > 0) {
157+
console.log('Your calls:');
158+
calls.forEach((call: any) => {
159+
const createdAt = call.createdAt ? new Date(call.createdAt).toLocaleString() : 'N/A';
160+
const customerPhone = call.customer?.phoneNumber || 'N/A';
161+
const endedReason = call.endedReason || 'N/A';
162+
163+
console.log(`- ID: ${call.id} | Status: ${call.status} | Created: ${createdAt} | Customer: ${customerPhone} | Ended reason: ${endedReason}`);
164+
});
165+
} else {
166+
console.log('No calls found');
167+
}
168+
169+
// Create a call
170+
console.log('\nCreating a call...');
171+
172+
if (Array.isArray(assistants) && assistants.length > 0 &&
173+
Array.isArray(phoneNumbers) && phoneNumbers.length > 0) {
174+
175+
const phoneNumberId = phoneNumbers[0].id;
176+
const assistantId = assistants[0].id;
177+
178+
console.log(`Creating a call using assistant (${assistantId}) and phone number (${phoneNumberId})...`);
179+
180+
const createCallResponse = await mcpClient.callTool({
181+
name: 'create_call',
182+
arguments: {
183+
assistantId: assistantId,
184+
phoneNumberId: phoneNumberId,
185+
customer: {
186+
// phoneNumber: '+1234567890', // Replace with actual customer phone number
187+
},
188+
// Optional: schedule a call for the future
189+
// scheduledAt: "2025-04-15T15:30:00Z"
190+
},
191+
});
192+
193+
const createdCall = parseToolResponse(createCallResponse);
194+
console.log('\nCall created:', JSON.stringify(createdCall, null, 2));
195+
196+
// Get call details if we have the call ID
197+
if (createdCall && createdCall.id) {
198+
console.log(`\nGetting details for call ${createdCall.id}...`);
199+
const callDetailsResponse = await mcpClient.callTool({
200+
name: 'get_call',
201+
arguments: {
202+
callId: createdCall.id
203+
},
204+
});
205+
206+
const callDetails = parseToolResponse(callDetailsResponse);
207+
console.log('\nCall details:', JSON.stringify(callDetails, null, 2));
208+
}
209+
} else {
210+
console.log('Cannot create call: Need both assistants and phone numbers.');
211+
}
128212
} finally {
129213
console.log('\nDisconnecting from server...');
130214
await mcpClient.close();

jest.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ export default {
1111
},
1212
],
1313
},
14+
testRegex: '.*\\.test\\.tsx?$',
15+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
16+
testPathIgnorePatterns: ['/node_modules/', '/dist/', '\\.d\\.ts$', '.*\\.mock\\.ts$'],
1417
extensionsToTreatAsEsm: ['.ts'],
1518
moduleNameMapper: {
1619
'^(\\.{1,2}/.*)\\.js$': '$1',

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
"build": "tsc && shx chmod +x dist/*.js",
3838
"start": "node dist/index.js",
3939
"dev": "tsx watch src/index.ts",
40-
"dev:example": "tsx examples/client.ts",
40+
"dev:stdio-example": "tsx examples/stdio-client.ts",
41+
"dev:sse-example": "tsx examples/sse-client.ts",
4142
"inspector": "mcp-inspector",
4243
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
4344
"test:unit": "NODE_OPTIONS=--experimental-vm-modules jest src/tests/mcp-server-mock.test.ts",

src/schemas/index.ts

+4-6
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,13 @@ export const GetCallInputSchema = z.object({
235235

236236
// ===== Phone Number Schemas =====
237237

238-
export const PhoneNumberInputSchema = z.object({
239-
areaCode: z.string().describe('Area code to search for'),
238+
239+
export const GetPhoneNumberInputSchema = z.object({
240+
phoneNumberId: z.string().describe('ID of the phone number to get'),
240241
});
241242

242243
export const PhoneNumberOutputSchema = BaseResponseSchema.extend({
244+
name: z.string().optional(),
243245
phoneNumber: z.string(),
244246
status: z.string(),
245247
capabilities: z
@@ -249,7 +251,3 @@ export const PhoneNumberOutputSchema = BaseResponseSchema.extend({
249251
})
250252
.optional(),
251253
});
252-
253-
export const GetPhoneNumberInputSchema = z.object({
254-
phoneNumberId: z.string().describe('ID of the phone number to get'),
255-
});

src/transformers/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,10 @@ export function transformPhoneNumberOutput(
152152
): z.infer<typeof PhoneNumberOutputSchema> {
153153
return {
154154
id: phoneNumber.id,
155+
name: phoneNumber.name,
155156
createdAt: phoneNumber.createdAt,
156157
updatedAt: phoneNumber.updatedAt,
157-
phoneNumber: phoneNumber.phoneNumber,
158+
phoneNumber: phoneNumber.number,
158159
status: phoneNumber.status,
159160
};
160161
}

src/utils/response.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ export function parseToolResponse(response: any): any {
99
)?.text;
1010

1111
if (textContent) {
12-
// Check if it's an error message first
13-
if (textContent.startsWith('Error:') || textContent.includes('error')) {
12+
// Check if it's an error message first - only if it starts with 'Error:'
13+
if (textContent.startsWith('Error:')) {
1414
return { error: textContent };
1515
}
1616

0 commit comments

Comments
 (0)