@vapi-ai/mcp-server 0.0.9 → 0.0.11

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 CHANGED
@@ -2,33 +2,32 @@
2
2
 
3
3
  [![smithery badge](https://smithery.ai/badge/@VapiAI/vapi-mcp-server)](https://smithery.ai/server/@VapiAI/vapi-mcp-server)
4
4
 
5
- The Vapi [Model Context Protocol](https://modelcontextprotocol.com/) server allows you to integrate with Vapi APIs through function calling.
5
+ Build AI voice assistants and phone agents with [Vapi](https://vapi.ai) using the [Model Context Protocol](https://modelcontextprotocol.com/).
6
6
 
7
7
  <a href="https://glama.ai/mcp/servers/@VapiAI/mcp-server">
8
8
  <img width="380" height="200" src="https://glama.ai/mcp/servers/@VapiAI/mcp-server/badge" alt="Vapi Server MCP server" />
9
9
  </a>
10
10
 
11
- ## Claude Desktop Setup
11
+ ## Setup
12
12
 
13
- 1. Open `Claude Desktop` and press `CMD + ,` to go to `Settings`.
14
- 2. Click on the `Developer` tab.
15
- 3. Click on the `Edit Config` button.
16
- 4. This will open the `claude_desktop_config.json` file in your file explorer.
17
- 5. Get your Vapi API key from the Vapi dashboard (<https://dashboard.vapi.ai/org/api-keys>).
18
- 6. Add the following to your `claude_desktop_config.json` file. See [here](https://modelcontextprotocol.io/quickstart/user) for more details.
19
- 7. Restart the Claude Desktop after editing the config file.
13
+ The MCP server requires a Vapi API key. Get one from the [Vapi dashboard](https://dashboard.vapi.ai/org/api-keys).
20
14
 
21
- ### Local Configuration
15
+ ### Local Server (stdio)
16
+
17
+ Configure any MCP client that supports local stdio servers to run:
18
+
19
+ ```text
20
+ npx -y @vapi-ai/mcp-server
21
+ ```
22
+
23
+ Set `VAPI_TOKEN` in the server environment. MCP client configuration formats vary, but the server definition generally looks like this:
22
24
 
23
25
  ```json
24
26
  {
25
27
  "mcpServers": {
26
- "vapi-mcp-server": {
28
+ "vapi": {
27
29
  "command": "npx",
28
- "args": [
29
- "-y",
30
- "@vapi-ai/mcp-server"
31
- ],
30
+ "args": ["-y", "@vapi-ai/mcp-server"],
32
31
  "env": {
33
32
  "VAPI_TOKEN": "<your_vapi_token>"
34
33
  }
@@ -37,12 +36,29 @@ The Vapi [Model Context Protocol](https://modelcontextprotocol.com/) server allo
37
36
  }
38
37
  ```
39
38
 
40
- ### Remote Configuration
39
+ ### Remote Server (Streamable HTTP)
40
+
41
+ Clients that support remote MCP servers can connect directly:
42
+
43
+ - URL: `https://mcp.vapi.ai/mcp`
44
+ - Header: `Authorization: Bearer your_vapi_api_key_here`
45
+
46
+ ### Client-Specific Examples
47
+
48
+ #### Claude Code
49
+
50
+ ```bash
51
+ claude mcp add -e VAPI_TOKEN=your_vapi_token vapi -- npx -y @vapi-ai/mcp-server
52
+ ```
53
+
54
+ #### Claude Desktop
55
+
56
+ Use the local server configuration above in the Claude Desktop configuration file. To connect to the hosted server through an stdio bridge instead:
41
57
 
42
58
  ```json
43
59
  {
44
60
  "mcpServers": {
45
- "vapi-mcp": {
61
+ "vapi": {
46
62
  "command": "npx",
47
63
  "args": [
48
64
  "mcp-remote",
@@ -58,40 +74,50 @@ The Vapi [Model Context Protocol](https://modelcontextprotocol.com/) server allo
58
74
  }
59
75
  ```
60
76
 
61
- ### Example Usage with Claude Desktop
77
+ ### Optional Agent Skill
62
78
 
63
- 1. Create or import a phone number using the Vapi dashboard (<https://dashboard.vapi.ai/phone-numbers>).
64
- 2. Create a new assistant using the existing 'Appointment Scheduler' template in the Vapi dashboard (<https://dashboard.vapi.ai/assistants>).
65
- 3. Make sure to configure Claude Desktop to use the Vapi MCP server and restart the Claude Desktop app.
66
- 4. Ask Claude to initiate or schedule a call. See examples below:
79
+ The [`skill`](./skill) directory contains reusable instructions for AI coding agents that support Agent Skills. Install it using your host's skill installation process.
67
80
 
68
- **Example 1:** Request an immediate call
81
+ For Claude Code:
69
82
 
70
- ```md
71
- I'd like to speak with my ShopHelper assistant to talk about my recent order. Can you have it call me at +1234567890?
83
+ ```bash
84
+ mkdir -p ~/.claude/skills/vapi
85
+ curl -o ~/.claude/skills/vapi/SKILL.md https://raw.githubusercontent.com/VapiAI/mcp-server/main/skill/SKILL.md
72
86
  ```
73
87
 
74
- **Example 2:** Schedule a future call
88
+ ---
89
+
90
+ ## Example Usage
75
91
 
76
- ```md
77
- I need to schedule a call with Mary assistant for next Tuesday at 3:00 PM. My phone number is +1555123456.
92
+ ### Create a Voice Assistant
93
+
94
+ Ask your MCP-enabled agent:
95
+ ```
96
+ I want to build a voice assistant that can schedule appointments
78
97
  ```
79
98
 
80
- **Example 3:** Make a call with dynamic variables
99
+ ### Make an Outbound Call
81
100
 
82
- ```md
83
- I want to call +1234567890 with my appointment reminder assistant. Use these details:
101
+ ```
102
+ Call +1234567890 using my appointment reminder assistant with these details:
84
103
  - Customer name: Sarah Johnson
85
104
  - Appointment date: March 25th
86
105
  - Appointment time: 2:30 PM
87
- - Doctor name: Dr. Smith
88
106
  ```
89
107
 
108
+ ### Schedule a Future Call
109
+
110
+ ```
111
+ Schedule a call with my support assistant for next Tuesday at 3:00 PM to +1555123456
112
+ ```
113
+
114
+ ---
115
+
90
116
  ## Using Variable Values in Assistant Prompts
91
117
 
92
- The `create_call` action supports passing dynamic variables through `assistantOverrides.variableValues`. These variables can be used in your assistant's prompts using double curly braces: `{{variableName}}`.
118
+ The `create_call` action supports passing dynamic variables through `assistantOverrides.variableValues`. Use double curly braces in your assistant's prompts: `{{variableName}}`.
93
119
 
94
- ### Example Assistant Prompt with Variables
120
+ ### Example Prompt with Variables
95
121
 
96
122
  ```
97
123
  Hello {{customerName}}, this is a reminder about your appointment on {{appointmentDate}} at {{appointmentTime}} with {{doctorName}}.
@@ -99,7 +125,7 @@ Hello {{customerName}}, this is a reminder about your appointment on {{appointme
99
125
 
100
126
  ### Default Variables
101
127
 
102
- The following variables are automatically available (no need to pass in variableValues):
128
+ These are automatically available (no need to pass):
103
129
 
104
130
  - `{{now}}` - Current date and time (UTC)
105
131
  - `{{date}}` - Current date (UTC)
@@ -109,29 +135,58 @@ The following variables are automatically available (no need to pass in variable
109
135
  - `{{year}}` - Current year (UTC)
110
136
  - `{{customer.number}}` - Customer's phone number
111
137
 
112
- For more details on default variables and advanced date/time formatting, see the [official Vapi documentation](https://docs.vapi.ai/assistants/dynamic-variables#default-variables).
138
+ See [Vapi documentation](https://docs.vapi.ai/assistants/dynamic-variables#default-variables) for advanced date/time formatting.
113
139
 
114
- ## Remote MCP
140
+ ---
115
141
 
116
- To connect to Vapi's MCP server remotely:
142
+ ## Remote MCP Server
117
143
 
118
- ### Streamable HTTP (Recommended)
144
+ Connect to Vapi's hosted MCP server from any MCP client:
119
145
 
120
- The default and recommended way to connect is via Streamable HTTP Transport:
146
+ ### Streamable HTTP (Recommended)
121
147
 
122
- - Connect to `https://mcp.vapi.ai/mcp` from any MCP client using Streamable HTTP Transport
123
- - Include your Vapi API key as a bearer token in the request headers
124
- - Example header: `Authorization: Bearer your_vapi_api_key_here`
148
+ - URL: `https://mcp.vapi.ai/mcp`
149
+ - Header: `Authorization: Bearer your_vapi_api_key_here`
125
150
 
126
151
  ### SSE (Deprecated)
127
152
 
128
- Server-Sent Events (SSE) Transport is still supported but deprecated:
153
+ - URL: `https://mcp.vapi.ai/sse`
154
+ - Header: `Authorization: Bearer your_vapi_api_key_here`
155
+
156
+ ---
157
+
158
+ ## Available Tools
159
+
160
+ ### Assistants
161
+ | Tool | Description |
162
+ |------|-------------|
163
+ | `list_assistants` | List all assistants |
164
+ | `get_assistant` | Get assistant by ID |
165
+ | `create_assistant` | Create new assistant |
166
+ | `update_assistant` | Update assistant |
129
167
 
130
- - Connect to `https://mcp.vapi.ai/sse` from any MCP client using SSE Transport
131
- - Include your Vapi API key as a bearer token in the request headers
132
- - Example header: `Authorization: Bearer your_vapi_api_key_here`
168
+ ### Calls
169
+ | Tool | Description |
170
+ |------|-------------|
171
+ | `list_calls` | List call history |
172
+ | `get_call` | Get call details |
173
+ | `create_call` | Start outbound call (immediate or scheduled) |
133
174
 
134
- This connection allows you to access Vapi's functionality remotely without running a local server.
175
+ ### Phone Numbers
176
+ | Tool | Description |
177
+ |------|-------------|
178
+ | `list_phone_numbers` | List phone numbers |
179
+ | `get_phone_number` | Get phone number details |
180
+
181
+ ### Tools (Function Calling)
182
+ | Tool | Description |
183
+ |------|-------------|
184
+ | `list_tools` | List custom tools |
185
+ | `get_tool` | Get tool details |
186
+ | `create_tool` | Create tool for API integration |
187
+ | `update_tool` | Update tool |
188
+
189
+ ---
135
190
 
136
191
  ## Development
137
192
 
@@ -139,101 +194,64 @@ This connection allows you to access Vapi's functionality remotely without runni
139
194
  # Install dependencies
140
195
  npm install
141
196
 
142
- # Build the server
197
+ # Build
143
198
  npm run build
144
199
 
145
- # Use inspector to test the server
200
+ # Test with MCP inspector
146
201
  npm run inspector
147
202
  ```
148
203
 
149
- Update your `claude_desktop_config.json` to use the local server.
204
+ ### Local Development Config
150
205
 
151
206
  ```json
152
207
  {
153
208
  "mcpServers": {
154
209
  "vapi-local": {
155
210
  "command": "node",
156
- "args": [
157
- "<path_to_vapi_mcp_server>/dist/index.js"
158
- ],
211
+ "args": ["<path>/dist/index.js"],
159
212
  "env": {
160
213
  "VAPI_TOKEN": "<your_vapi_token>"
161
214
  }
162
- },
215
+ }
163
216
  }
164
217
  }
165
218
  ```
166
219
 
167
220
  ### Testing
168
221
 
169
- The project has two types of tests:
222
+ ```bash
223
+ # Safe default suite (build, mocked execution, contract, and stdio compatibility)
224
+ npm test
170
225
 
171
- #### Unit Tests
226
+ # Unit tests (mocked public tool execution and catalog contract)
227
+ npm run test:unit
172
228
 
173
- Unit tests use mocks to test the MCP server without making actual API calls to Vapi.
229
+ # Documentation/tool-catalog consistency lint
230
+ npm run test:docs
174
231
 
175
- ```bash
176
- # Run unit tests
177
- npm run test:unit
178
- ```
232
+ # Full TypeScript check (production and test code)
233
+ npm run typecheck
179
234
 
180
- #### End-to-End Tests
235
+ # Build and run local stdio protocol compatibility tests (no Vapi API calls)
236
+ npm run test:stdio
181
237
 
182
- E2E tests run the full MCP server with actual API calls to Vapi.
238
+ # Pack, install, and launch the package from a clean temporary consumer
239
+ npm run test:package
183
240
 
184
- ```bash
185
- # Set your Vapi API token
241
+ # Live read-only API tests
186
242
  export VAPI_TOKEN=your_token_here
243
+ npm run test:live:readonly
187
244
 
188
- # Run E2E tests
189
- npm run test:e2e
245
+ # Live mutating tests (creates and cleans up disposable assistants and tools)
246
+ export VAPI_TOKEN=your_test_org_token_here
247
+ npm run test:live:mutating
190
248
  ```
191
249
 
192
- Note: E2E tests require a valid Vapi API token to be set in the environment.
193
-
194
- #### Running All Tests
195
-
196
- To run all tests at once:
197
-
198
- ```bash
199
- npm test
200
- ```
250
+ ---
201
251
 
202
252
  ## References
203
253
 
204
- - [VAPI Remote MCP Server](https://mcp.vapi.ai/)
205
- - [VAPI MCP Tool](https://docs.vapi.ai/tools/mcp)
206
- - [VAPI MCP Server SDK](https://docs.vapi.ai/sdk/mcp-server)
254
+ - [Vapi Documentation](https://docs.vapi.ai)
255
+ - [Vapi Dashboard](https://dashboard.vapi.ai)
256
+ - [Vapi Remote MCP Server](https://mcp.vapi.ai/)
207
257
  - [Model Context Protocol](https://modelcontextprotocol.com/)
208
- - [Claude Desktop](https://modelcontextprotocol.io/quickstart/user)
209
-
210
- ## Supported Actions
211
-
212
- The Vapi MCP Server provides the following tools for integration:
213
-
214
- ### Assistant Tools
215
-
216
- - `list_assistants`: Lists all Vapi assistants
217
- - `create_assistant`: Creates a new Vapi assistant
218
- - `update_assistant`: Updates an existing Vapi assistant
219
- - `get_assistant`: Gets a Vapi assistant by ID
220
-
221
- ### Call Tools
222
-
223
- - `list_calls`: Lists all Vapi calls
224
- - `create_call`: Creates an outbound call with support for:
225
- - Immediate or scheduled calls
226
- - Dynamic variable values through `assistantOverrides`
227
- - `get_call`: Gets details of a specific call
228
-
229
- > **Note:** The `create_call` action supports scheduling calls for immediate execution or for a future time. You can also pass dynamic variables using `assistantOverrides.variableValues` to personalize assistant messages.
230
-
231
- ### Phone Number Tools
232
-
233
- - `list_phone_numbers`: Lists all Vapi phone numbers
234
- - `get_phone_number`: Gets details of a specific phone number
235
-
236
- ### Vapi Tools
237
-
238
- - `list_tools`: Lists all Vapi tools
239
- - `get_tool`: Gets details of a specific tool
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQpE,iBAAS,eAAe,cAiBvB;AA8BD,OAAO,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAYpE,iBAAS,eAAe,cAgBvB;AAgCD,OAAO,EAAE,eAAe,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -1,10 +1,12 @@
1
1
  #!/usr/bin/env node
2
+ import { readFileSync } from 'node:fs';
2
3
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
4
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
5
  import { registerAllTools } from './tools/index.js';
5
6
  import { createVapiClient } from './client.js';
6
7
  import dotenv from 'dotenv';
7
8
  dotenv.config();
9
+ const packageMetadata = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
8
10
  function createMcpServer() {
9
11
  const vapiToken = process.env.VAPI_TOKEN;
10
12
  if (!vapiToken) {
@@ -13,8 +15,7 @@ function createMcpServer() {
13
15
  const vapiClient = createVapiClient(vapiToken);
14
16
  const mcpServer = new McpServer({
15
17
  name: 'Vapi MCP',
16
- version: '0.1.0',
17
- capabilities: [],
18
+ version: packageMetadata.version,
18
19
  });
19
20
  registerAllTools(mcpServer, vapiClient);
20
21
  return mcpServer;
@@ -27,6 +28,7 @@ async function main() {
27
28
  setupShutdownHandler(mcpServer);
28
29
  }
29
30
  catch (err) {
31
+ console.error('Failed to start MCP server:', err);
30
32
  process.exit(1);
31
33
  }
32
34
  }
@@ -42,6 +44,7 @@ function setupShutdownHandler(mcpServer) {
42
44
  });
43
45
  }
44
46
  main().catch((err) => {
47
+ console.error('Fatal error:', err);
45
48
  process.exit(1);
46
49
  });
47
50
  export { createMcpServer };
@@ -167,11 +167,11 @@ export declare const CreateAssistantInputSchema: z.ZodObject<{
167
167
  firstMessage?: string | undefined;
168
168
  firstMessageMode?: "assistant-speaks-first" | "assistant-waits-for-user" | "assistant-speaks-first-with-model-generated-message" | undefined;
169
169
  }>;
170
- export declare const AssistantOutputSchema: z.ZodObject<z.objectUtil.extendShape<{
170
+ export declare const AssistantOutputSchema: z.ZodObject<{
171
171
  id: z.ZodString;
172
172
  createdAt: z.ZodString;
173
173
  updatedAt: z.ZodString;
174
- }, {
174
+ } & {
175
175
  name: z.ZodString;
176
176
  llm: z.ZodObject<{
177
177
  provider: z.ZodString;
@@ -207,7 +207,7 @@ export declare const AssistantOutputSchema: z.ZodObject<z.objectUtil.extendShape
207
207
  model: string;
208
208
  }>;
209
209
  toolIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
210
- }>, "strip", z.ZodTypeAny, {
210
+ }, "strip", z.ZodTypeAny, {
211
211
  id: string;
212
212
  createdAt: string;
213
213
  updatedAt: string;
@@ -406,11 +406,11 @@ export declare const CallInputSchema: z.ZodObject<{
406
406
  variableValues?: Record<string, any> | undefined;
407
407
  } | undefined;
408
408
  }>;
409
- export declare const CallOutputSchema: z.ZodObject<z.objectUtil.extendShape<{
409
+ export declare const CallOutputSchema: z.ZodObject<{
410
410
  id: z.ZodString;
411
411
  createdAt: z.ZodString;
412
412
  updatedAt: z.ZodString;
413
- }, {
413
+ } & {
414
414
  status: z.ZodString;
415
415
  endedReason: z.ZodOptional<z.ZodString>;
416
416
  assistantId: z.ZodOptional<z.ZodString>;
@@ -423,7 +423,7 @@ export declare const CallOutputSchema: z.ZodObject<z.objectUtil.extendShape<{
423
423
  number: string;
424
424
  }>>;
425
425
  scheduledAt: z.ZodOptional<z.ZodString>;
426
- }>, "strip", z.ZodTypeAny, {
426
+ }, "strip", z.ZodTypeAny, {
427
427
  status: string;
428
428
  id: string;
429
429
  createdAt: string;
@@ -462,11 +462,11 @@ export declare const GetPhoneNumberInputSchema: z.ZodObject<{
462
462
  }, {
463
463
  phoneNumberId: string;
464
464
  }>;
465
- export declare const PhoneNumberOutputSchema: z.ZodObject<z.objectUtil.extendShape<{
465
+ export declare const PhoneNumberOutputSchema: z.ZodObject<{
466
466
  id: z.ZodString;
467
467
  createdAt: z.ZodString;
468
468
  updatedAt: z.ZodString;
469
- }, {
469
+ } & {
470
470
  name: z.ZodOptional<z.ZodString>;
471
471
  phoneNumber: z.ZodString;
472
472
  status: z.ZodString;
@@ -480,7 +480,7 @@ export declare const PhoneNumberOutputSchema: z.ZodObject<z.objectUtil.extendSha
480
480
  voice?: boolean | undefined;
481
481
  sms?: boolean | undefined;
482
482
  }>>;
483
- }>, "strip", z.ZodTypeAny, {
483
+ }, "strip", z.ZodTypeAny, {
484
484
  status: string;
485
485
  id: string;
486
486
  createdAt: string;
@@ -510,7 +510,7 @@ export declare const GetToolInputSchema: z.ZodObject<{
510
510
  }, {
511
511
  toolId: string;
512
512
  }>;
513
- export declare const CreateToolInputSchema: z.ZodObject<z.objectUtil.extendShape<{
513
+ export declare const CreateToolInputSchema: z.ZodObject<{
514
514
  name: z.ZodOptional<z.ZodString>;
515
515
  description: z.ZodOptional<z.ZodString>;
516
516
  sms: z.ZodOptional<z.ZodObject<{
@@ -772,9 +772,9 @@ export declare const CreateToolInputSchema: z.ZodObject<z.objectUtil.extendShape
772
772
  } | undefined;
773
773
  timeoutSeconds?: number | undefined;
774
774
  }>>;
775
- }, {
775
+ } & {
776
776
  type: z.ZodEnum<["sms", "transferCall", "function", "apiRequest"]>;
777
- }>, "strip", z.ZodTypeAny, {
777
+ }, "strip", z.ZodTypeAny, {
778
778
  type: "function" | "sms" | "transferCall" | "apiRequest";
779
779
  function?: {
780
780
  parameters: {
@@ -893,7 +893,7 @@ export declare const CreateToolInputSchema: z.ZodObject<z.objectUtil.extendShape
893
893
  timeoutSeconds?: number | undefined;
894
894
  } | undefined;
895
895
  }>;
896
- export declare const UpdateToolInputSchema: z.ZodObject<z.objectUtil.extendShape<{
896
+ export declare const UpdateToolInputSchema: z.ZodObject<{
897
897
  name: z.ZodOptional<z.ZodString>;
898
898
  description: z.ZodOptional<z.ZodString>;
899
899
  sms: z.ZodOptional<z.ZodObject<{
@@ -1155,9 +1155,9 @@ export declare const UpdateToolInputSchema: z.ZodObject<z.objectUtil.extendShape
1155
1155
  } | undefined;
1156
1156
  timeoutSeconds?: number | undefined;
1157
1157
  }>>;
1158
- }, {
1158
+ } & {
1159
1159
  toolId: z.ZodString;
1160
- }>, "strip", z.ZodTypeAny, {
1160
+ }, "strip", z.ZodTypeAny, {
1161
1161
  toolId: string;
1162
1162
  function?: {
1163
1163
  parameters: {
@@ -1276,11 +1276,11 @@ export declare const UpdateToolInputSchema: z.ZodObject<z.objectUtil.extendShape
1276
1276
  timeoutSeconds?: number | undefined;
1277
1277
  } | undefined;
1278
1278
  }>;
1279
- export declare const ToolOutputSchema: z.ZodObject<z.objectUtil.extendShape<{
1279
+ export declare const ToolOutputSchema: z.ZodObject<{
1280
1280
  id: z.ZodString;
1281
1281
  createdAt: z.ZodString;
1282
1282
  updatedAt: z.ZodString;
1283
- }, {
1283
+ } & {
1284
1284
  type: z.ZodString;
1285
1285
  name: z.ZodString;
1286
1286
  description: z.ZodString;
@@ -1295,7 +1295,7 @@ export declare const ToolOutputSchema: z.ZodObject<z.objectUtil.extendShape<{
1295
1295
  url: string;
1296
1296
  headers?: Record<string, string> | undefined;
1297
1297
  }>;
1298
- }>, "strip", z.ZodTypeAny, {
1298
+ }, "strip", z.ZodTypeAny, {
1299
1299
  type: string;
1300
1300
  id: string;
1301
1301
  createdAt: string;
@@ -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,SA2EvB,CAAC"}
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"}
@@ -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.tool('list_assistants', 'Lists all Vapi assistants', {}, createToolHandler(async () => {
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);
@@ -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,SAgCvB,CAAC"}
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"}
@@ -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.tool('list_calls', 'Lists all Vapi calls', {}, createToolHandler(async () => {
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,SAsBvB,CAAC"}
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.tool('list_phone_numbers', 'Lists all Vapi phone numbers', {}, createToolHandler(async () => {
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
  }));
@@ -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,SA2CvB,CAAC"}
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"}
@@ -2,7 +2,10 @@ import { GetToolInputSchema, CreateToolInputSchema, UpdateToolInputSchema } from
2
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.tool('list_tools', 'Lists all Vapi tools', {}, createToolHandler(async () => {
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
  }));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vapi-ai/mcp-server",
3
- "description": "Vapi MCP Server",
4
- "version": "0.0.9",
3
+ "description": "Build AI voice assistants and phone agents with Vapi through the Model Context Protocol",
4
+ "version": "0.0.11",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "type": "module",
@@ -24,26 +24,37 @@
24
24
  "vapi",
25
25
  "mcp",
26
26
  "model-context-protocol",
27
+ "mcp-server",
28
+ "mcp-client",
27
29
  "ai",
28
- "claude",
30
+ "voice-agents",
29
31
  "voice-api",
30
32
  "tool-calling"
31
33
  ],
32
34
  "bin": {
33
- "@vapi-ai/mcp-server": "dist/index.js"
35
+ "mcp-server": "dist/index.js"
34
36
  },
35
37
  "scripts": {
36
38
  "prepare": "npm run build",
37
- "build": "tsc && shx chmod +x dist/*.js",
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
- "test": "NODE_OPTIONS=--experimental-vm-modules jest",
45
- "test:unit": "NODE_OPTIONS=--experimental-vm-modules jest src/tests/mcp-server-mock.test.ts",
46
- "test:e2e": "NODE_OPTIONS=--experimental-vm-modules jest src/tests/mcp-server-e2e.test.ts"
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": "^1.12.3",
65
+ "@modelcontextprotocol/sdk": "1.26.0",
55
66
  "@vapi-ai/server-sdk": "^0.5.2",
56
67
  "dotenv": "^16.4.7",
57
- "zod": "^3.24.2",
68
+ "zod": "^3.25.76",
58
69
  "zod-to-json-schema": "^3.24.5"
59
70
  },
60
71
  "devDependencies": {
61
- "@modelcontextprotocol/inspector": "^0.14.2",
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,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=mcp-server-e2e.test.d.ts.map
@@ -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
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=mcp-server-mock.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mcp-server-mock.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/mcp-server-mock.test.ts"],"names":[],"mappings":""}
@@ -1,34 +0,0 @@
1
- import { jest } from '@jest/globals';
2
- import { createMcpServer } from '../index.js';
3
- import { createMockVapiClient } from './mocks/vapi-client.mock.js';
4
- jest.mock('../client.js', () => ({
5
- createVapiClient: jest.fn(() => createMockVapiClient()),
6
- }));
7
- process.env.VAPI_TOKEN = 'test-mock-token';
8
- describe('MCP Server Unit Test (with mocks)', () => {
9
- let mcpServer;
10
- beforeAll(() => {
11
- console.log('Creating MCP server with mocked Vapi client...');
12
- mcpServer = createMcpServer();
13
- console.log('MCP server created successfully');
14
- });
15
- test('server should be initialized correctly', () => {
16
- expect(mcpServer).toBeDefined();
17
- expect(typeof mcpServer).toBe('object');
18
- expect(mcpServer.constructor.name).toBe('McpServer');
19
- expect(mcpServer.connect).toBeDefined();
20
- expect(typeof mcpServer.connect).toBe('function');
21
- });
22
- test('server should have required internal structures', () => {
23
- expect(mcpServer._registeredTools).toBeDefined();
24
- expect(typeof mcpServer._registeredTools).toBe('object');
25
- });
26
- test('server should have registered Vapi tools', () => {
27
- const registeredTools = Object.keys(mcpServer._registeredTools);
28
- expect(registeredTools.length).toBeGreaterThan(0);
29
- console.log('Found registered tools:', registeredTools);
30
- expect(registeredTools).toContain('list_assistants');
31
- expect(registeredTools).toContain('create_assistant');
32
- expect(registeredTools).toContain('get_assistant');
33
- });
34
- });
@@ -1,9 +0,0 @@
1
- export declare class MockVapiClient {
2
- assistants: {
3
- list: jest.Mock<any, any, any>;
4
- get: jest.Mock<any, any, any>;
5
- create: jest.Mock<any, any, any>;
6
- };
7
- }
8
- export declare const createMockVapiClient: () => MockVapiClient;
9
- //# sourceMappingURL=vapi-client.mock.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vapi-client.mock.d.ts","sourceRoot":"","sources":["../../../src/__tests__/mocks/vapi-client.mock.ts"],"names":[],"mappings":"AAAA,qBAAa,cAAc;IACzB,UAAU;;;;MAuCR;CACH;AAED,eAAO,MAAM,oBAAoB,sBAEhC,CAAC"}
@@ -1,43 +0,0 @@
1
- export class MockVapiClient {
2
- assistants = {
3
- list: jest.fn().mockResolvedValue([
4
- {
5
- id: 'mock-assistant-id-1',
6
- name: 'Mock Assistant 1',
7
- model: 'gpt-4',
8
- instructions: 'Example instructions',
9
- createdAt: new Date().toISOString(),
10
- updatedAt: new Date().toISOString(),
11
- },
12
- {
13
- id: 'mock-assistant-id-2',
14
- name: 'Mock Assistant 2',
15
- model: 'claude-3-opus',
16
- instructions: 'Another example',
17
- createdAt: new Date().toISOString(),
18
- updatedAt: new Date().toISOString(),
19
- },
20
- ]),
21
- get: jest.fn().mockImplementation((id) => {
22
- return Promise.resolve({
23
- id,
24
- name: `Mock Assistant ${id}`,
25
- model: 'gpt-4',
26
- instructions: 'Example instructions',
27
- createdAt: new Date().toISOString(),
28
- updatedAt: new Date().toISOString(),
29
- });
30
- }),
31
- create: jest.fn().mockImplementation((data) => {
32
- return Promise.resolve({
33
- id: 'new-mock-assistant-id',
34
- ...data,
35
- createdAt: new Date().toISOString(),
36
- updatedAt: new Date().toISOString(),
37
- });
38
- }),
39
- };
40
- }
41
- export const createMockVapiClient = () => {
42
- return new MockVapiClient();
43
- };