@vapi-ai/mcp-server 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -112
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/schemas/index.d.ts +799 -12
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +69 -0
- package/dist/tools/assistant.d.ts.map +1 -1
- package/dist/tools/assistant.js +4 -1
- package/dist/tools/call.d.ts.map +1 -1
- package/dist/tools/call.js +4 -1
- package/dist/tools/phone-number.d.ts.map +1 -1
- package/dist/tools/phone-number.js +4 -1
- package/dist/tools/tool.d.ts.map +1 -1
- package/dist/tools/tool.js +16 -3
- package/dist/transformers/index.d.ts +4 -2
- package/dist/transformers/index.d.ts.map +1 -1
- package/dist/transformers/index.js +114 -0
- package/package.json +21 -10
- package/dist/__tests__/mcp-server-e2e.test.d.ts +0 -2
- package/dist/__tests__/mcp-server-e2e.test.d.ts.map +0 -1
- package/dist/__tests__/mcp-server-e2e.test.js +0 -239
- package/dist/__tests__/mcp-server-mock.test.d.ts +0 -2
- package/dist/__tests__/mcp-server-mock.test.d.ts.map +0 -1
- package/dist/__tests__/mcp-server-mock.test.js +0 -34
- package/dist/__tests__/mocks/vapi-client.mock.d.ts +0 -9
- package/dist/__tests__/mocks/vapi-client.mock.d.ts.map +0 -1
- package/dist/__tests__/mocks/vapi-client.mock.js +0 -43
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,aAAa;;;;CAIhB,CAAC;AAEX,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAEX,eAAO,MAAM,eAAe;;;CAGlB,CAAC;AAEX,eAAO,MAAM,YAAY;;;;;CAKf,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAC3B,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC;AACrD,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAC/E,MAAM,MAAM,kBAAkB,GAC5B,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,OAAO,eAAe,CAAC,CAAC;AACzD,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAqC/E,eAAO,MAAM,WAAW;;;CAGvB,CAAC;AAEF,QAAA,MAAM,mBAAmB,wLAiBvB,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEpE,eAAO,MAAM,aAAa;cACF,iBAAiB;;CAExC,CAAC;AAEF,eAAO,MAAM,mBAAmB;;;CAG/B,CAAC;AAEF,eAAO,MAAM,kBAAkB;;;;;;CAMrB,CAAC;AAIX,eAAO,MAAM,kBAAkB;;;;;;;;;;;;EAI7B,CAAC;AAIH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqDrC,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgBhC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;EAElC,CAAC;AAEH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmDrC,CAAC;AAIH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgC1B,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAW3B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;EAE7B,CAAC;AAIH,eAAO,MAAM,yBAAyB;;;;;;EAEpC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUlC,CAAC;AAIH,eAAO,MAAM,kBAAkB;;;;;;EAE7B,CAAC;AAEH,eAAO,MAAM,gBAAgB
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"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"}
|
package/dist/schemas/index.js
CHANGED
|
@@ -285,10 +285,79 @@ export const PhoneNumberOutputSchema = BaseResponseSchema.extend({
|
|
|
285
285
|
export const GetToolInputSchema = z.object({
|
|
286
286
|
toolId: z.string().describe('ID of the tool to get'),
|
|
287
287
|
});
|
|
288
|
+
const TransferCallDestinationSchema = z.object({
|
|
289
|
+
type: z.literal('number'),
|
|
290
|
+
number: z.string().describe('Phone number to transfer to (e.g., "+16054440129"). It can be any phone number in E.164 format.'),
|
|
291
|
+
extension: z.string().optional().describe('Extension number if applicable'),
|
|
292
|
+
callerId: z.string().optional().describe('Caller ID to use for the transfer'),
|
|
293
|
+
description: z.string().optional().describe('Description of the transfer destination'),
|
|
294
|
+
});
|
|
295
|
+
// Generic custom tool schemas
|
|
296
|
+
const JsonSchemaProperty = z.object({
|
|
297
|
+
type: z.string(),
|
|
298
|
+
description: z.string().optional(),
|
|
299
|
+
enum: z.array(z.string()).optional(),
|
|
300
|
+
items: z.any().optional(),
|
|
301
|
+
properties: z.record(z.any()).optional(),
|
|
302
|
+
required: z.array(z.string()).optional(),
|
|
303
|
+
});
|
|
304
|
+
const JsonSchema = z.object({
|
|
305
|
+
type: z.literal('object'),
|
|
306
|
+
properties: z.record(JsonSchemaProperty),
|
|
307
|
+
required: z.array(z.string()).optional(),
|
|
308
|
+
});
|
|
309
|
+
const ServerSchema = z.object({
|
|
310
|
+
url: z.string().url().describe('Server URL where the function will be called'),
|
|
311
|
+
headers: z.record(z.string()).optional().describe('Headers to send with the request'),
|
|
312
|
+
});
|
|
313
|
+
const BackoffPlanSchema = z.object({
|
|
314
|
+
type: z.enum(['fixed', 'exponential']).default('fixed'),
|
|
315
|
+
maxRetries: z.number().default(3).describe('Maximum number of retries'),
|
|
316
|
+
baseDelaySeconds: z.number().default(1).describe('Base delay between retries in seconds'),
|
|
317
|
+
});
|
|
318
|
+
// Base tool configuration schema (reusable for both create and update)
|
|
319
|
+
const BaseToolConfigSchema = z.object({
|
|
320
|
+
// Common fields for all tools
|
|
321
|
+
name: z.string().optional().describe('Name of the function/tool'),
|
|
322
|
+
description: z.string().optional().describe('Description of what the function/tool does'),
|
|
323
|
+
// SMS tool configuration
|
|
324
|
+
sms: z.object({
|
|
325
|
+
metadata: z.object({
|
|
326
|
+
from: z.string().describe('Phone number to send SMS from (e.g., "+15551234567"). It must be a twilio number in E.164 format.'),
|
|
327
|
+
}).describe('SMS configuration metadata'),
|
|
328
|
+
}).optional().describe('SMS tool configuration - to send text messages'),
|
|
329
|
+
// Transfer call tool configuration
|
|
330
|
+
transferCall: z.object({
|
|
331
|
+
destinations: z.array(TransferCallDestinationSchema).describe('Array of possible transfer destinations'),
|
|
332
|
+
}).optional().describe('Transfer call tool configuration - to transfer calls to destinations'),
|
|
333
|
+
// Function tool configuration (custom functions with parameters)
|
|
334
|
+
function: z.object({
|
|
335
|
+
parameters: JsonSchema.describe('JSON schema for function parameters'),
|
|
336
|
+
server: ServerSchema.describe('Server configuration with URL where the function will be called'),
|
|
337
|
+
}).optional().describe('Custom function tool configuration - for custom server-side functions'),
|
|
338
|
+
// API Request tool configuration
|
|
339
|
+
apiRequest: z.object({
|
|
340
|
+
url: z.string().url().describe('URL to make the API request to'),
|
|
341
|
+
method: z.enum(['GET', 'POST']).default('POST').describe('HTTP method for the API request'),
|
|
342
|
+
headers: z.record(z.string()).optional().describe('Headers to send with the request (key-value pairs)'),
|
|
343
|
+
body: JsonSchema.optional().describe('Body schema for the API request in JSON Schema format'),
|
|
344
|
+
backoffPlan: BackoffPlanSchema.optional().describe('Retry configuration for failed API requests'),
|
|
345
|
+
timeoutSeconds: z.number().default(20).describe('Request timeout in seconds'),
|
|
346
|
+
}).optional().describe('API Request tool configuration - for HTTP API integration'),
|
|
347
|
+
});
|
|
348
|
+
export const CreateToolInputSchema = BaseToolConfigSchema.extend({
|
|
349
|
+
type: z.enum(['sms', 'transferCall', 'function', 'apiRequest'])
|
|
350
|
+
.describe('Type of the tool to create'),
|
|
351
|
+
});
|
|
352
|
+
export const UpdateToolInputSchema = BaseToolConfigSchema.extend({
|
|
353
|
+
toolId: z.string().describe('ID of the tool to update'),
|
|
354
|
+
});
|
|
288
355
|
export const ToolOutputSchema = BaseResponseSchema.extend({
|
|
289
356
|
type: z
|
|
290
357
|
.string()
|
|
291
358
|
.describe('Type of the tool (dtmf, function, mcp, query, etc.)'),
|
|
292
359
|
name: z.string().describe('Name of the tool'),
|
|
293
360
|
description: z.string().describe('Description of the tool'),
|
|
361
|
+
parameters: z.record(z.any()).describe('Parameters of the tool'),
|
|
362
|
+
server: ServerSchema.describe('Server of the tool'),
|
|
294
363
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant.d.ts","sourceRoot":"","sources":["../../src/tools/assistant.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAQ,MAAM,qBAAqB,CAAC;AAavD,eAAO,MAAM,sBAAsB,GACjC,QAAQ,SAAS,EACjB,YAAY,UAAU,
|
|
1
|
+
{"version":3,"file":"assistant.d.ts","sourceRoot":"","sources":["../../src/tools/assistant.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAQ,MAAM,qBAAqB,CAAC;AAavD,eAAO,MAAM,sBAAsB,GACjC,QAAQ,SAAS,EACjB,YAAY,UAAU,SA6EvB,CAAC"}
|
package/dist/tools/assistant.js
CHANGED
|
@@ -2,7 +2,10 @@ import { CreateAssistantInputSchema, GetAssistantInputSchema, UpdateAssistantInp
|
|
|
2
2
|
import { transformAssistantInput, transformAssistantOutput, transformUpdateAssistantInput, } from '../transformers/index.js';
|
|
3
3
|
import { createToolHandler } from './utils.js';
|
|
4
4
|
export const registerAssistantTools = (server, vapiClient) => {
|
|
5
|
-
server.
|
|
5
|
+
server.registerTool('list_assistants', {
|
|
6
|
+
description: 'Lists all Vapi assistants',
|
|
7
|
+
inputSchema: {},
|
|
8
|
+
}, createToolHandler(async () => {
|
|
6
9
|
// console.log('list_assistants');
|
|
7
10
|
const assistants = await vapiClient.assistants.list({ limit: 10 });
|
|
8
11
|
// console.log('assistants', assistants);
|
package/dist/tools/call.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call.d.ts","sourceRoot":"","sources":["../../src/tools/call.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAQ,MAAM,qBAAqB,CAAC;AASvD,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,SAAS,EACjB,YAAY,UAAU,
|
|
1
|
+
{"version":3,"file":"call.d.ts","sourceRoot":"","sources":["../../src/tools/call.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAQ,MAAM,qBAAqB,CAAC;AASvD,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,SAAS,EACjB,YAAY,UAAU,SAkCvB,CAAC"}
|
package/dist/tools/call.js
CHANGED
|
@@ -2,7 +2,10 @@ import { CallInputSchema, GetCallInputSchema } from '../schemas/index.js';
|
|
|
2
2
|
import { transformCallInput, transformCallOutput, } from '../transformers/index.js';
|
|
3
3
|
import { createToolHandler } from './utils.js';
|
|
4
4
|
export const registerCallTools = (server, vapiClient) => {
|
|
5
|
-
server.
|
|
5
|
+
server.registerTool('list_calls', {
|
|
6
|
+
description: 'Lists all Vapi calls',
|
|
7
|
+
inputSchema: {},
|
|
8
|
+
}, createToolHandler(async () => {
|
|
6
9
|
const calls = await vapiClient.calls.list({ limit: 10 });
|
|
7
10
|
return calls.map(transformCallOutput);
|
|
8
11
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"phone-number.d.ts","sourceRoot":"","sources":["../../src/tools/phone-number.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAMjD,eAAO,MAAM,wBAAwB,GACnC,QAAQ,SAAS,EACjB,YAAY,UAAU,
|
|
1
|
+
{"version":3,"file":"phone-number.d.ts","sourceRoot":"","sources":["../../src/tools/phone-number.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAMjD,eAAO,MAAM,wBAAwB,GACnC,QAAQ,SAAS,EACjB,YAAY,UAAU,SAwBvB,CAAC"}
|
|
@@ -2,7 +2,10 @@ import { transformPhoneNumberOutput } from '../transformers/index.js';
|
|
|
2
2
|
import { createToolHandler } from './utils.js';
|
|
3
3
|
import { GetPhoneNumberInputSchema } from '../schemas/index.js';
|
|
4
4
|
export const registerPhoneNumberTools = (server, vapiClient) => {
|
|
5
|
-
server.
|
|
5
|
+
server.registerTool('list_phone_numbers', {
|
|
6
|
+
description: 'Lists all Vapi phone numbers',
|
|
7
|
+
inputSchema: {},
|
|
8
|
+
}, createToolHandler(async () => {
|
|
6
9
|
const phoneNumbers = await vapiClient.phoneNumbers.list({ limit: 10 });
|
|
7
10
|
return phoneNumbers.map(transformPhoneNumberOutput);
|
|
8
11
|
}));
|
package/dist/tools/tool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/tools/tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAQ,MAAM,qBAAqB,CAAC;AAMvD,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,SAAS,EACjB,YAAY,UAAU,
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/tools/tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAQ,MAAM,qBAAqB,CAAC;AAMvD,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,SAAS,EACjB,YAAY,UAAU,SA6CvB,CAAC"}
|
package/dist/tools/tool.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { GetToolInputSchema } from '../schemas/index.js';
|
|
2
|
-
import { transformToolOutput } from '../transformers/index.js';
|
|
1
|
+
import { GetToolInputSchema, CreateToolInputSchema, UpdateToolInputSchema } from '../schemas/index.js';
|
|
2
|
+
import { transformToolInput, transformUpdateToolInput, transformToolOutput } from '../transformers/index.js';
|
|
3
3
|
import { createToolHandler } from './utils.js';
|
|
4
4
|
export const registerToolTools = (server, vapiClient) => {
|
|
5
|
-
server.
|
|
5
|
+
server.registerTool('list_tools', {
|
|
6
|
+
description: 'Lists all Vapi tools',
|
|
7
|
+
inputSchema: {},
|
|
8
|
+
}, createToolHandler(async () => {
|
|
6
9
|
const tools = await vapiClient.tools.list({ limit: 10 });
|
|
7
10
|
return tools.map(transformToolOutput);
|
|
8
11
|
}));
|
|
@@ -10,4 +13,14 @@ export const registerToolTools = (server, vapiClient) => {
|
|
|
10
13
|
const tool = await vapiClient.tools.get(data.toolId);
|
|
11
14
|
return transformToolOutput(tool);
|
|
12
15
|
}));
|
|
16
|
+
server.tool('create_tool', 'Creates a new Vapi tool', CreateToolInputSchema.shape, createToolHandler(async (data) => {
|
|
17
|
+
const createToolDto = transformToolInput(data);
|
|
18
|
+
const tool = await vapiClient.tools.create(createToolDto);
|
|
19
|
+
return transformToolOutput(tool);
|
|
20
|
+
}));
|
|
21
|
+
server.tool('update_tool', 'Updates an existing Vapi tool', UpdateToolInputSchema.shape, createToolHandler(async (data) => {
|
|
22
|
+
const updateToolDto = transformUpdateToolInput(data);
|
|
23
|
+
const tool = await vapiClient.tools.update(data.toolId, updateToolDto);
|
|
24
|
+
return transformToolOutput(tool);
|
|
25
|
+
}));
|
|
13
26
|
};
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Vapi } from '@vapi-ai/server-sdk';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { CreateAssistantInputSchema, CallInputSchema, AssistantOutputSchema, CallOutputSchema, PhoneNumberOutputSchema, ToolOutputSchema, UpdateAssistantInputSchema } from '../schemas/index.js';
|
|
3
|
+
import { CreateAssistantInputSchema, CallInputSchema, AssistantOutputSchema, CallOutputSchema, PhoneNumberOutputSchema, ToolOutputSchema, UpdateAssistantInputSchema, CreateToolInputSchema, UpdateToolInputSchema } from '../schemas/index.js';
|
|
4
4
|
export declare function transformAssistantInput(input: z.infer<typeof CreateAssistantInputSchema>): Vapi.CreateAssistantDto;
|
|
5
5
|
export declare function transformUpdateAssistantInput(input: z.infer<typeof UpdateAssistantInputSchema>): Vapi.UpdateAssistantDto;
|
|
6
6
|
export declare function transformAssistantOutput(assistant: Vapi.Assistant): z.infer<typeof AssistantOutputSchema>;
|
|
7
7
|
export declare function transformCallInput(input: z.infer<typeof CallInputSchema>): Vapi.CreateCallDto;
|
|
8
8
|
export declare function transformCallOutput(call: Vapi.Call): z.infer<typeof CallOutputSchema>;
|
|
9
9
|
export declare function transformPhoneNumberOutput(phoneNumber: any): z.infer<typeof PhoneNumberOutputSchema>;
|
|
10
|
-
export declare function
|
|
10
|
+
export declare function transformToolInput(input: z.infer<typeof CreateToolInputSchema>): any;
|
|
11
|
+
export declare function transformUpdateToolInput(input: z.infer<typeof UpdateToolInputSchema>): any;
|
|
12
|
+
export declare function transformToolOutput(tool: Vapi.ToolsGetResponse): z.infer<typeof ToolOutputSchema>;
|
|
11
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transformers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,0BAA0B,EAC1B,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,0BAA0B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transformers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,0BAA0B,EAC1B,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,0BAA0B,EAC1B,qBAAqB,EACrB,qBAAqB,EACtB,MAAM,qBAAqB,CAAC;AAI7B,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,GAChD,IAAI,CAAC,kBAAkB,CA2CzB;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,GAChD,IAAI,CAAC,kBAAkB,CAiEzB;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,IAAI,CAAC,SAAS,GACxB,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAqBvC;AA2BD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,GACrC,IAAI,CAAC,aAAa,CAwBpB;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,IAAI,CAAC,IAAI,GACd,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAgBlC;AAID,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,GAAG,GACf,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CASzC;AAID,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,GAC3C,GAAG,CA8DL;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,GAC3C,GAAG,CAiDL;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,IAAI,CAAC,gBAAgB,GAC1B,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAclC"}
|
|
@@ -188,6 +188,115 @@ export function transformPhoneNumberOutput(phoneNumber) {
|
|
|
188
188
|
};
|
|
189
189
|
}
|
|
190
190
|
// ===== Tool Transformers =====
|
|
191
|
+
export function transformToolInput(input) {
|
|
192
|
+
let toolDto = {
|
|
193
|
+
type: input.type,
|
|
194
|
+
};
|
|
195
|
+
// Add function definition if name and description are provided
|
|
196
|
+
if (input.name || input.description) {
|
|
197
|
+
toolDto.function = {
|
|
198
|
+
...(input.name && { name: input.name }),
|
|
199
|
+
...(input.description && { description: input.description }),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
// Handle different tool types using the new nested structure
|
|
203
|
+
switch (input.type) {
|
|
204
|
+
case 'sms':
|
|
205
|
+
if (input.sms?.metadata) {
|
|
206
|
+
toolDto.metadata = input.sms.metadata;
|
|
207
|
+
}
|
|
208
|
+
break;
|
|
209
|
+
case 'transferCall':
|
|
210
|
+
if (input.transferCall?.destinations) {
|
|
211
|
+
toolDto.destinations = input.transferCall.destinations;
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
case 'function':
|
|
215
|
+
if (input.function?.parameters && input.function?.server) {
|
|
216
|
+
// For function tools, add parameters to the existing function object
|
|
217
|
+
if (toolDto.function) {
|
|
218
|
+
toolDto.function.parameters = input.function.parameters;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
toolDto.function = {
|
|
222
|
+
parameters: input.function.parameters,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
toolDto.server = {
|
|
226
|
+
url: input.function.server.url,
|
|
227
|
+
...(input.function.server.headers && { headers: input.function.server.headers }),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
break;
|
|
231
|
+
case 'apiRequest':
|
|
232
|
+
if (input.apiRequest?.url) {
|
|
233
|
+
toolDto.url = input.apiRequest.url;
|
|
234
|
+
toolDto.method = input.apiRequest.method || 'POST';
|
|
235
|
+
if (input.apiRequest.headers)
|
|
236
|
+
toolDto.headers = input.apiRequest.headers;
|
|
237
|
+
if (input.apiRequest.body)
|
|
238
|
+
toolDto.body = input.apiRequest.body;
|
|
239
|
+
if (input.apiRequest.backoffPlan)
|
|
240
|
+
toolDto.backoffPlan = input.apiRequest.backoffPlan;
|
|
241
|
+
if (input.apiRequest.timeoutSeconds)
|
|
242
|
+
toolDto.timeoutSeconds = input.apiRequest.timeoutSeconds;
|
|
243
|
+
}
|
|
244
|
+
break;
|
|
245
|
+
default:
|
|
246
|
+
throw new Error(`Unsupported tool type: ${input.type}`);
|
|
247
|
+
}
|
|
248
|
+
return toolDto;
|
|
249
|
+
}
|
|
250
|
+
export function transformUpdateToolInput(input) {
|
|
251
|
+
let updateDto = {};
|
|
252
|
+
// Add function definition if name and description are provided
|
|
253
|
+
if (input.name || input.description) {
|
|
254
|
+
updateDto.function = {
|
|
255
|
+
...(input.name && { name: input.name }),
|
|
256
|
+
...(input.description && { description: input.description }),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
// Handle SMS tool configuration
|
|
260
|
+
if (input.sms?.metadata) {
|
|
261
|
+
updateDto.metadata = input.sms.metadata;
|
|
262
|
+
}
|
|
263
|
+
// Handle Transfer call tool configuration
|
|
264
|
+
if (input.transferCall?.destinations) {
|
|
265
|
+
updateDto.destinations = input.transferCall.destinations;
|
|
266
|
+
}
|
|
267
|
+
// Handle Function tool configuration
|
|
268
|
+
if (input.function?.parameters && input.function?.server) {
|
|
269
|
+
// For function tools, add parameters to the existing function object
|
|
270
|
+
if (updateDto.function) {
|
|
271
|
+
updateDto.function.parameters = input.function.parameters;
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
updateDto.function = {
|
|
275
|
+
parameters: input.function.parameters,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
updateDto.server = {
|
|
279
|
+
url: input.function.server.url,
|
|
280
|
+
...(input.function.server.headers && { headers: input.function.server.headers }),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
// Handle API Request tool configuration
|
|
284
|
+
if (input.apiRequest) {
|
|
285
|
+
if (input.apiRequest.url)
|
|
286
|
+
updateDto.url = input.apiRequest.url;
|
|
287
|
+
if (input.apiRequest.method)
|
|
288
|
+
updateDto.method = input.apiRequest.method;
|
|
289
|
+
if (input.apiRequest.headers)
|
|
290
|
+
updateDto.headers = input.apiRequest.headers;
|
|
291
|
+
if (input.apiRequest.body)
|
|
292
|
+
updateDto.body = input.apiRequest.body;
|
|
293
|
+
if (input.apiRequest.backoffPlan)
|
|
294
|
+
updateDto.backoffPlan = input.apiRequest.backoffPlan;
|
|
295
|
+
if (input.apiRequest.timeoutSeconds)
|
|
296
|
+
updateDto.timeoutSeconds = input.apiRequest.timeoutSeconds;
|
|
297
|
+
}
|
|
298
|
+
return updateDto;
|
|
299
|
+
}
|
|
191
300
|
export function transformToolOutput(tool) {
|
|
192
301
|
return {
|
|
193
302
|
id: tool.id,
|
|
@@ -196,5 +305,10 @@ export function transformToolOutput(tool) {
|
|
|
196
305
|
type: tool.type || '',
|
|
197
306
|
name: tool.function?.name || '',
|
|
198
307
|
description: tool.function?.description || '',
|
|
308
|
+
parameters: tool.function?.parameters || {},
|
|
309
|
+
server: {
|
|
310
|
+
url: tool.server?.url || '',
|
|
311
|
+
headers: tool.server?.headers || {},
|
|
312
|
+
}
|
|
199
313
|
};
|
|
200
314
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vapi-ai/mcp-server",
|
|
3
|
-
"description": "Vapi
|
|
4
|
-
"version": "0.0.
|
|
3
|
+
"description": "Build AI voice assistants and phone agents with Vapi through the Model Context Protocol",
|
|
4
|
+
"version": "0.0.10",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
@@ -24,8 +24,10 @@
|
|
|
24
24
|
"vapi",
|
|
25
25
|
"mcp",
|
|
26
26
|
"model-context-protocol",
|
|
27
|
+
"mcp-server",
|
|
28
|
+
"mcp-client",
|
|
27
29
|
"ai",
|
|
28
|
-
"
|
|
30
|
+
"voice-agents",
|
|
29
31
|
"voice-api",
|
|
30
32
|
"tool-calling"
|
|
31
33
|
],
|
|
@@ -34,16 +36,25 @@
|
|
|
34
36
|
},
|
|
35
37
|
"scripts": {
|
|
36
38
|
"prepare": "npm run build",
|
|
37
|
-
"
|
|
39
|
+
"clean": "shx rm -rf dist",
|
|
40
|
+
"build": "npm run clean && tsc -p tsconfig.build.json && shx chmod +x dist/*.js",
|
|
41
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
38
42
|
"start": "node dist/index.js",
|
|
39
43
|
"dev": "tsx watch src/index.ts",
|
|
40
44
|
"dev:stdio-example": "tsx examples/stdio-client.ts",
|
|
41
45
|
"dev:sse-example": "tsx examples/sse-client.ts",
|
|
42
46
|
"dev:shttp-example": "tsx examples/shttp-client.ts",
|
|
43
47
|
"inspector": "mcp-inspector",
|
|
44
|
-
"
|
|
45
|
-
"test
|
|
46
|
-
"test:
|
|
48
|
+
"pretest": "npm run build",
|
|
49
|
+
"test": "VAPI_TOKEN=test-mock-token NODE_OPTIONS=--experimental-vm-modules jest --runInBand --testPathIgnorePatterns='.*-live\\.test\\.ts$'",
|
|
50
|
+
"test:unit": "VAPI_TOKEN=test-mock-token NODE_OPTIONS=--experimental-vm-modules jest --runInBand src/__tests__/mcp-tool-execution.test.ts src/__tests__/mcp-tools-list.test.ts",
|
|
51
|
+
"test:docs": "NODE_OPTIONS=--experimental-vm-modules jest --runInBand src/__tests__/documentation-tools.test.ts",
|
|
52
|
+
"pretest:stdio": "npm run build",
|
|
53
|
+
"test:stdio": "VAPI_TOKEN=test-mock-token NODE_OPTIONS=--experimental-vm-modules jest --runInBand src/__tests__/mcp-stdio-compat.test.ts",
|
|
54
|
+
"pretest:package": "npm run build",
|
|
55
|
+
"test:package": "node scripts/package-smoke.mjs",
|
|
56
|
+
"test:live:readonly": "npm run build && RUN_VAPI_READONLY_TESTS=1 NODE_OPTIONS=--experimental-vm-modules jest --runInBand src/__tests__/mcp-server-readonly-live.test.ts",
|
|
57
|
+
"test:live:mutating": "npm run build && RUN_VAPI_MUTATING_TESTS=1 NODE_OPTIONS=--experimental-vm-modules jest --runInBand src/__tests__/mcp-server-mutating-live.test.ts"
|
|
47
58
|
},
|
|
48
59
|
"files": [
|
|
49
60
|
"dist",
|
|
@@ -51,14 +62,14 @@
|
|
|
51
62
|
"dist/**/*.d.ts.map"
|
|
52
63
|
],
|
|
53
64
|
"dependencies": {
|
|
54
|
-
"@modelcontextprotocol/sdk": "
|
|
65
|
+
"@modelcontextprotocol/sdk": "1.26.0",
|
|
55
66
|
"@vapi-ai/server-sdk": "^0.5.2",
|
|
56
67
|
"dotenv": "^16.4.7",
|
|
57
|
-
"zod": "^3.
|
|
68
|
+
"zod": "^3.25.76",
|
|
58
69
|
"zod-to-json-schema": "^3.24.5"
|
|
59
70
|
},
|
|
60
71
|
"devDependencies": {
|
|
61
|
-
"@modelcontextprotocol/inspector": "
|
|
72
|
+
"@modelcontextprotocol/inspector": "1.0.1",
|
|
62
73
|
"@types/jest": "^29.5.14",
|
|
63
74
|
"@types/node": "^22.14.0",
|
|
64
75
|
"jest": "^29.7.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-server-e2e.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/mcp-server-e2e.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
-
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { jest } from '@jest/globals';
|
|
5
|
-
import dotenv from 'dotenv';
|
|
6
|
-
import { parseToolResponse } from '../utils/response.js';
|
|
7
|
-
dotenv.config();
|
|
8
|
-
jest.setTimeout(15000);
|
|
9
|
-
describe('MCP Server E2E Test', () => {
|
|
10
|
-
let mcpClient;
|
|
11
|
-
let transport;
|
|
12
|
-
beforeAll(async () => {
|
|
13
|
-
const serverScriptPath = join(process.cwd(), 'src', 'index.ts');
|
|
14
|
-
console.log(`Using server source at: ${serverScriptPath}`);
|
|
15
|
-
mcpClient = new Client({ name: 'vapi-e2e-test-client', version: '1.0.0' });
|
|
16
|
-
transport = new StdioClientTransport({
|
|
17
|
-
command: 'npx',
|
|
18
|
-
args: ['tsx', serverScriptPath],
|
|
19
|
-
env: {
|
|
20
|
-
...process.env,
|
|
21
|
-
VAPI_TOKEN: process.env.VAPI_TOKEN || 'test-token',
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
console.log('Connecting to MCP server...');
|
|
25
|
-
await mcpClient.connect(transport);
|
|
26
|
-
console.log('Connected to server successfully');
|
|
27
|
-
});
|
|
28
|
-
afterAll(async () => {
|
|
29
|
-
console.log('Disconnecting from server...');
|
|
30
|
-
await mcpClient.close();
|
|
31
|
-
console.log('Disconnected from server');
|
|
32
|
-
});
|
|
33
|
-
test('should list available tools', async () => {
|
|
34
|
-
console.log('Requesting available tools...');
|
|
35
|
-
const toolsResult = await mcpClient.listTools();
|
|
36
|
-
expect(toolsResult.tools).toBeDefined();
|
|
37
|
-
expect(Array.isArray(toolsResult.tools)).toBe(true);
|
|
38
|
-
const toolNames = toolsResult.tools.map((tool) => tool.name);
|
|
39
|
-
console.log('Available tools:', toolNames);
|
|
40
|
-
expect(toolNames).toContain('list_assistants');
|
|
41
|
-
expect(toolNames).toContain('create_assistant');
|
|
42
|
-
expect(toolNames).toContain('get_assistant');
|
|
43
|
-
expect(toolNames).toContain('list_phone_numbers');
|
|
44
|
-
expect(toolNames).toContain('get_phone_number');
|
|
45
|
-
expect(toolNames).toContain('list_calls');
|
|
46
|
-
expect(toolNames).toContain('create_call');
|
|
47
|
-
expect(toolNames).toContain('get_call');
|
|
48
|
-
});
|
|
49
|
-
describe('Assistant Tools', () => {
|
|
50
|
-
test('should list all assistants', async () => {
|
|
51
|
-
console.log('Calling list_assistants tool...');
|
|
52
|
-
const rawResult = await mcpClient.callTool({
|
|
53
|
-
name: 'list_assistants',
|
|
54
|
-
arguments: {},
|
|
55
|
-
});
|
|
56
|
-
const result = parseToolResponse(rawResult);
|
|
57
|
-
expect(result).toBeDefined();
|
|
58
|
-
if (Array.isArray(result)) {
|
|
59
|
-
console.log(`Received ${result.length} assistants in array form`);
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
console.log(`Received assistants in non-array form:`, result);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
test('should create a new assistant', async () => {
|
|
66
|
-
console.log('Calling create_assistant tool...');
|
|
67
|
-
const assistantData = {
|
|
68
|
-
name: `Test Assistant ${Date.now()}`,
|
|
69
|
-
instructions: 'You are a helpful test assistant',
|
|
70
|
-
llm: {
|
|
71
|
-
provider: 'openai',
|
|
72
|
-
model: 'gpt-4o',
|
|
73
|
-
},
|
|
74
|
-
transcriber: {
|
|
75
|
-
provider: 'deepgram',
|
|
76
|
-
model: 'nova-3',
|
|
77
|
-
},
|
|
78
|
-
voice: {
|
|
79
|
-
provider: '11labs',
|
|
80
|
-
model: 'eleven_turbo_v2_5',
|
|
81
|
-
voiceId: 'sarah',
|
|
82
|
-
},
|
|
83
|
-
firstMessage: "Hello, I'm your vapi assistant.",
|
|
84
|
-
};
|
|
85
|
-
const rawResult = await mcpClient.callTool({
|
|
86
|
-
name: 'create_assistant',
|
|
87
|
-
arguments: assistantData,
|
|
88
|
-
});
|
|
89
|
-
const result = parseToolResponse(rawResult);
|
|
90
|
-
expect(result).toBeDefined();
|
|
91
|
-
expect(result.id).toBeDefined();
|
|
92
|
-
expect(result.name).toBe(assistantData.name);
|
|
93
|
-
expect(result.llm.provider).toBe(assistantData.llm.provider);
|
|
94
|
-
expect(result.llm.model).toBe(assistantData.llm.model);
|
|
95
|
-
console.log(`Successfully created assistant with ID: ${result.id}`);
|
|
96
|
-
});
|
|
97
|
-
test('should get an assistant by ID', async () => {
|
|
98
|
-
console.log('Listing assistants to get the first one...');
|
|
99
|
-
const rawListResult = await mcpClient.callTool({
|
|
100
|
-
name: 'list_assistants',
|
|
101
|
-
arguments: {},
|
|
102
|
-
});
|
|
103
|
-
const listResult = parseToolResponse(rawListResult);
|
|
104
|
-
expect(listResult).toBeDefined();
|
|
105
|
-
expect(Array.isArray(listResult)).toBe(true);
|
|
106
|
-
if (listResult.length === 0) {
|
|
107
|
-
console.log('No assistants found, skipping get_assistant test.');
|
|
108
|
-
// Optionally, you could fail the test here or create an assistant first
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
const firstAssistant = listResult[0];
|
|
112
|
-
expect(firstAssistant.id).toBeDefined();
|
|
113
|
-
const assistantId = firstAssistant.id;
|
|
114
|
-
const assistantName = firstAssistant.name;
|
|
115
|
-
console.log(`Attempting to fetch assistant with ID: ${assistantId} (Name: ${assistantName})`);
|
|
116
|
-
const rawGetResult = await mcpClient.callTool({
|
|
117
|
-
name: 'get_assistant',
|
|
118
|
-
arguments: { assistantId: assistantId },
|
|
119
|
-
});
|
|
120
|
-
const getResult = parseToolResponse(rawGetResult);
|
|
121
|
-
expect(getResult).toBeDefined();
|
|
122
|
-
expect(getResult.id).toBe(assistantId);
|
|
123
|
-
expect(getResult.name).toBe(assistantName); // Verify name matches too
|
|
124
|
-
console.log(`Successfully fetched assistant with ID: ${getResult.id}`);
|
|
125
|
-
});
|
|
126
|
-
test('should handle invalid assistant ID', async () => {
|
|
127
|
-
const invalidId = 'non-existent-assistant-id-' + Date.now();
|
|
128
|
-
console.log(`Testing error handling with invalid assistant ID: ${invalidId}`);
|
|
129
|
-
try {
|
|
130
|
-
const rawResult = await mcpClient.callTool({
|
|
131
|
-
name: 'get_assistant',
|
|
132
|
-
arguments: { assistantId: invalidId },
|
|
133
|
-
});
|
|
134
|
-
const result = parseToolResponse(rawResult);
|
|
135
|
-
// Check for error in the result
|
|
136
|
-
if (result.error ||
|
|
137
|
-
(typeof result === 'string' &&
|
|
138
|
-
(result.includes('Error') || result.includes('error')))) {
|
|
139
|
-
// Test passed - we got an error response
|
|
140
|
-
expect(true).toBe(true);
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
// If we somehow got a successful result, fail the test
|
|
144
|
-
expect(result).toContain('error');
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
catch (error) {
|
|
148
|
-
// This is also acceptable - the API might throw instead of returning error
|
|
149
|
-
expect(error).toBeDefined();
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
describe('Phone Number Tools', () => {
|
|
154
|
-
test('should list all phone numbers', async () => {
|
|
155
|
-
console.log('Calling list_phone_numbers tool...');
|
|
156
|
-
const rawResult = await mcpClient.callTool({
|
|
157
|
-
name: 'list_phone_numbers',
|
|
158
|
-
arguments: {},
|
|
159
|
-
});
|
|
160
|
-
const result = parseToolResponse(rawResult);
|
|
161
|
-
expect(result).toBeDefined();
|
|
162
|
-
if (Array.isArray(result)) {
|
|
163
|
-
console.log(`Received ${result.length} phone numbers in array form`);
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
console.log(`Received phone numbers in non-array form:`, result);
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
test('should handle invalid phone number ID', async () => {
|
|
170
|
-
const invalidId = 'non-existent-phone-number-id-' + Date.now();
|
|
171
|
-
console.log(`Testing error handling with invalid phone number ID: ${invalidId}`);
|
|
172
|
-
try {
|
|
173
|
-
const rawResult = await mcpClient.callTool({
|
|
174
|
-
name: 'get_phone_number',
|
|
175
|
-
arguments: { phoneNumberId: invalidId },
|
|
176
|
-
});
|
|
177
|
-
const result = parseToolResponse(rawResult);
|
|
178
|
-
// Check for error in the result
|
|
179
|
-
if (result.error ||
|
|
180
|
-
(typeof result === 'string' &&
|
|
181
|
-
(result.includes('Error') || result.includes('error')))) {
|
|
182
|
-
// Test passed - we got an error response
|
|
183
|
-
expect(true).toBe(true);
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
// If we somehow got a successful result, fail the test
|
|
187
|
-
expect(result).toContain('error');
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
catch (error) {
|
|
191
|
-
// This is also acceptable - the API might throw instead of returning error
|
|
192
|
-
expect(error).toBeDefined();
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
describe('Call Tools', () => {
|
|
197
|
-
test('should list all calls', async () => {
|
|
198
|
-
console.log('Calling list_calls tool...');
|
|
199
|
-
const rawResult = await mcpClient.callTool({
|
|
200
|
-
name: 'list_calls',
|
|
201
|
-
arguments: {},
|
|
202
|
-
});
|
|
203
|
-
const result = parseToolResponse(rawResult);
|
|
204
|
-
expect(result).toBeDefined();
|
|
205
|
-
if (Array.isArray(result)) {
|
|
206
|
-
console.log(`Received ${result.length} calls in array form`);
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
console.log(`Received calls in non-array form:`, result);
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
test('should handle invalid call ID', async () => {
|
|
213
|
-
const invalidId = 'non-existent-call-id-' + Date.now();
|
|
214
|
-
console.log(`Testing error handling with invalid call ID: ${invalidId}`);
|
|
215
|
-
try {
|
|
216
|
-
const rawResult = await mcpClient.callTool({
|
|
217
|
-
name: 'get_call',
|
|
218
|
-
arguments: { callId: invalidId },
|
|
219
|
-
});
|
|
220
|
-
const result = parseToolResponse(rawResult);
|
|
221
|
-
// Check for error in the result
|
|
222
|
-
if (result.error ||
|
|
223
|
-
(typeof result === 'string' &&
|
|
224
|
-
(result.includes('Error') || result.includes('error')))) {
|
|
225
|
-
// Test passed - we got an error response
|
|
226
|
-
expect(true).toBe(true);
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
// If we somehow got a successful result, fail the test
|
|
230
|
-
expect(result).toContain('error');
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
catch (error) {
|
|
234
|
-
// This is also acceptable - the API might throw instead of returning error
|
|
235
|
-
expect(error).toBeDefined();
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
});
|