@vapi-ai/mcp-server 0.1.0 → 0.2.0
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 +95 -104
- package/dist/schemas/index.d.ts +3 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +4 -0
- package/dist/tools/annotations.d.ts +5 -0
- package/dist/tools/annotations.d.ts.map +1 -0
- package/dist/tools/annotations.js +14 -0
- package/dist/tools/api-schema.d.ts.map +1 -1
- package/dist/tools/api-schema.js +2 -0
- package/dist/tools/assistant.d.ts.map +1 -1
- package/dist/tools/assistant.js +10 -9
- package/dist/tools/call.d.ts.map +1 -1
- package/dist/tools/call.js +9 -7
- package/dist/tools/docs.d.ts.map +1 -1
- package/dist/tools/docs.js +2 -2
- package/dist/tools/list.d.ts +34 -0
- package/dist/tools/list.d.ts.map +1 -0
- package/dist/tools/list.js +47 -0
- package/dist/tools/phone-number.d.ts.map +1 -1
- package/dist/tools/phone-number.js +8 -7
- package/dist/tools/simulation.d.ts.map +1 -1
- package/dist/tools/simulation.js +13 -0
- package/dist/tools/skills.d.ts.map +1 -1
- package/dist/tools/skills.js +3 -3
- package/dist/tools/tool.d.ts.map +1 -1
- package/dist/tools/tool.js +10 -7
- package/dist/tools/validation.d.ts +2 -0
- package/dist/tools/validation.d.ts.map +1 -1
- package/dist/tools/validation.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,96 +1,46 @@
|
|
|
1
1
|
# Vapi MCP Server
|
|
2
2
|
|
|
3
|
-
Build AI voice assistants and phone agents with [Vapi](https://vapi.ai)
|
|
3
|
+
Build AI voice assistants and phone agents with [Vapi](https://vapi.ai) from any agent or app that speaks the [Model Context Protocol](https://modelcontextprotocol.com/).
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Connect to the hosted server
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**You don't need to clone, install or run anything.** Vapi hosts this server for you:
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- **URL:** `https://mcp.vapi.ai/mcp` (Streamable HTTP)
|
|
10
|
+
- **Header:** `Authorization: Bearer YOUR_VAPI_API_KEY`
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
Get an API key from the [Vapi dashboard](https://dashboard.vapi.ai/org/api-keys).
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
npx -y @vapi-ai/mcp-server
|
|
15
|
-
```
|
|
14
|
+
👉 **[Step-by-step setup for Codex, Claude Code, Cursor, VS Code, Hermes and Claude Desktop](https://docs.vapi.ai/sdk/mcp-server#connect-your-agent)**
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
The two most common setups:
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
{
|
|
21
|
-
"mcpServers": {
|
|
22
|
-
"vapi": {
|
|
23
|
-
"command": "npx",
|
|
24
|
-
"args": ["-y", "@vapi-ai/mcp-server"],
|
|
25
|
-
"env": {
|
|
26
|
-
"VAPI_TOKEN": "<your_vapi_token>"
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Remote Server (Streamable HTTP)
|
|
34
|
-
|
|
35
|
-
Clients that support remote MCP servers can connect directly:
|
|
36
|
-
|
|
37
|
-
- URL: `https://mcp.vapi.ai/mcp`
|
|
38
|
-
- Header: `Authorization: Bearer your_vapi_api_key_here`
|
|
39
|
-
|
|
40
|
-
### Client-Specific Examples
|
|
41
|
-
|
|
42
|
-
#### Claude Code
|
|
18
|
+
**Claude Code**
|
|
43
19
|
|
|
44
20
|
```bash
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
Use the local server configuration above in the Claude Desktop configuration file. To connect to the hosted server through an stdio bridge instead:
|
|
51
|
-
|
|
52
|
-
```json
|
|
53
|
-
{
|
|
54
|
-
"mcpServers": {
|
|
55
|
-
"vapi": {
|
|
56
|
-
"command": "npx",
|
|
57
|
-
"args": [
|
|
58
|
-
"mcp-remote",
|
|
59
|
-
"https://mcp.vapi.ai/mcp",
|
|
60
|
-
"--header",
|
|
61
|
-
"Authorization: Bearer ${VAPI_TOKEN}"
|
|
62
|
-
],
|
|
63
|
-
"env": {
|
|
64
|
-
"VAPI_TOKEN": "<your_vapi_token>"
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
21
|
+
export VAPI_API_KEY="YOUR_VAPI_API_KEY"
|
|
22
|
+
claude mcp add --transport http --scope user vapi \
|
|
23
|
+
https://mcp.vapi.ai/mcp \
|
|
24
|
+
--header 'Authorization: Bearer ${VAPI_API_KEY}'
|
|
69
25
|
```
|
|
70
26
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
The [`skill`](./skill) directory contains reusable instructions for AI coding agents that support Agent Skills. Install it using your host's skill installation process.
|
|
74
|
-
|
|
75
|
-
For Claude Code:
|
|
27
|
+
**Codex**
|
|
76
28
|
|
|
77
29
|
```bash
|
|
78
|
-
|
|
79
|
-
|
|
30
|
+
export VAPI_API_KEY="YOUR_VAPI_API_KEY"
|
|
31
|
+
codex mcp add vapi --url https://mcp.vapi.ai/mcp \
|
|
32
|
+
--bearer-token-env-var VAPI_API_KEY
|
|
80
33
|
```
|
|
81
34
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
## Example Usage
|
|
85
|
-
|
|
86
|
-
### Create a Voice Assistant
|
|
35
|
+
Keep `VAPI_API_KEY` set whenever you launch your agent. Start a new session, then try:
|
|
87
36
|
|
|
88
|
-
Ask your MCP-enabled agent:
|
|
89
37
|
```
|
|
90
|
-
|
|
38
|
+
List my Vapi assistants.
|
|
91
39
|
```
|
|
92
40
|
|
|
93
|
-
|
|
41
|
+
```
|
|
42
|
+
I want to build a voice assistant that can schedule appointments.
|
|
43
|
+
```
|
|
94
44
|
|
|
95
45
|
```
|
|
96
46
|
Call +1234567890 using my appointment reminder assistant with these details:
|
|
@@ -99,25 +49,34 @@ Call +1234567890 using my appointment reminder assistant with these details:
|
|
|
99
49
|
- Appointment time: 2:30 PM
|
|
100
50
|
```
|
|
101
51
|
|
|
102
|
-
### Schedule a Future Call
|
|
103
|
-
|
|
104
52
|
```
|
|
105
53
|
Schedule a call with my support assistant for next Tuesday at 3:00 PM to +1555123456
|
|
106
54
|
```
|
|
107
55
|
|
|
108
|
-
|
|
56
|
+
> The legacy SSE endpoint (`https://mcp.vapi.ai/sse`) is deprecated. Move existing remote configurations to `https://mcp.vapi.ai/mcp`.
|
|
57
|
+
|
|
58
|
+
### Optional: add the Vapi agent skill
|
|
59
|
+
|
|
60
|
+
The [`skill`](./skill) directory contains reusable instructions for AI coding agents that support Agent Skills. Install it using your host's skill installation process.
|
|
109
61
|
|
|
110
|
-
|
|
62
|
+
For Claude Code:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
mkdir -p ~/.claude/skills/vapi
|
|
66
|
+
curl -o ~/.claude/skills/vapi/SKILL.md https://raw.githubusercontent.com/VapiAI/mcp-server/main/skill/SKILL.md
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Using Variable Values in Assistant Prompts
|
|
111
70
|
|
|
112
71
|
The `create_call` action supports passing dynamic variables through `assistantOverrides.variableValues`. Use double curly braces in your assistant's prompts: `{{variableName}}`.
|
|
113
72
|
|
|
114
|
-
|
|
73
|
+
#### Example Prompt with Variables
|
|
115
74
|
|
|
116
75
|
```
|
|
117
76
|
Hello {{customerName}}, this is a reminder about your appointment on {{appointmentDate}} at {{appointmentTime}} with {{doctorName}}.
|
|
118
77
|
```
|
|
119
78
|
|
|
120
|
-
|
|
79
|
+
#### Default Variables
|
|
121
80
|
|
|
122
81
|
These are automatically available (no need to pass):
|
|
123
82
|
|
|
@@ -133,25 +92,59 @@ See [Vapi documentation](https://docs.vapi.ai/assistants/dynamic-variables#defau
|
|
|
133
92
|
|
|
134
93
|
---
|
|
135
94
|
|
|
136
|
-
##
|
|
95
|
+
## Oh, you're still here?
|
|
96
|
+
|
|
97
|
+
You must want to [leave feedback](#leave-feedback), [run a local server yourself](#run-a-local-server) or [peek under the hood](#peek-under-the-hood). Read on.
|
|
137
98
|
|
|
138
|
-
|
|
99
|
+
### Leave feedback
|
|
139
100
|
|
|
140
|
-
|
|
101
|
+
- **Found a bug or want a tool we don't have?** [Open an issue](https://github.com/VapiAI/mcp-server/issues).
|
|
102
|
+
- **Have a question or want to talk it through?** Join the [Vapi Discord](https://discord.gg/v5Ee6FhAZt).
|
|
103
|
+
- **Want to fix it yourself?** Pull requests are welcome. See [Development](#development) for how to build and test.
|
|
141
104
|
|
|
142
|
-
|
|
143
|
-
- Header: `Authorization: Bearer your_vapi_api_key_here`
|
|
105
|
+
### Run a local server
|
|
144
106
|
|
|
145
|
-
|
|
107
|
+
Run the server on your own machine if your client only supports local stdio servers or you want to try unreleased changes. It uses the same tools as the hosted server.
|
|
146
108
|
|
|
147
|
-
|
|
148
|
-
|
|
109
|
+
Configure your MCP client to run:
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
npx -y @vapi-ai/mcp-server
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Set `VAPI_TOKEN` to your Vapi API key in the server environment. MCP client configuration formats vary, but the server definition generally looks like this:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"mcpServers": {
|
|
120
|
+
"vapi": {
|
|
121
|
+
"command": "npx",
|
|
122
|
+
"args": ["-y", "@vapi-ai/mcp-server"],
|
|
123
|
+
"env": {
|
|
124
|
+
"VAPI_TOKEN": "<your_vapi_token>"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
For Claude Code:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
claude mcp add -e VAPI_TOKEN=your_vapi_token vapi -- npx -y @vapi-ai/mcp-server
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
For Claude Desktop, add the configuration above to the Claude Desktop configuration file.
|
|
138
|
+
|
|
139
|
+
To run a build from this repository instead, see [Local Development Config](#local-development-config).
|
|
149
140
|
|
|
150
141
|
---
|
|
151
142
|
|
|
152
|
-
##
|
|
143
|
+
## Peek under the hood
|
|
144
|
+
|
|
145
|
+
### Available Tools
|
|
153
146
|
|
|
154
|
-
|
|
147
|
+
#### Documentation
|
|
155
148
|
| Tool | Description |
|
|
156
149
|
|------|-------------|
|
|
157
150
|
| `ask_vapi_docs` | Query the Fern docs MCP for current documentation passages and source URLs |
|
|
@@ -169,36 +162,36 @@ at startup. Discovery through `tools/list` makes no network requests; upstream
|
|
|
169
162
|
failures are returned as tool errors. No extra MCP connection is needed. Do not
|
|
170
163
|
include secrets or private customer data in docs questions.
|
|
171
164
|
|
|
172
|
-
|
|
165
|
+
#### Assistants
|
|
173
166
|
| Tool | Description |
|
|
174
167
|
|------|-------------|
|
|
175
|
-
| `list_assistants` | List
|
|
168
|
+
| `list_assistants` | List assistants in pages of up to 10 |
|
|
176
169
|
| `get_assistant` | Get assistant by ID |
|
|
177
170
|
| `create_assistant` | Create new assistant |
|
|
178
171
|
| `update_assistant` | Update assistant |
|
|
179
172
|
|
|
180
|
-
|
|
173
|
+
#### Calls
|
|
181
174
|
| Tool | Description |
|
|
182
175
|
|------|-------------|
|
|
183
|
-
| `list_calls` | List call history |
|
|
176
|
+
| `list_calls` | List call history in pages of up to 10 |
|
|
184
177
|
| `get_call` | Get call details |
|
|
185
178
|
| `create_call` | Start outbound call (immediate or scheduled) |
|
|
186
179
|
|
|
187
|
-
|
|
180
|
+
#### Phone Numbers
|
|
188
181
|
| Tool | Description |
|
|
189
182
|
|------|-------------|
|
|
190
|
-
| `list_phone_numbers` | List phone numbers |
|
|
183
|
+
| `list_phone_numbers` | List phone numbers in pages of up to 10 |
|
|
191
184
|
| `get_phone_number` | Get phone number details |
|
|
192
185
|
|
|
193
|
-
|
|
186
|
+
#### Tools (Function Calling)
|
|
194
187
|
| Tool | Description |
|
|
195
188
|
|------|-------------|
|
|
196
|
-
| `list_tools` | List custom tools |
|
|
189
|
+
| `list_tools` | List custom tools in pages of up to 10 |
|
|
197
190
|
| `get_tool` | Get tool details |
|
|
198
191
|
| `create_tool` | Create tool for API integration |
|
|
199
192
|
| `update_tool` | Update tool |
|
|
200
193
|
|
|
201
|
-
|
|
194
|
+
#### Public Skills
|
|
202
195
|
| Tool | Description |
|
|
203
196
|
|------|-------------|
|
|
204
197
|
| `search_skills` | Search public Vapi skills by keywords; omit `query` to browse |
|
|
@@ -224,7 +217,7 @@ calls and send no Vapi credentials upstream. The server still requires
|
|
|
224
217
|
upstream failures are returned as tool errors. No GitHub token is needed for this
|
|
225
218
|
public content. GitHub's unauthenticated API rate limits apply.
|
|
226
219
|
|
|
227
|
-
|
|
220
|
+
#### Simulations
|
|
228
221
|
|
|
229
222
|
| Tool | Description |
|
|
230
223
|
|------|-------------|
|
|
@@ -247,9 +240,7 @@ metadata in `itemsMetadata` and `itemsTruncated: true` when more items exist.
|
|
|
247
240
|
Legacy array responses are also supported. Use `get_simulation_run_item` for
|
|
248
241
|
the full details of a known item.
|
|
249
242
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
## Development
|
|
243
|
+
### Development
|
|
253
244
|
|
|
254
245
|
```bash
|
|
255
246
|
# Install dependencies
|
|
@@ -262,7 +253,7 @@ npm run build
|
|
|
262
253
|
npm run inspector
|
|
263
254
|
```
|
|
264
255
|
|
|
265
|
-
|
|
256
|
+
#### Local Development Config
|
|
266
257
|
|
|
267
258
|
```json
|
|
268
259
|
{
|
|
@@ -278,7 +269,7 @@ npm run inspector
|
|
|
278
269
|
}
|
|
279
270
|
```
|
|
280
271
|
|
|
281
|
-
|
|
272
|
+
#### Testing
|
|
282
273
|
|
|
283
274
|
```bash
|
|
284
275
|
# Safe default suite (build, mocked execution, contract, and stdio compatibility)
|
|
@@ -308,7 +299,7 @@ export VAPI_TOKEN=your_test_org_token_here
|
|
|
308
299
|
npm run test:live:mutating
|
|
309
300
|
```
|
|
310
301
|
|
|
311
|
-
|
|
302
|
+
#### Input validation from OpenAPI
|
|
312
303
|
|
|
313
304
|
All 21 parameterized MCP tools use imported OpenAPI constraints through
|
|
314
305
|
Zod's experimental `z.fromJSONSchema()`, pinned to Zod 4.6.7. This covers
|
package/dist/schemas/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { VoiceInputSchema } from './assistant-openapi.js';
|
|
3
3
|
export declare const EmptyInputSchema: z.ZodObject<{}, z.core.$strip>;
|
|
4
|
+
export declare const ListInputSchema: z.ZodObject<{
|
|
5
|
+
before: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodISODateTime>>;
|
|
6
|
+
}, z.core.$strict>;
|
|
4
7
|
export declare const ModelProvider: {
|
|
5
8
|
readonly OpenAI: "openai";
|
|
6
9
|
readonly Anthropic: "anthropic";
|
|
@@ -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;AACxB,OAAO,EAAwD,gBAAgB,EAAsH,MAAM,wBAAwB,CAAC;AAEpO,eAAO,MAAM,gBAAgB,gCAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAwD,gBAAgB,EAAsH,MAAM,wBAAwB,CAAC;AAEpO,eAAO,MAAM,gBAAgB,gCAAe,CAAC;AAE7C,eAAO,MAAM,eAAe;;kBAK1B,CAAC;AAIH,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;AAa/E,eAAO,MAAM,WAAW;;;CAGvB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC,UAAU,CAAC,CAAC;AAE7E,eAAO,MAAM,aAAa;cACF,iBAAiB;;CAExC,CAAC;AAEF,eAAO,MAAM,mBAAmB;;;CAG/B,CAAC;AAEF,eAAO,MAAM,kBAAkB;;;;;;CAMrB,CAAC;AAIX,eAAO,MAAM,kBAAkB;;;;iBAI7B,CAAC;AAIH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA2BrC,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;iBAgBhC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;iBAElC,CAAC;AAEH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwBrC,CAAC;AAIH,eAAO,MAAM,eAAe;;;;;;;;;;iBA4B1B,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;iBAW3B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;iBAE7B,CAAC;AAIH,eAAO,MAAM,yBAAyB;;iBAEpC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;iBAUlC,CAAC;AAIH,eAAO,MAAM,kBAAkB;;iBAE7B,CAAC;AAqEH,eAAO,MAAM,qBAAqB;;;;;;;;;;kBAnEqB,QAAQ;oBAAU,MAAM;wBAAc,MAAM;uBAAa,MAAM;0BAAgB,MAAM;;kBAArF,QAAQ;oBAAU,MAAM;wBAAc,MAAM;uBAAa,MAAM;0BAAgB,MAAM;;;;;;;;;;;;;;;;;;;;;;;;iBAgFxI,CAAC;AAEL,eAAO,MAAM,qBAAqB;;;;;;;;;;kBAlFqB,QAAQ;oBAAU,MAAM;wBAAc,MAAM;uBAAa,MAAM;0BAAgB,MAAM;;kBAArF,QAAQ;oBAAU,MAAM;wBAAc,MAAM;uBAAa,MAAM;0BAAgB,MAAM;;;;;;;;;;;;;;;;;;;;;;;;iBAoF1I,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;iBAQ3B,CAAC;AAIH,eAAO,MAAM,uBAAuB;;;iBAalC,CAAC;AAEH,cAAc,iBAAiB,CAAC"}
|
package/dist/schemas/index.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { CreateAssistantNameSchema, UpdateAssistantNameSchema, VoiceInputSchema, TranscriberInputSchema, LLMInputSchema, apiField, apiObjectField, requiredToolConfigurations, functionRequiresName } from './assistant-openapi.js';
|
|
3
3
|
export const EmptyInputSchema = z.object({});
|
|
4
|
+
export const ListInputSchema = z.strictObject({
|
|
5
|
+
// Keep discovery compact while validating the full ISO timestamp at runtime.
|
|
6
|
+
before: z.string().meta({ format: 'date-time' }).pipe(z.iso.datetime({ offset: true })).optional().describe('Use pagination.nextBefore to continue.'),
|
|
7
|
+
});
|
|
4
8
|
// ===== Model Provider and Models =====
|
|
5
9
|
export const ModelProvider = {
|
|
6
10
|
OpenAI: 'openai',
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
export declare const readOnly: (title: string, openWorldHint?: boolean) => ToolAnnotations;
|
|
3
|
+
export declare const creates: (title: string, openWorldHint?: boolean) => ToolAnnotations;
|
|
4
|
+
export declare const updates: (title: string) => ToolAnnotations;
|
|
5
|
+
//# sourceMappingURL=annotations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"annotations.d.ts","sourceRoot":"","sources":["../../src/tools/annotations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAO1E,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,EAAE,uBAAqB,KAAG,eAE9D,CAAC;AAEH,eAAO,MAAM,OAAO,GAAI,OAAO,MAAM,EAAE,uBAAqB,KAAG,eAE7D,CAAC;AAGH,eAAO,MAAM,OAAO,GAAI,OAAO,MAAM,KAAG,eAEtC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// MCP tool annotations. Clients use these to label tools and decide when to ask
|
|
2
|
+
// for confirmation, and directory review requires a title and readOnlyHint.
|
|
3
|
+
// openWorldHint is false for calls into the Vapi API itself (a closed domain)
|
|
4
|
+
// and true when a tool reaches outside it, such as dialing a phone number.
|
|
5
|
+
export const readOnly = (title, openWorldHint = false) => ({
|
|
6
|
+
title, readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint,
|
|
7
|
+
});
|
|
8
|
+
export const creates = (title, openWorldHint = false) => ({
|
|
9
|
+
title, readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint,
|
|
10
|
+
});
|
|
11
|
+
// Updates overwrite fields on an existing resource, so clients should confirm them.
|
|
12
|
+
export const updates = (title) => ({
|
|
13
|
+
title, readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false,
|
|
14
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-schema.d.ts","sourceRoot":"","sources":["../../src/tools/api-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAmB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"api-schema.d.ts","sourceRoot":"","sources":["../../src/tools/api-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAmB,MAAM,qBAAqB,CAAC;AAmElE,eAAO,MAAM,sBAAsB,GACjC,QAAQ,SAAS,EACjB,YAAY,UAAU,SAwCvB,CAAC"}
|
package/dist/tools/api-schema.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { VapiEnvironment } from '@vapi-ai/server-sdk';
|
|
2
2
|
import { GetApiSchemaInputSchema } from '../schemas/index.js';
|
|
3
3
|
import { createToolHandler } from './utils.js';
|
|
4
|
+
import { readOnly } from './annotations.js';
|
|
4
5
|
// The OpenAPI spec is about 2 MB, so load it once per client and keep only
|
|
5
6
|
// its schemas. It is fetched through the client so it comes from the same
|
|
6
7
|
// API environment the other tools call.
|
|
@@ -47,6 +48,7 @@ export const registerApiSchemaTools = (server, vapiClient) => {
|
|
|
47
48
|
'References to other schemas are left as "#/components/schemas/<Name>" and listed in referencedSchemas, so look those up next if you need them. ' +
|
|
48
49
|
'Use it to find fields that other tools accept through additionalFields.',
|
|
49
50
|
inputSchema: GetApiSchemaInputSchema.shape,
|
|
51
|
+
annotations: readOnly('Get API Schema'),
|
|
50
52
|
}, createToolHandler(async (data) => {
|
|
51
53
|
const schemas = await loadSchemas(vapiClient);
|
|
52
54
|
if (data.name) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant.d.ts","sourceRoot":"","sources":["../../src/tools/assistant.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assistant.d.ts","sourceRoot":"","sources":["../../src/tools/assistant.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAQ,MAAM,qBAAqB,CAAC;AAevD,eAAO,MAAM,sBAAsB,GACjC,QAAQ,SAAS,EACjB,YAAY,UAAU,SA2FvB,CAAC"}
|
package/dist/tools/assistant.js
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import { registerValidatedTool } from './validation.js';
|
|
2
|
-
import {
|
|
2
|
+
import { creates, readOnly, updates } from './annotations.js';
|
|
3
|
+
import { ListInputSchema, CreateAssistantInputSchema, GetAssistantInputSchema, UpdateAssistantInputSchema, } from '../schemas/index.js';
|
|
3
4
|
import { transformAssistantInput, transformAssistantOutput, transformUpdateAssistantInput, } from '../transformers/index.js';
|
|
4
5
|
import { createToolHandler } from './utils.js';
|
|
6
|
+
import { createV1ListHandler } from './list.js';
|
|
5
7
|
export const registerAssistantTools = (server, vapiClient) => {
|
|
6
8
|
registerValidatedTool(server, 'list_assistants', {
|
|
7
|
-
description: 'Lists
|
|
8
|
-
inputSchema:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const assistants = await vapiClient.assistants.list({ limit: 10 });
|
|
12
|
-
// console.log('assistants', assistants);
|
|
13
|
-
return assistants.map(transformAssistantOutput);
|
|
14
|
-
}));
|
|
9
|
+
description: 'Lists up to 10 Vapi assistants',
|
|
10
|
+
inputSchema: ListInputSchema,
|
|
11
|
+
annotations: readOnly('List Assistants'),
|
|
12
|
+
}, createV1ListHandler(request => vapiClient.assistants.list(request), transformAssistantOutput));
|
|
15
13
|
registerValidatedTool(server, 'create_assistant', {
|
|
16
14
|
description: 'Creates a new Vapi assistant',
|
|
17
15
|
inputSchema: CreateAssistantInputSchema,
|
|
16
|
+
annotations: creates('Create Assistant'),
|
|
18
17
|
}, createToolHandler(async (data) => {
|
|
19
18
|
// console.log('create_assistant', data);
|
|
20
19
|
const createAssistantDto = transformAssistantInput(data);
|
|
@@ -24,6 +23,7 @@ export const registerAssistantTools = (server, vapiClient) => {
|
|
|
24
23
|
registerValidatedTool(server, 'get_assistant', {
|
|
25
24
|
description: 'Gets a Vapi assistant by ID',
|
|
26
25
|
inputSchema: GetAssistantInputSchema,
|
|
26
|
+
annotations: readOnly('Get Assistant'),
|
|
27
27
|
}, createToolHandler(async (data) => {
|
|
28
28
|
// console.log('get_assistant', data);
|
|
29
29
|
const assistantId = data.assistantId;
|
|
@@ -42,6 +42,7 @@ export const registerAssistantTools = (server, vapiClient) => {
|
|
|
42
42
|
registerValidatedTool(server, 'update_assistant', {
|
|
43
43
|
description: 'Updates an existing Vapi assistant',
|
|
44
44
|
inputSchema: UpdateAssistantInputSchema,
|
|
45
|
+
annotations: updates('Update Assistant'),
|
|
45
46
|
}, createToolHandler(async (data) => {
|
|
46
47
|
const assistantId = data.assistantId;
|
|
47
48
|
try {
|
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":"
|
|
1
|
+
{"version":3,"file":"call.d.ts","sourceRoot":"","sources":["../../src/tools/call.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAQ,MAAM,qBAAqB,CAAC;AAUvD,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,SAAS,EACjB,YAAY,UAAU,SAyCvB,CAAC"}
|
package/dist/tools/call.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { registerValidatedTool } from './validation.js';
|
|
2
|
-
import {
|
|
2
|
+
import { creates, readOnly } from './annotations.js';
|
|
3
|
+
import { ListInputSchema, CallInputSchema, GetCallInputSchema } from '../schemas/index.js';
|
|
3
4
|
import { transformCallInput, transformCallOutput, } from '../transformers/index.js';
|
|
4
5
|
import { createToolHandler } from './utils.js';
|
|
6
|
+
import { createV1ListHandler } from './list.js';
|
|
5
7
|
export const registerCallTools = (server, vapiClient) => {
|
|
6
8
|
registerValidatedTool(server, 'list_calls', {
|
|
7
|
-
description: 'Lists
|
|
8
|
-
inputSchema:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return calls.map(transformCallOutput);
|
|
12
|
-
}));
|
|
9
|
+
description: 'Lists up to 10 Vapi calls',
|
|
10
|
+
inputSchema: ListInputSchema,
|
|
11
|
+
annotations: readOnly('List Calls'),
|
|
12
|
+
}, createV1ListHandler(request => vapiClient.calls.list(request), transformCallOutput));
|
|
13
13
|
registerValidatedTool(server, 'create_call', {
|
|
14
14
|
description: 'Creates a outbound call',
|
|
15
15
|
inputSchema: CallInputSchema,
|
|
16
|
+
annotations: creates('Create Outbound Call', true),
|
|
16
17
|
}, createToolHandler(async (data) => {
|
|
17
18
|
const createCallDto = transformCallInput(data);
|
|
18
19
|
const call = await vapiClient.calls.create(createCallDto);
|
|
@@ -21,6 +22,7 @@ export const registerCallTools = (server, vapiClient) => {
|
|
|
21
22
|
registerValidatedTool(server, 'get_call', {
|
|
22
23
|
description: 'Gets details of a specific call',
|
|
23
24
|
inputSchema: GetCallInputSchema,
|
|
25
|
+
annotations: readOnly('Get Call'),
|
|
24
26
|
}, createToolHandler(async (data) => {
|
|
25
27
|
const call = await vapiClient.calls.get({ id: data.callId });
|
|
26
28
|
return transformCallOutput(call);
|
package/dist/tools/docs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/tools/docs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/tools/docs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAczE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,QAclD"}
|
package/dist/tools/docs.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { askVapiDocs } from '../knowledge/docs.js';
|
|
3
|
+
import { readOnly } from './annotations.js';
|
|
3
4
|
async function knowledgeResult(action) {
|
|
4
5
|
try {
|
|
5
6
|
return await action();
|
|
@@ -9,13 +10,12 @@ async function knowledgeResult(action) {
|
|
|
9
10
|
}
|
|
10
11
|
}
|
|
11
12
|
export function registerDocsTools(server) {
|
|
12
|
-
const annotations = { readOnlyHint: true, destructiveHint: false, openWorldHint: true };
|
|
13
13
|
server.registerTool('ask_vapi_docs', {
|
|
14
14
|
description: 'Ask about current Vapi documentation through the Fern docs MCP. Returns relevant documentation passages and source URLs; use them to answer the question.',
|
|
15
15
|
inputSchema: {
|
|
16
16
|
question: z.string().trim().min(1).max(4000).describe('A specific question about Vapi configuration, APIs, SDKs or troubleshooting. Send no API keys or private customer data.'),
|
|
17
17
|
topK: z.number().int().min(1).max(20).default(8).describe('Maximum number of relevant documentation passages.'),
|
|
18
|
-
}, annotations,
|
|
18
|
+
}, annotations: readOnly('Ask Vapi Docs', true),
|
|
19
19
|
}, ({ question, topK }, extra) => knowledgeResult(async () => {
|
|
20
20
|
const result = await askVapiDocs(question, topK, extra.signal);
|
|
21
21
|
// The upstream SDK also types legacy toolResult responses. Fern uses the
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare function v1ListPage<T extends {
|
|
2
|
+
createdAt: string;
|
|
3
|
+
}>(rows: T[]): {
|
|
4
|
+
results: T[];
|
|
5
|
+
pagination: {
|
|
6
|
+
warning?: string | undefined;
|
|
7
|
+
pageSize: number;
|
|
8
|
+
hasMore: boolean;
|
|
9
|
+
nextBefore: string | null;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export declare function createV1ListHandler<T extends {
|
|
13
|
+
createdAt: string;
|
|
14
|
+
}, R>(list: (request: {
|
|
15
|
+
limit: number;
|
|
16
|
+
createdAtLt?: string;
|
|
17
|
+
}) => Promise<T[]>, transform: (row: T) => R): (data: {
|
|
18
|
+
before?: string;
|
|
19
|
+
}) => Promise<import("./utils.js").ToolResponse | {
|
|
20
|
+
content: {
|
|
21
|
+
type: "text";
|
|
22
|
+
text: string;
|
|
23
|
+
}[];
|
|
24
|
+
structuredContent: {
|
|
25
|
+
results: R[];
|
|
26
|
+
pagination: {
|
|
27
|
+
warning?: string | undefined;
|
|
28
|
+
pageSize: number;
|
|
29
|
+
hasMore: boolean;
|
|
30
|
+
nextBefore: string | null;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
}>;
|
|
34
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/tools/list.ts"],"names":[],"mappings":"AAKA,wBAAgB,UAAU,CAAC,CAAC,SAAS;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,IAAI,EAAE,CAAC,EAAE;;;;;;;;EAoBpE;AAED,wBAAgB,mBAAmB,CAAC,CAAC,SAAS;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,EACpE,IAAI,EAAE,CAAC,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,EACxE,SAAS,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAEV,MAAM;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;GAoBxC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createErrorResponse, createSuccessResponse } from './utils.js';
|
|
2
|
+
const PAGE_SIZE = 10;
|
|
3
|
+
const TIE_WARNING = 'V1 cannot safely continue: more than 10 items share the same creation timestamp. No continuation is provided because it would skip items.';
|
|
4
|
+
export function v1ListPage(rows) {
|
|
5
|
+
let end = Math.min(rows.length, PAGE_SIZE);
|
|
6
|
+
const hasMore = rows.length > PAGE_SIZE;
|
|
7
|
+
// V1 sorts only by creation time. Keep a timestamp group on the same page,
|
|
8
|
+
// using one bounded lookahead row to avoid skipping ties at the boundary.
|
|
9
|
+
if (hasMore) {
|
|
10
|
+
while (end > 0 && rows[end - 1].createdAt === rows[PAGE_SIZE].createdAt)
|
|
11
|
+
end--;
|
|
12
|
+
}
|
|
13
|
+
const blocked = hasMore && end === 0;
|
|
14
|
+
const results = rows.slice(0, blocked ? PAGE_SIZE : end);
|
|
15
|
+
return {
|
|
16
|
+
results,
|
|
17
|
+
pagination: {
|
|
18
|
+
pageSize: PAGE_SIZE,
|
|
19
|
+
hasMore,
|
|
20
|
+
nextBefore: hasMore && !blocked ? results[results.length - 1].createdAt : null,
|
|
21
|
+
...(blocked ? { warning: TIE_WARNING } : {}),
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function createV1ListHandler(list, transform) {
|
|
26
|
+
return async (data) => {
|
|
27
|
+
try {
|
|
28
|
+
const page = v1ListPage(await list({
|
|
29
|
+
limit: PAGE_SIZE + 1,
|
|
30
|
+
...(data.before ? { createdAtLt: data.before } : {}),
|
|
31
|
+
}));
|
|
32
|
+
const results = page.results.map(transform);
|
|
33
|
+
const response = createSuccessResponse(results);
|
|
34
|
+
return {
|
|
35
|
+
// Preserve the original array in the first text block for existing clients.
|
|
36
|
+
content: [...response.content, {
|
|
37
|
+
type: 'text',
|
|
38
|
+
text: JSON.stringify({ pagination: page.pagination }),
|
|
39
|
+
}],
|
|
40
|
+
structuredContent: { results, pagination: page.pagination },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return createErrorResponse(error);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"phone-number.d.ts","sourceRoot":"","sources":["../../src/tools/phone-number.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"phone-number.d.ts","sourceRoot":"","sources":["../../src/tools/phone-number.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAOjD,eAAO,MAAM,wBAAwB,GACnC,QAAQ,SAAS,EACjB,YAAY,UAAU,SA6BvB,CAAC"}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { registerValidatedTool } from './validation.js';
|
|
2
|
+
import { readOnly } from './annotations.js';
|
|
2
3
|
import { transformPhoneNumberOutput } from '../transformers/index.js';
|
|
3
4
|
import { createToolHandler } from './utils.js';
|
|
4
|
-
import {
|
|
5
|
+
import { ListInputSchema, GetPhoneNumberInputSchema } from '../schemas/index.js';
|
|
6
|
+
import { createV1ListHandler } from './list.js';
|
|
5
7
|
export const registerPhoneNumberTools = (server, vapiClient) => {
|
|
6
8
|
registerValidatedTool(server, 'list_phone_numbers', {
|
|
7
|
-
description: 'Lists
|
|
8
|
-
inputSchema:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return phoneNumbers.map(transformPhoneNumberOutput);
|
|
12
|
-
}));
|
|
9
|
+
description: 'Lists up to 10 Vapi phone numbers',
|
|
10
|
+
inputSchema: ListInputSchema,
|
|
11
|
+
annotations: readOnly('List Phone Numbers'),
|
|
12
|
+
}, createV1ListHandler(request => vapiClient.phoneNumbers.list(request), transformPhoneNumberOutput));
|
|
13
13
|
registerValidatedTool(server, 'get_phone_number', {
|
|
14
14
|
description: 'Gets details of a specific phone number',
|
|
15
15
|
inputSchema: GetPhoneNumberInputSchema,
|
|
16
|
+
annotations: readOnly('Get Phone Number'),
|
|
16
17
|
}, createToolHandler(async (data) => {
|
|
17
18
|
const phoneNumberId = data.phoneNumberId;
|
|
18
19
|
const phoneNumber = await vapiClient.phoneNumbers.get({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simulation.d.ts","sourceRoot":"","sources":["../../src/tools/simulation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAQ,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"simulation.d.ts","sourceRoot":"","sources":["../../src/tools/simulation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAQ,MAAM,qBAAqB,CAAC;AA4CvD,eAAO,MAAM,uBAAuB,GAClC,QAAQ,SAAS,EACjB,YAAY,UAAU,SAyOvB,CAAC"}
|
package/dist/tools/simulation.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CreateSimulationInputSchema, CreateSimulationPersonalityInputSchema, CreateSimulationScenarioInputSchema, CreateSimulationSuiteInputSchema, GetSimulationRunInputSchema, GetSimulationRunItemInputSchema, ListSimulationResourcesInputSchema, ListSimulationRunsInputSchema, ListSimulationScenariosInputSchema, RunSimulationsInputSchema, } from '../schemas/index.js';
|
|
2
2
|
import { registerValidatedTool } from './validation.js';
|
|
3
|
+
import { creates, readOnly } from './annotations.js';
|
|
3
4
|
import { createToolHandler } from './utils.js';
|
|
4
5
|
const DEFAULT_LIMIT = 50;
|
|
5
6
|
// Run items carry call snapshots and transcripts in these fields, which can
|
|
@@ -21,16 +22,19 @@ export const registerSimulationTools = (server, vapiClient) => {
|
|
|
21
22
|
registerValidatedTool(server, 'list_simulation_personalities', {
|
|
22
23
|
description: 'Lists simulation personalities: the simulated callers (testers) used in Vapi simulations',
|
|
23
24
|
inputSchema: ListSimulationResourcesInputSchema,
|
|
25
|
+
annotations: readOnly('List Simulation Personalities'),
|
|
24
26
|
}, createToolHandler(async (data) => vapiClient.simulationPersonalities.personalityControllerFindAll({
|
|
25
27
|
limit: data.limit ?? DEFAULT_LIMIT,
|
|
26
28
|
})));
|
|
27
29
|
registerValidatedTool(server, 'create_simulation_personality', {
|
|
28
30
|
description: 'Creates a simulation personality: the simulated caller that talks to the assistant under test',
|
|
29
31
|
inputSchema: CreateSimulationPersonalityInputSchema,
|
|
32
|
+
annotations: creates('Create Simulation Personality'),
|
|
30
33
|
}, createToolHandler(async (data) => vapiClient.simulationPersonalities.personalityControllerCreate(data)));
|
|
31
34
|
registerValidatedTool(server, 'list_simulation_scenarios', {
|
|
32
35
|
description: 'Lists simulation scenarios: the scripts testers follow and the checks that decide pass or fail',
|
|
33
36
|
inputSchema: ListSimulationScenariosInputSchema,
|
|
37
|
+
annotations: readOnly('List Simulation Scenarios'),
|
|
34
38
|
}, createToolHandler(async (data) => vapiClient.simulationScenarios.scenarioControllerFindAll({
|
|
35
39
|
limit: data.limit ?? DEFAULT_LIMIT,
|
|
36
40
|
...(data.name && { name: data.name }),
|
|
@@ -38,6 +42,7 @@ export const registerSimulationTools = (server, vapiClient) => {
|
|
|
38
42
|
registerValidatedTool(server, 'create_simulation_scenario', {
|
|
39
43
|
description: 'Creates a simulation scenario: instructions for the tester plus evaluations that decide whether the assistant passed',
|
|
40
44
|
inputSchema: CreateSimulationScenarioInputSchema,
|
|
45
|
+
annotations: creates('Create Simulation Scenario'),
|
|
41
46
|
}, createToolHandler(async ({ additionalFields, ...data }) => vapiClient.simulationScenarios.scenarioControllerCreate({
|
|
42
47
|
...data,
|
|
43
48
|
...additionalFields,
|
|
@@ -45,22 +50,26 @@ export const registerSimulationTools = (server, vapiClient) => {
|
|
|
45
50
|
registerValidatedTool(server, 'list_simulations', {
|
|
46
51
|
description: 'Lists simulations. Each simulation pairs one scenario with one personality.',
|
|
47
52
|
inputSchema: ListSimulationResourcesInputSchema,
|
|
53
|
+
annotations: readOnly('List Simulations'),
|
|
48
54
|
}, createToolHandler(async (data) => vapiClient.simulations.simulationControllerFindAll({
|
|
49
55
|
limit: data.limit ?? DEFAULT_LIMIT,
|
|
50
56
|
})));
|
|
51
57
|
registerValidatedTool(server, 'create_simulation', {
|
|
52
58
|
description: 'Creates a simulation that pairs a scenario with a personality. Run it with run_simulations.',
|
|
53
59
|
inputSchema: CreateSimulationInputSchema,
|
|
60
|
+
annotations: creates('Create Simulation'),
|
|
54
61
|
}, createToolHandler(async (data) => vapiClient.simulations.simulationControllerCreate(data)));
|
|
55
62
|
registerValidatedTool(server, 'list_simulation_suites', {
|
|
56
63
|
description: 'Lists simulation suites: named groups of simulations',
|
|
57
64
|
inputSchema: ListSimulationResourcesInputSchema,
|
|
65
|
+
annotations: readOnly('List Simulation Suites'),
|
|
58
66
|
}, createToolHandler(async (data) => vapiClient.simulationSuites.simulationSuiteControllerFindAll({
|
|
59
67
|
limit: data.limit ?? DEFAULT_LIMIT,
|
|
60
68
|
})));
|
|
61
69
|
registerValidatedTool(server, 'create_simulation_suite', {
|
|
62
70
|
description: 'Creates a simulation suite that groups simulations so they can be run together',
|
|
63
71
|
inputSchema: CreateSimulationSuiteInputSchema,
|
|
72
|
+
annotations: creates('Create Simulation Suite'),
|
|
64
73
|
}, createToolHandler(async ({ additionalFields, ...data }) => vapiClient.simulationSuites.simulationSuiteControllerCreate({
|
|
65
74
|
...data,
|
|
66
75
|
...additionalFields,
|
|
@@ -69,6 +78,7 @@ export const registerSimulationTools = (server, vapiClient) => {
|
|
|
69
78
|
description: 'Starts a simulation run of simulations and/or suites against an assistant or squad. ' +
|
|
70
79
|
'Returns the run with its ID and a dashboard URL to share with the user. Check progress with get_simulation_run.',
|
|
71
80
|
inputSchema: RunSimulationsInputSchema,
|
|
81
|
+
annotations: creates('Run Simulations'),
|
|
72
82
|
}, createToolHandler(async (data) => {
|
|
73
83
|
const simulations = [
|
|
74
84
|
...(data.simulationIds ?? []).map((simulationId) => ({
|
|
@@ -94,6 +104,7 @@ export const registerSimulationTools = (server, vapiClient) => {
|
|
|
94
104
|
registerValidatedTool(server, 'list_simulation_runs', {
|
|
95
105
|
description: 'Lists simulation runs, newest first',
|
|
96
106
|
inputSchema: ListSimulationRunsInputSchema,
|
|
107
|
+
annotations: readOnly('List Simulation Runs'),
|
|
97
108
|
}, createToolHandler(async (data) => vapiClient.simulationRuns.simulationRunControllerFindAll({
|
|
98
109
|
limit: data.limit ?? DEFAULT_LIMIT,
|
|
99
110
|
...(data.status && { status: data.status }),
|
|
@@ -104,6 +115,7 @@ export const registerSimulationTools = (server, vapiClient) => {
|
|
|
104
115
|
'itemsTruncated indicates omitted items; itemsMetadata preserves API pagination metadata. ' +
|
|
105
116
|
'Use get_simulation_run_item for an item’s transcript and call details.',
|
|
106
117
|
inputSchema: GetSimulationRunInputSchema,
|
|
118
|
+
annotations: readOnly('Get Simulation Run'),
|
|
107
119
|
}, createToolHandler(async (data) => {
|
|
108
120
|
const [run, response] = await Promise.all([
|
|
109
121
|
vapiClient.simulationRuns.simulationRunControllerFindOne({
|
|
@@ -126,6 +138,7 @@ export const registerSimulationTools = (server, vapiClient) => {
|
|
|
126
138
|
registerValidatedTool(server, 'get_simulation_run_item', {
|
|
127
139
|
description: 'Gets one simulation run item in full, including results, call snapshots, transcript, and improvement suggestions',
|
|
128
140
|
inputSchema: GetSimulationRunItemInputSchema,
|
|
141
|
+
annotations: readOnly('Get Simulation Run Item'),
|
|
129
142
|
}, createToolHandler(async (data) => vapiClient.simulationRuns.simulationRunControllerFindItem({
|
|
130
143
|
id: data.runId,
|
|
131
144
|
itemId: data.itemId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/tools/skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/tools/skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAkBzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,QAiBnD"}
|
package/dist/tools/skills.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { PublicSkills } from '../knowledge/skills.js';
|
|
3
|
+
import { readOnly } from './annotations.js';
|
|
3
4
|
async function knowledgeResult(action) {
|
|
4
5
|
try {
|
|
5
6
|
return await action();
|
|
@@ -13,19 +14,18 @@ function jsonResult(data) {
|
|
|
13
14
|
}
|
|
14
15
|
export function registerSkillTools(server) {
|
|
15
16
|
const skills = new PublicSkills();
|
|
16
|
-
const annotations = { readOnlyHint: true, destructiveHint: false, openWorldHint: true };
|
|
17
17
|
server.registerTool('search_skills', {
|
|
18
18
|
description: 'Find Vapi agent skills in the public VapiAI/skills repository by name, description or content. Omit query to browse. Use load_skill to read a result.',
|
|
19
19
|
inputSchema: {
|
|
20
20
|
query: z.string().trim().max(500).default('').describe('Keywords describing the Vapi task, or empty to browse all skills.'),
|
|
21
21
|
limit: z.number().int().min(1).max(30).default(10),
|
|
22
|
-
}, annotations,
|
|
22
|
+
}, annotations: readOnly('Search Vapi Skills', true),
|
|
23
23
|
}, ({ query, limit }) => knowledgeResult(async () => jsonResult(await skills.search(query, limit))));
|
|
24
24
|
server.registerTool('load_skill', {
|
|
25
25
|
description: 'Read a public Vapi skill or one of its supporting files. Start with SKILL.md, then load relevant files from the returned file list as needed. Returns instructions for this task; does not install skills or execute scripts.',
|
|
26
26
|
inputSchema: {
|
|
27
27
|
name: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).max(100).describe('Exact skill name from search_skills.'),
|
|
28
28
|
path: z.string().min(1).max(300).default('SKILL.md').describe('File path relative to the skill directory, such as SKILL.md or references/hooks.md.'),
|
|
29
|
-
}, annotations,
|
|
29
|
+
}, annotations: readOnly('Load Vapi Skill', true),
|
|
30
30
|
}, ({ name, path }) => knowledgeResult(async () => jsonResult(await skills.load(name, path))));
|
|
31
31
|
}
|
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":"
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/tools/tool.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAQ,MAAM,qBAAqB,CAAC;AAOvD,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,SAAS,EACjB,YAAY,UAAU,SA4DvB,CAAC"}
|
package/dist/tools/tool.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { registerValidatedTool } from './validation.js';
|
|
2
|
-
import {
|
|
2
|
+
import { creates, readOnly, updates } from './annotations.js';
|
|
3
|
+
import { ListInputSchema, GetToolInputSchema, CreateToolInputSchema, UpdateToolInputSchema } from '../schemas/index.js';
|
|
3
4
|
import { transformToolInput, transformUpdateToolInput, transformToolOutput } from '../transformers/index.js';
|
|
4
5
|
import { createToolHandler } from './utils.js';
|
|
6
|
+
import { createV1ListHandler } from './list.js';
|
|
5
7
|
export const registerToolTools = (server, vapiClient) => {
|
|
6
8
|
registerValidatedTool(server, 'list_tools', {
|
|
7
|
-
description: 'Lists
|
|
8
|
-
inputSchema:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return tools.map(transformToolOutput);
|
|
12
|
-
}));
|
|
9
|
+
description: 'Lists up to 10 Vapi tools',
|
|
10
|
+
inputSchema: ListInputSchema,
|
|
11
|
+
annotations: readOnly('List Tools'),
|
|
12
|
+
}, createV1ListHandler(request => vapiClient.tools.list(request), transformToolOutput));
|
|
13
13
|
registerValidatedTool(server, 'get_tool', {
|
|
14
14
|
description: 'Gets details of a specific tool',
|
|
15
15
|
inputSchema: GetToolInputSchema,
|
|
16
|
+
annotations: readOnly('Get Tool'),
|
|
16
17
|
}, createToolHandler(async (data) => {
|
|
17
18
|
const tool = await vapiClient.tools.get({ id: data.toolId });
|
|
18
19
|
return transformToolOutput(tool);
|
|
@@ -20,6 +21,7 @@ export const registerToolTools = (server, vapiClient) => {
|
|
|
20
21
|
registerValidatedTool(server, 'create_tool', {
|
|
21
22
|
description: 'Creates a new Vapi tool',
|
|
22
23
|
inputSchema: CreateToolInputSchema,
|
|
24
|
+
annotations: creates('Create Tool'),
|
|
23
25
|
}, createToolHandler(async (data) => {
|
|
24
26
|
const createToolDto = transformToolInput(data);
|
|
25
27
|
const tool = await vapiClient.tools.create(createToolDto);
|
|
@@ -28,6 +30,7 @@ export const registerToolTools = (server, vapiClient) => {
|
|
|
28
30
|
registerValidatedTool(server, 'update_tool', {
|
|
29
31
|
description: 'Updates an existing Vapi tool',
|
|
30
32
|
inputSchema: UpdateToolInputSchema,
|
|
33
|
+
annotations: updates('Update Tool'),
|
|
31
34
|
}, createToolHandler(async (data) => {
|
|
32
35
|
const existingTool = await vapiClient.tools.get({ id: data.toolId });
|
|
33
36
|
const updateToolDto = transformUpdateToolInput(data, existingTool);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
|
|
2
3
|
import { z } from 'zod';
|
|
3
4
|
import type { ToolResponse } from './utils.js';
|
|
4
5
|
type Issue = z.core.$ZodIssue;
|
|
@@ -17,6 +18,7 @@ export declare function validationIssues(issues: Issue[], input: unknown, prefix
|
|
|
17
18
|
export declare function registerValidatedTool<Schema extends z.ZodType>(server: McpServer, name: string, config: {
|
|
18
19
|
description: string;
|
|
19
20
|
inputSchema: Schema;
|
|
21
|
+
annotations: ToolAnnotations;
|
|
20
22
|
}, handler: (params: z.output<Schema>) => Promise<ToolResponse>): import("@modelcontextprotocol/sdk/server/mcp.js").RegisteredTool;
|
|
21
23
|
export {};
|
|
22
24
|
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/tools/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,KAAK,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AAC9B,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC;IACvE,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACxE,CAAC;AAcF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,GAAE,WAAW,EAAO,GAAG,UAAU,EAAE,CA8C1G;AAWD,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,CAAC,CAAC,OAAO,EAC5D,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/tools/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,KAAK,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AAC9B,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC;IACvE,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACxE,CAAC;AAcF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,GAAE,WAAW,EAAO,GAAG,UAAU,EAAE,CA8C1G;AAWD,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,CAAC,CAAC,OAAO,EAC5D,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,eAAe,CAAA;CAAE,EAClF,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,oEAsB7D"}
|
package/dist/tools/validation.js
CHANGED
|
@@ -78,7 +78,7 @@ export function registerValidatedTool(server, name, config, handler) {
|
|
|
78
78
|
// boundary lets us format validation failures before the SDK stringifies a
|
|
79
79
|
// raw ZodError. No request reaches the API handler before parsing succeeds.
|
|
80
80
|
const transportSchema = z.object({}).passthrough().meta(summarizeInputSchema(z.toJSONSchema(schema, { io: 'input', target: 'draft-07' })));
|
|
81
|
-
return server.registerTool(name, { description: config.description, inputSchema: transportSchema }, async (raw) => {
|
|
81
|
+
return server.registerTool(name, { description: config.description, inputSchema: transportSchema, annotations: config.annotations }, async (raw) => {
|
|
82
82
|
const parsed = await schema.safeParseAsync(raw);
|
|
83
83
|
if (!parsed.success) {
|
|
84
84
|
const all = validationIssues(parsed.error.issues, raw);
|
package/package.json
CHANGED