wixzel-voice-mcp 0.4.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/CHANGELOG.md +57 -0
- package/LICENSE +21 -0
- package/README.md +127 -0
- package/dist/client.d.ts +69 -0
- package/dist/client.js +137 -0
- package/dist/client.js.map +1 -0
- package/dist/guide.d.ts +11 -0
- package/dist/guide.js +86 -0
- package/dist/guide.js.map +1 -0
- package/dist/http.d.ts +80 -0
- package/dist/http.js +281 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts.d.ts +7 -0
- package/dist/prompts.js +83 -0
- package/dist/prompts.js.map +1 -0
- package/dist/schemas.d.ts +105 -0
- package/dist/schemas.js +122 -0
- package/dist/schemas.js.map +1 -0
- package/dist/server.d.ts +16 -0
- package/dist/server.js +58 -0
- package/dist/server.js.map +1 -0
- package/dist/site.d.ts +12 -0
- package/dist/site.js +17 -0
- package/dist/site.js.map +1 -0
- package/dist/tooling.d.ts +59 -0
- package/dist/tooling.js +129 -0
- package/dist/tooling.js.map +1 -0
- package/dist/tools/agents.d.ts +97 -0
- package/dist/tools/agents.js +105 -0
- package/dist/tools/agents.js.map +1 -0
- package/dist/tools/api-keys.d.ts +37 -0
- package/dist/tools/api-keys.js +61 -0
- package/dist/tools/api-keys.js.map +1 -0
- package/dist/tools/appointments.d.ts +30 -0
- package/dist/tools/appointments.js +77 -0
- package/dist/tools/appointments.js.map +1 -0
- package/dist/tools/billing.d.ts +29 -0
- package/dist/tools/billing.js +72 -0
- package/dist/tools/billing.js.map +1 -0
- package/dist/tools/calls.d.ts +37 -0
- package/dist/tools/calls.js +98 -0
- package/dist/tools/calls.js.map +1 -0
- package/dist/tools/campaigns.d.ts +13 -0
- package/dist/tools/campaigns.js +76 -0
- package/dist/tools/campaigns.js.map +1 -0
- package/dist/tools/engines.d.ts +4 -0
- package/dist/tools/engines.js +43 -0
- package/dist/tools/engines.js.map +1 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.js +37 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/knowledge-bases.d.ts +27 -0
- package/dist/tools/knowledge-bases.js +69 -0
- package/dist/tools/knowledge-bases.js.map +1 -0
- package/dist/tools/leads.d.ts +28 -0
- package/dist/tools/leads.js +88 -0
- package/dist/tools/leads.js.map +1 -0
- package/dist/tools/phone-numbers.d.ts +19 -0
- package/dist/tools/phone-numbers.js +72 -0
- package/dist/tools/phone-numbers.js.map +1 -0
- package/dist/tools/realtime.d.ts +8 -0
- package/dist/tools/realtime.js +28 -0
- package/dist/tools/realtime.js.map +1 -0
- package/dist/tools/sip-trunks.d.ts +45 -0
- package/dist/tools/sip-trunks.js +118 -0
- package/dist/tools/sip-trunks.js.map +1 -0
- package/dist/tools/webhooks.d.ts +52 -0
- package/dist/tools/webhooks.js +90 -0
- package/dist/tools/webhooks.js.map +1 -0
- package/dist/version.d.ts +7 -0
- package/dist/version.js +8 -0
- package/dist/version.js.map +1 -0
- package/package.json +65 -0
package/dist/schemas.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zod shapes shared across tools. Kept loose on purpose where the API already
|
|
3
|
+
* gives a better error than a client could — the mutually-exclusive voice
|
|
4
|
+
* rule, for instance, is enforced server-side with a message that names the
|
|
5
|
+
* block to delete.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod/v4';
|
|
8
|
+
export const id = z.string().min(1).describe('The record id, e.g. "6a96a3ead6e886d42462dd3e".');
|
|
9
|
+
export const pagination = {
|
|
10
|
+
limit: z.number().int().min(1).max(100).optional().describe('Page size, 1–100. Default 20.'),
|
|
11
|
+
starting_after: z
|
|
12
|
+
.string()
|
|
13
|
+
.optional()
|
|
14
|
+
.describe('Cursor from a previous response\'s next_cursor. Fetches the page after it.'),
|
|
15
|
+
ending_before: z
|
|
16
|
+
.string()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe('Cursor from a previous response. Fetches the page before it. Not with starting_after.'),
|
|
19
|
+
};
|
|
20
|
+
export const isoDate = z
|
|
21
|
+
.string()
|
|
22
|
+
.describe('ISO 8601 timestamp, UTC, e.g. "2026-09-01T12:00:00.000Z".');
|
|
23
|
+
export const e164 = z
|
|
24
|
+
.string()
|
|
25
|
+
.min(3)
|
|
26
|
+
.describe('Phone number in E.164 form, e.g. "+14155551234".');
|
|
27
|
+
const providerModel = z
|
|
28
|
+
.string()
|
|
29
|
+
// The model half may itself contain slashes: OpenRouter ids are
|
|
30
|
+
// vendor-qualified, so `openrouter/anthropic/claude-sonnet-4.5` is the
|
|
31
|
+
// openrouter provider and the model `anthropic/claude-sonnet-4.5`. Only the
|
|
32
|
+
// FIRST slash separates the two. This mirrors ProviderModelSchema in
|
|
33
|
+
// @wixzel/schemas; a stricter copy here rejects valid models before the
|
|
34
|
+
// request ever reaches the API, which is worse than no validation at all.
|
|
35
|
+
.regex(/^[a-z0-9_-]+\/[a-zA-Z0-9._-]+(?:\/[a-zA-Z0-9._-]+)*$/, 'must be "provider/model", e.g. deepgram/nova-3 or openrouter/anthropic/claude-sonnet-4.5')
|
|
36
|
+
.describe('"provider/model", e.g. "deepgram/nova-3" or "openrouter/anthropic/claude-sonnet-4.5". Call list_engines for what is available and priced.');
|
|
37
|
+
export const sttConfig = z.object({
|
|
38
|
+
model: providerModel,
|
|
39
|
+
language: z.string().optional().describe('BCP-47 tag, or "multi" for automatic detection. Default en-US.'),
|
|
40
|
+
endpointing_ms: z
|
|
41
|
+
.number()
|
|
42
|
+
.int()
|
|
43
|
+
.min(50)
|
|
44
|
+
.max(3000)
|
|
45
|
+
.optional()
|
|
46
|
+
.describe('Silence before a turn is considered finished. Lower is snappier and more prone to cutting people off.'),
|
|
47
|
+
});
|
|
48
|
+
export const llmConfig = z.object({
|
|
49
|
+
model: providerModel,
|
|
50
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
51
|
+
max_tokens: z
|
|
52
|
+
.number()
|
|
53
|
+
.int()
|
|
54
|
+
.min(1)
|
|
55
|
+
.max(4096)
|
|
56
|
+
.optional()
|
|
57
|
+
.describe('Caps reply length. Long replies cost the caller waiting time as well as money.'),
|
|
58
|
+
});
|
|
59
|
+
export const ttsConfig = z.object({
|
|
60
|
+
model: providerModel,
|
|
61
|
+
voice: z.string().optional().describe('Provider voice id, e.g. an ElevenLabs voice id.'),
|
|
62
|
+
stability: z.number().min(0).max(1).optional(),
|
|
63
|
+
similarity_boost: z.number().min(0).max(1).optional(),
|
|
64
|
+
speed: z.number().min(0.5).max(2).optional(),
|
|
65
|
+
});
|
|
66
|
+
export const realtimeConfig = z.object({
|
|
67
|
+
model: providerModel.describe('A realtime model, e.g. "google/gemini-live-2.5-flash".'),
|
|
68
|
+
voice: z.string().optional().describe('Provider voice name, e.g. "Charon".'),
|
|
69
|
+
language: z.string().optional().describe('Default "auto".'),
|
|
70
|
+
});
|
|
71
|
+
export const turnTaking = z.object({
|
|
72
|
+
interrupt_sensitivity: z
|
|
73
|
+
.enum(['low', 'normal', 'high'])
|
|
74
|
+
.optional()
|
|
75
|
+
.describe('How readily the agent stops talking when the caller speaks. Default normal.'),
|
|
76
|
+
silence_wait_ms: z.number().int().min(100).max(5000).optional(),
|
|
77
|
+
});
|
|
78
|
+
export const voiceConfig = z
|
|
79
|
+
.object({
|
|
80
|
+
stt: sttConfig.optional(),
|
|
81
|
+
llm: llmConfig.optional(),
|
|
82
|
+
tts: ttsConfig.optional(),
|
|
83
|
+
realtime: realtimeConfig.optional(),
|
|
84
|
+
turn_taking: turnTaking.optional(),
|
|
85
|
+
})
|
|
86
|
+
.describe('Either a COMPOSED pipeline {stt, llm, tts} (all three required together) or a single REALTIME model {realtime}. Never both. Use list_engines to pick models that are available right now.');
|
|
87
|
+
export const scopes = [
|
|
88
|
+
'agents:read',
|
|
89
|
+
'agents:write',
|
|
90
|
+
'calls:read',
|
|
91
|
+
'calls:write',
|
|
92
|
+
'leads:read',
|
|
93
|
+
'leads:write',
|
|
94
|
+
'campaigns:read',
|
|
95
|
+
'campaigns:write',
|
|
96
|
+
'knowledge_bases:read',
|
|
97
|
+
'knowledge_bases:write',
|
|
98
|
+
'phone_numbers:read',
|
|
99
|
+
'phone_numbers:write',
|
|
100
|
+
'sip_trunks:read',
|
|
101
|
+
'sip_trunks:write',
|
|
102
|
+
'appointments:read',
|
|
103
|
+
'appointments:write',
|
|
104
|
+
'webhooks:read',
|
|
105
|
+
'webhooks:write',
|
|
106
|
+
'api_keys:read',
|
|
107
|
+
'api_keys:write',
|
|
108
|
+
'usage:read',
|
|
109
|
+
'billing:read',
|
|
110
|
+
'billing:write',
|
|
111
|
+
];
|
|
112
|
+
export const scope = z.enum(scopes);
|
|
113
|
+
export const arbitraryFields = z
|
|
114
|
+
.record(z.string(), z.unknown())
|
|
115
|
+
.optional()
|
|
116
|
+
.describe('Arbitrary key/value data.');
|
|
117
|
+
export const idempotencyKey = z
|
|
118
|
+
.string()
|
|
119
|
+
.max(255)
|
|
120
|
+
.optional()
|
|
121
|
+
.describe('Idempotency-Key for safe retries. Generated automatically when omitted. Reuse the SAME value when retrying the SAME logical request; never reuse it for a different one.');
|
|
122
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { WixzelClient, type WixzelClientOptions } from './client.js';
|
|
3
|
+
export declare const SERVER_NAME = "wixzel-voice";
|
|
4
|
+
export declare const SERVER_VERSION = "0.4.0";
|
|
5
|
+
export interface CreateServerOptions {
|
|
6
|
+
/** An already-constructed client, or the options to build one. */
|
|
7
|
+
client: WixzelClient | WixzelClientOptions;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Build an MCP server bound to one Wixzel Voice API key. Cheap enough to
|
|
11
|
+
* construct per request in HTTP mode, where the key arrives with each call.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createServer(opts: CreateServerOptions): McpServer;
|
|
14
|
+
export { WixzelClient, WixzelApiError } from './client.js';
|
|
15
|
+
export { allTools } from './tools/index.js';
|
|
16
|
+
export { GUIDE } from './guide.js';
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { WixzelClient } from './client.js';
|
|
3
|
+
import { GUIDE } from './guide.js';
|
|
4
|
+
import { registerPrompts } from './prompts.js';
|
|
5
|
+
import { toolsFor } from './tools/index.js';
|
|
6
|
+
import { consoleUrl } from './site.js';
|
|
7
|
+
import { registerTools } from './tooling.js';
|
|
8
|
+
import { VERSION } from './version.js';
|
|
9
|
+
export const SERVER_NAME = 'wixzel-voice';
|
|
10
|
+
export const SERVER_VERSION = VERSION;
|
|
11
|
+
/**
|
|
12
|
+
* Build an MCP server bound to one Wixzel Voice API key. Cheap enough to
|
|
13
|
+
* construct per request in HTTP mode, where the key arrives with each call.
|
|
14
|
+
*/
|
|
15
|
+
export function createServer(opts) {
|
|
16
|
+
const client = opts.client instanceof WixzelClient ? opts.client : new WixzelClient(opts.client);
|
|
17
|
+
const server = new McpServer({
|
|
18
|
+
name: SERVER_NAME,
|
|
19
|
+
version: SERVER_VERSION,
|
|
20
|
+
title: 'Wixzel Voice',
|
|
21
|
+
websiteUrl: consoleUrl(),
|
|
22
|
+
// Shown by clients that render a connector icon (claude.ai does).
|
|
23
|
+
icons: [
|
|
24
|
+
{ src: `${consoleUrl()}/icon-192.png`, mimeType: 'image/png', sizes: ['192x192'] },
|
|
25
|
+
{ src: `${consoleUrl()}/icon-512.png`, mimeType: 'image/png', sizes: ['512x512'] },
|
|
26
|
+
],
|
|
27
|
+
}, {
|
|
28
|
+
instructions: GUIDE,
|
|
29
|
+
capabilities: { tools: {}, prompts: {}, resources: {} },
|
|
30
|
+
});
|
|
31
|
+
registerTools(server, client, toolsFor());
|
|
32
|
+
registerPrompts(server);
|
|
33
|
+
server.registerResource('guide', 'wixzel://guide', {
|
|
34
|
+
title: 'Wixzel Voice operating guide',
|
|
35
|
+
description: 'How the pieces fit together, the order to set them up in, and which tools spend money.',
|
|
36
|
+
mimeType: 'text/markdown',
|
|
37
|
+
}, async (uri) => ({
|
|
38
|
+
contents: [{ uri: uri.href, mimeType: 'text/markdown', text: GUIDE }],
|
|
39
|
+
}));
|
|
40
|
+
server.registerResource('connection', 'wixzel://connection', {
|
|
41
|
+
title: 'Current connection',
|
|
42
|
+
description: 'Which API base URL this server talks to and whether the key is live or test. Never includes the key.',
|
|
43
|
+
mimeType: 'application/json',
|
|
44
|
+
}, async (uri) => ({
|
|
45
|
+
contents: [
|
|
46
|
+
{
|
|
47
|
+
uri: uri.href,
|
|
48
|
+
mimeType: 'application/json',
|
|
49
|
+
text: JSON.stringify({ base_url: client.baseUrl, key_mode: client.keyMode, tools: toolsFor().length }, null, 2),
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
}));
|
|
53
|
+
return server;
|
|
54
|
+
}
|
|
55
|
+
export { WixzelClient, WixzelApiError } from './client.js';
|
|
56
|
+
export { allTools } from './tools/index.js';
|
|
57
|
+
export { GUIDE } from './guide.js';
|
|
58
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/site.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where this server's console is, and which edition it serves.
|
|
3
|
+
*
|
|
4
|
+
* The hosted server and the npm package both talk to voice.wixzel.com, which is
|
|
5
|
+
* the default. A self-hosted install runs this same process against the buyer's
|
|
6
|
+
* own API: WIXZEL_CONSOLE_URL points every link at the buyer's console, and
|
|
7
|
+
* WIXZEL_EDITION=selfhost keeps the guide from sending an agent to buy credit
|
|
8
|
+
* that does not exist there.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_CONSOLE_URL = "https://voice.wixzel.com";
|
|
11
|
+
export declare function consoleUrl(env?: NodeJS.ProcessEnv): string;
|
|
12
|
+
export declare function isSelfHosted(env?: NodeJS.ProcessEnv): boolean;
|
package/dist/site.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where this server's console is, and which edition it serves.
|
|
3
|
+
*
|
|
4
|
+
* The hosted server and the npm package both talk to voice.wixzel.com, which is
|
|
5
|
+
* the default. A self-hosted install runs this same process against the buyer's
|
|
6
|
+
* own API: WIXZEL_CONSOLE_URL points every link at the buyer's console, and
|
|
7
|
+
* WIXZEL_EDITION=selfhost keeps the guide from sending an agent to buy credit
|
|
8
|
+
* that does not exist there.
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_CONSOLE_URL = 'https://voice.wixzel.com';
|
|
11
|
+
export function consoleUrl(env = process.env) {
|
|
12
|
+
return (env.WIXZEL_CONSOLE_URL || DEFAULT_CONSOLE_URL).replace(/\/+$/, '');
|
|
13
|
+
}
|
|
14
|
+
export function isSelfHosted(env = process.env) {
|
|
15
|
+
return String(env.WIXZEL_EDITION ?? '').trim().toLowerCase() === 'selfhost';
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=site.js.map
|
package/dist/site.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site.js","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,0BAA0B,CAAC;AAE9D,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC3D,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,mBAAmB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,OAAO,MAAM,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC;AAChF,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The glue between a tool definition and the MCP server: result formatting,
|
|
3
|
+
* error translation, and the annotation presets that tell a client which
|
|
4
|
+
* tools are safe to call without asking.
|
|
5
|
+
*/
|
|
6
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
+
import type { CallToolResult, ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
import type { ZodRawShape } from 'zod/v4';
|
|
9
|
+
import { type WixzelClient } from './client.js';
|
|
10
|
+
export interface ToolDef<Shape extends ZodRawShape = ZodRawShape> {
|
|
11
|
+
name: string;
|
|
12
|
+
title: string;
|
|
13
|
+
description: string;
|
|
14
|
+
input: Shape;
|
|
15
|
+
/**
|
|
16
|
+
* The API operation this tool wraps, as `METHOD /v1/path/{id}`. Never used
|
|
17
|
+
* at runtime; the spec-coverage test compares it to the OpenAPI document so
|
|
18
|
+
* an endpoint added to the API cannot go unwrapped, and a tool cannot claim
|
|
19
|
+
* an endpoint that does not exist.
|
|
20
|
+
*/
|
|
21
|
+
endpoint: string;
|
|
22
|
+
annotations: ToolAnnotations;
|
|
23
|
+
/** The API scope the key must hold. Surfaced in errors when the key lacks it. */
|
|
24
|
+
scope?: string;
|
|
25
|
+
handler: (client: WixzelClient, args: ShapeArgs<Shape>) => Promise<unknown>;
|
|
26
|
+
}
|
|
27
|
+
type ShapeArgs<Shape extends ZodRawShape> = {
|
|
28
|
+
[K in keyof Shape]: Shape[K] extends {
|
|
29
|
+
_output: infer O;
|
|
30
|
+
} ? O : unknown;
|
|
31
|
+
};
|
|
32
|
+
/** Presets. Every tool picks exactly one. */
|
|
33
|
+
export declare const annotate: {
|
|
34
|
+
/** Reads a record or a list. Safe to call freely. */
|
|
35
|
+
read: ToolAnnotations;
|
|
36
|
+
/** Creates or updates a record on the account. Reversible. */
|
|
37
|
+
write: ToolAnnotations;
|
|
38
|
+
/** Same as write, and calling it twice is the same as once. */
|
|
39
|
+
writeIdempotent: ToolAnnotations;
|
|
40
|
+
/** Deletes or revokes. Not reversible. */
|
|
41
|
+
destructive: ToolAnnotations;
|
|
42
|
+
/** Spends credit or makes a phone ring in the real world. */
|
|
43
|
+
spend: ToolAnnotations;
|
|
44
|
+
/** Sends traffic to a third party (a carrier) without spending. */
|
|
45
|
+
probe: ToolAnnotations;
|
|
46
|
+
};
|
|
47
|
+
export declare function defineTool<Shape extends ZodRawShape>(def: ToolDef<Shape>): ToolDef<Shape>;
|
|
48
|
+
export declare function registerTools(server: McpServer, client: WixzelClient, tools: ToolDef<any>[]): void;
|
|
49
|
+
export declare function ok(data: unknown): CallToolResult;
|
|
50
|
+
export declare function fail(error: unknown, tool?: ToolDef<any>): CallToolResult;
|
|
51
|
+
/**
|
|
52
|
+
* Turn a failure into something an agent can act on: the machine-readable code
|
|
53
|
+
* first (the docs say to match on it, not the message), then the human
|
|
54
|
+
* message, then what to do about it.
|
|
55
|
+
*/
|
|
56
|
+
export declare function describeError(error: unknown, tool?: ToolDef<any>): string;
|
|
57
|
+
/** Drop keys whose value is undefined so PATCH bodies only carry what was sent. */
|
|
58
|
+
export declare function compact<T extends Record<string, unknown>>(obj: T): Partial<T>;
|
|
59
|
+
export {};
|
package/dist/tooling.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The glue between a tool definition and the MCP server: result formatting,
|
|
3
|
+
* error translation, and the annotation presets that tell a client which
|
|
4
|
+
* tools are safe to call without asking.
|
|
5
|
+
*/
|
|
6
|
+
import { consoleUrl } from './site.js';
|
|
7
|
+
import { WixzelApiError } from './client.js';
|
|
8
|
+
/** Presets. Every tool picks exactly one. */
|
|
9
|
+
export const annotate = {
|
|
10
|
+
/** Reads a record or a list. Safe to call freely. */
|
|
11
|
+
read: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
12
|
+
/** Creates or updates a record on the account. Reversible. */
|
|
13
|
+
write: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
14
|
+
/** Same as write, and calling it twice is the same as once. */
|
|
15
|
+
writeIdempotent: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
16
|
+
/** Deletes or revokes. Not reversible. */
|
|
17
|
+
destructive: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
18
|
+
/** Spends credit or makes a phone ring in the real world. */
|
|
19
|
+
spend: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
20
|
+
/** Sends traffic to a third party (a carrier) without spending. */
|
|
21
|
+
probe: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
22
|
+
};
|
|
23
|
+
export function defineTool(def) {
|
|
24
|
+
return def;
|
|
25
|
+
}
|
|
26
|
+
export function registerTools(server, client, tools) {
|
|
27
|
+
for (const tool of tools) {
|
|
28
|
+
server.registerTool(tool.name, {
|
|
29
|
+
title: tool.title,
|
|
30
|
+
description: tool.scope ? `${tool.description}\n\nRequires scope \`${tool.scope}\`.` : tool.description,
|
|
31
|
+
inputSchema: tool.input,
|
|
32
|
+
annotations: tool.annotations,
|
|
33
|
+
}, async (args) => {
|
|
34
|
+
try {
|
|
35
|
+
const result = await tool.handler(client, args);
|
|
36
|
+
return ok(result);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return fail(error, tool);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function ok(data) {
|
|
45
|
+
const text = data === null || data === undefined
|
|
46
|
+
? 'Done.'
|
|
47
|
+
: typeof data === 'string'
|
|
48
|
+
? data
|
|
49
|
+
: JSON.stringify(data, null, 2);
|
|
50
|
+
return { content: [{ type: 'text', text }] };
|
|
51
|
+
}
|
|
52
|
+
export function fail(error, tool) {
|
|
53
|
+
return { isError: true, content: [{ type: 'text', text: describeError(error, tool) }] };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Turn a failure into something an agent can act on: the machine-readable code
|
|
57
|
+
* first (the docs say to match on it, not the message), then the human
|
|
58
|
+
* message, then what to do about it.
|
|
59
|
+
*/
|
|
60
|
+
export function describeError(error, tool) {
|
|
61
|
+
if (error instanceof WixzelApiError) {
|
|
62
|
+
const lines = [
|
|
63
|
+
`Wixzel Voice API error ${error.status} (${error.type} / ${error.code}): ${error.message}`,
|
|
64
|
+
];
|
|
65
|
+
if (error.param)
|
|
66
|
+
lines.push(`Parameter: ${error.param}`);
|
|
67
|
+
if (error.requestId)
|
|
68
|
+
lines.push(`request_id: ${error.requestId}`);
|
|
69
|
+
const hint = hintFor(error, tool);
|
|
70
|
+
if (hint)
|
|
71
|
+
lines.push(`Hint: ${hint}`);
|
|
72
|
+
return lines.join('\n');
|
|
73
|
+
}
|
|
74
|
+
if (error instanceof Error) {
|
|
75
|
+
if (error.name === 'TimeoutError' || error.name === 'AbortError') {
|
|
76
|
+
return `The request to the Wixzel Voice API timed out. ${tool?.annotations.idempotentHint ? 'It is safe to retry.' : 'If this tool spends money, retry with the same idempotency_key so it is not repeated.'}`;
|
|
77
|
+
}
|
|
78
|
+
return `Request failed: ${error.message}`;
|
|
79
|
+
}
|
|
80
|
+
return `Request failed: ${String(error)}`;
|
|
81
|
+
}
|
|
82
|
+
function hintFor(error, tool) {
|
|
83
|
+
switch (error.code) {
|
|
84
|
+
case 'insufficient_credits':
|
|
85
|
+
return `The account balance cannot cover this. ${error.balanceHeader ? `Current balance: ${error.balanceHeader}. ` : ''}Add credit with create_topup (returns a checkout URL for a human to pay) or in the dashboard at ${consoleUrl()}.`;
|
|
86
|
+
case 'insufficient_scope':
|
|
87
|
+
case 'permission_denied':
|
|
88
|
+
return `The API key does not hold ${tool?.scope ? `the \`${tool.scope}\` scope` : 'the scope this endpoint needs'}. Keys are scoped with no wildcard; create one with that scope in Dashboard → API keys, then restart this MCP server with it.`;
|
|
89
|
+
case 'scope_escalation':
|
|
90
|
+
return 'A key cannot grant scopes it does not itself hold. Drop the extra scopes, or create the key from the dashboard.';
|
|
91
|
+
case 'unsupported_model':
|
|
92
|
+
return 'Call list_engines and pick a model from what it returns. The message above lists what is available for that component.';
|
|
93
|
+
case 'idempotency_key_reuse':
|
|
94
|
+
return 'That idempotency_key was already used with a different body. Use a fresh key for a new request.';
|
|
95
|
+
case 'idempotency_key_in_flight':
|
|
96
|
+
return 'The original request is still running. Wait a moment and retry with the same idempotency_key; do not start a second one.';
|
|
97
|
+
case 'rate_limit_exceeded':
|
|
98
|
+
return `Rate limited (10 req/s, burst 20). Nothing was charged. Wait ${error.retryAfterSeconds ?? 1}s and retry.`;
|
|
99
|
+
case 'invalid_cursor':
|
|
100
|
+
case 'conflicting_cursors':
|
|
101
|
+
return 'Pass exactly one cursor, copied verbatim from a previous response\'s next_cursor.';
|
|
102
|
+
default:
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
switch (error.type) {
|
|
106
|
+
case 'authentication_error':
|
|
107
|
+
return 'The API key is missing, malformed, revoked or expired. Set WIXZEL_API_KEY to a valid wv_live_ or wv_test_ key.';
|
|
108
|
+
case 'permission_error':
|
|
109
|
+
return `The API key does not hold ${tool?.scope ? `the \`${tool.scope}\` scope` : 'the scope this endpoint needs'}. Create a key with it in Dashboard → API keys.`;
|
|
110
|
+
case 'not_found_error':
|
|
111
|
+
return 'No such record on this account. A record owned by another account also returns 404. List the resource to find the right id.';
|
|
112
|
+
case 'conflict_error':
|
|
113
|
+
return 'The request conflicts with the record\'s current state. Fetch it and look at its status before retrying.';
|
|
114
|
+
case 'api_error':
|
|
115
|
+
return 'Something failed on the Wixzel side. Quote the request_id if reporting it. Retry once after a short wait.';
|
|
116
|
+
default:
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** Drop keys whose value is undefined so PATCH bodies only carry what was sent. */
|
|
121
|
+
export function compact(obj) {
|
|
122
|
+
const out = {};
|
|
123
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
124
|
+
if (value !== undefined)
|
|
125
|
+
out[key] = value;
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=tooling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tooling.js","sourceRoot":"","sources":["../src/tooling.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
import { id } from '../schemas.js';
|
|
3
|
+
export declare const agentTools: (import("../tooling.js").ToolDef<{
|
|
4
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
5
|
+
starting_after: z.ZodOptional<z.ZodString>;
|
|
6
|
+
ending_before: z.ZodOptional<z.ZodString>;
|
|
7
|
+
}> | import("../tooling.js").ToolDef<{
|
|
8
|
+
id: z.ZodString;
|
|
9
|
+
}> | import("../tooling.js").ToolDef<{
|
|
10
|
+
name: z.ZodString;
|
|
11
|
+
system_prompt: z.ZodString;
|
|
12
|
+
opening_message: z.ZodString;
|
|
13
|
+
voice: z.ZodObject<{
|
|
14
|
+
stt: z.ZodOptional<z.ZodObject<{
|
|
15
|
+
model: z.ZodString;
|
|
16
|
+
language: z.ZodOptional<z.ZodString>;
|
|
17
|
+
endpointing_ms: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
}, z.core.$strip>>;
|
|
19
|
+
llm: z.ZodOptional<z.ZodObject<{
|
|
20
|
+
model: z.ZodString;
|
|
21
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
22
|
+
max_tokens: z.ZodOptional<z.ZodNumber>;
|
|
23
|
+
}, z.core.$strip>>;
|
|
24
|
+
tts: z.ZodOptional<z.ZodObject<{
|
|
25
|
+
model: z.ZodString;
|
|
26
|
+
voice: z.ZodOptional<z.ZodString>;
|
|
27
|
+
stability: z.ZodOptional<z.ZodNumber>;
|
|
28
|
+
similarity_boost: z.ZodOptional<z.ZodNumber>;
|
|
29
|
+
speed: z.ZodOptional<z.ZodNumber>;
|
|
30
|
+
}, z.core.$strip>>;
|
|
31
|
+
realtime: z.ZodOptional<z.ZodObject<{
|
|
32
|
+
model: z.ZodString;
|
|
33
|
+
voice: z.ZodOptional<z.ZodString>;
|
|
34
|
+
language: z.ZodOptional<z.ZodString>;
|
|
35
|
+
}, z.core.$strip>>;
|
|
36
|
+
turn_taking: z.ZodOptional<z.ZodObject<{
|
|
37
|
+
interrupt_sensitivity: z.ZodOptional<z.ZodEnum<{
|
|
38
|
+
low: "low";
|
|
39
|
+
normal: "normal";
|
|
40
|
+
high: "high";
|
|
41
|
+
}>>;
|
|
42
|
+
silence_wait_ms: z.ZodOptional<z.ZodNumber>;
|
|
43
|
+
}, z.core.$strip>>;
|
|
44
|
+
}, z.core.$strip>;
|
|
45
|
+
language: z.ZodOptional<z.ZodString>;
|
|
46
|
+
knowledge_base_id: z.ZodOptional<z.ZodString>;
|
|
47
|
+
outbound_phone_number_id: z.ZodOptional<z.ZodString>;
|
|
48
|
+
appointment_booking_enabled: z.ZodOptional<z.ZodBoolean>;
|
|
49
|
+
}> | import("../tooling.js").ToolDef<{
|
|
50
|
+
id: z.ZodString;
|
|
51
|
+
to: z.ZodString;
|
|
52
|
+
from_number_id: z.ZodOptional<z.ZodString>;
|
|
53
|
+
phrase: z.ZodOptional<z.ZodString>;
|
|
54
|
+
idempotency_key: z.ZodOptional<z.ZodString>;
|
|
55
|
+
}> | import("../tooling.js").ToolDef<{
|
|
56
|
+
id: typeof id;
|
|
57
|
+
} & {
|
|
58
|
+
name: z.ZodOptional<z.ZodString>;
|
|
59
|
+
system_prompt: z.ZodOptional<z.ZodString>;
|
|
60
|
+
opening_message: z.ZodOptional<z.ZodString>;
|
|
61
|
+
voice: z.ZodOptional<z.ZodObject<{
|
|
62
|
+
stt: z.ZodOptional<z.ZodObject<{
|
|
63
|
+
model: z.ZodString;
|
|
64
|
+
language: z.ZodOptional<z.ZodString>;
|
|
65
|
+
endpointing_ms: z.ZodOptional<z.ZodNumber>;
|
|
66
|
+
}, z.core.$strip>>;
|
|
67
|
+
llm: z.ZodOptional<z.ZodObject<{
|
|
68
|
+
model: z.ZodString;
|
|
69
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
70
|
+
max_tokens: z.ZodOptional<z.ZodNumber>;
|
|
71
|
+
}, z.core.$strip>>;
|
|
72
|
+
tts: z.ZodOptional<z.ZodObject<{
|
|
73
|
+
model: z.ZodString;
|
|
74
|
+
voice: z.ZodOptional<z.ZodString>;
|
|
75
|
+
stability: z.ZodOptional<z.ZodNumber>;
|
|
76
|
+
similarity_boost: z.ZodOptional<z.ZodNumber>;
|
|
77
|
+
speed: z.ZodOptional<z.ZodNumber>;
|
|
78
|
+
}, z.core.$strip>>;
|
|
79
|
+
realtime: z.ZodOptional<z.ZodObject<{
|
|
80
|
+
model: z.ZodString;
|
|
81
|
+
voice: z.ZodOptional<z.ZodString>;
|
|
82
|
+
language: z.ZodOptional<z.ZodString>;
|
|
83
|
+
}, z.core.$strip>>;
|
|
84
|
+
turn_taking: z.ZodOptional<z.ZodObject<{
|
|
85
|
+
interrupt_sensitivity: z.ZodOptional<z.ZodEnum<{
|
|
86
|
+
low: "low";
|
|
87
|
+
normal: "normal";
|
|
88
|
+
high: "high";
|
|
89
|
+
}>>;
|
|
90
|
+
silence_wait_ms: z.ZodOptional<z.ZodNumber>;
|
|
91
|
+
}, z.core.$strip>>;
|
|
92
|
+
}, z.core.$strip>>;
|
|
93
|
+
language: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
94
|
+
knowledge_base_id: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
95
|
+
outbound_phone_number_id: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
96
|
+
appointment_booking_enabled: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
|
|
97
|
+
}>)[];
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
import { annotate, compact, defineTool } from '../tooling.js';
|
|
3
|
+
import { e164, id, idempotencyKey, pagination, voiceConfig } from '../schemas.js';
|
|
4
|
+
const agentFields = {
|
|
5
|
+
name: z.string().min(1).describe('A label for your own reference, e.g. "Support line".'),
|
|
6
|
+
system_prompt: z
|
|
7
|
+
.string()
|
|
8
|
+
.min(1)
|
|
9
|
+
.describe('The agent\'s instructions. This is a spoken conversation, so keep it short, concrete, and free of markdown.'),
|
|
10
|
+
opening_message: z
|
|
11
|
+
.string()
|
|
12
|
+
.min(1)
|
|
13
|
+
.describe('Spoken as soon as the call connects. Supports {{name}} style merge fields from the lead. Required: an agent without one answers in silence.'),
|
|
14
|
+
voice: voiceConfig,
|
|
15
|
+
language: z.string().optional().describe('BCP-47 tag for the conversation, e.g. "en-US" or "hi-IN".'),
|
|
16
|
+
knowledge_base_id: z.string().optional().describe('A knowledge base the agent can draw on. See list_knowledge_bases.'),
|
|
17
|
+
outbound_phone_number_id: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe('Default caller id for outbound calls placed with this agent. See list_phone_numbers.'),
|
|
21
|
+
appointment_booking_enabled: z
|
|
22
|
+
.boolean()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('Let the agent book appointments during a call.'),
|
|
25
|
+
};
|
|
26
|
+
export const agentTools = [
|
|
27
|
+
defineTool({
|
|
28
|
+
name: 'list_agents',
|
|
29
|
+
endpoint: 'GET /v1/agents',
|
|
30
|
+
title: 'List agents',
|
|
31
|
+
description: 'List the voice agents on this account. Cursor-paginated: pass next_cursor as starting_after for the next page.',
|
|
32
|
+
input: { ...pagination },
|
|
33
|
+
annotations: annotate.read,
|
|
34
|
+
scope: 'agents:read',
|
|
35
|
+
handler: (client, args) => client.get('/v1/agents', args),
|
|
36
|
+
}),
|
|
37
|
+
defineTool({
|
|
38
|
+
name: 'get_agent',
|
|
39
|
+
endpoint: 'GET /v1/agents/{id}',
|
|
40
|
+
title: 'Retrieve an agent',
|
|
41
|
+
description: 'Fetch one agent by id, including its full voice configuration and prompt.',
|
|
42
|
+
input: { id },
|
|
43
|
+
annotations: annotate.read,
|
|
44
|
+
scope: 'agents:read',
|
|
45
|
+
handler: (client, { id }) => client.get(`/v1/agents/${encodeURIComponent(id)}`),
|
|
46
|
+
}),
|
|
47
|
+
defineTool({
|
|
48
|
+
name: 'create_agent',
|
|
49
|
+
endpoint: 'POST /v1/agents',
|
|
50
|
+
title: 'Create an agent',
|
|
51
|
+
description: 'Create a voice agent. Pick models with list_engines first: an unavailable or mistyped model is rejected with unsupported_model. ' +
|
|
52
|
+
'voice is either a composed pipeline {stt, llm, tts} or a single {realtime} model, never both.',
|
|
53
|
+
input: agentFields,
|
|
54
|
+
annotations: annotate.write,
|
|
55
|
+
scope: 'agents:write',
|
|
56
|
+
handler: (client, args) => client.post('/v1/agents', compact(args)),
|
|
57
|
+
}),
|
|
58
|
+
defineTool({
|
|
59
|
+
name: 'test_call_agent',
|
|
60
|
+
endpoint: 'POST /v1/agents/{id}/test-call',
|
|
61
|
+
title: 'Place a test call',
|
|
62
|
+
description: 'Ring a number and have the agent speak one phrase, then hang up. A probe, not a conversation: it answers ' +
|
|
63
|
+
'"is the trunk configured and does this agent sound right" in seconds. For a real conversation use place_call. ' +
|
|
64
|
+
'THIS RINGS A REAL PHONE AND SPENDS REAL CREDIT — the meter runs on a test call exactly as on any other, so ' +
|
|
65
|
+
'confirm the number with the user first. Human transfer is not offered during a test call, so this cannot check ' +
|
|
66
|
+
'that a transfer destination answers. Needs calls:write.',
|
|
67
|
+
input: {
|
|
68
|
+
id,
|
|
69
|
+
to: e164.describe('Destination in E.164 form, e.g. "+14155551234". A real phone will ring.'),
|
|
70
|
+
from_number_id: z.string().optional().describe("Defaults to the agent's own outbound number. See list_phone_numbers."),
|
|
71
|
+
phrase: z.string().optional().describe("What to say. Defaults to the agent's opening message, which is usually what you want to hear."),
|
|
72
|
+
idempotency_key: idempotencyKey,
|
|
73
|
+
},
|
|
74
|
+
annotations: annotate.spend,
|
|
75
|
+
scope: 'calls:write',
|
|
76
|
+
handler: (client, { id, idempotency_key, ...body }) => client.post(`/v1/agents/${encodeURIComponent(id)}/test-call`, compact(body), { idempotencyKey: idempotency_key, idempotent: true }),
|
|
77
|
+
}),
|
|
78
|
+
defineTool({
|
|
79
|
+
name: 'update_agent',
|
|
80
|
+
endpoint: 'PATCH /v1/agents/{id}',
|
|
81
|
+
title: 'Update an agent',
|
|
82
|
+
description: 'Change an agent. Only the fields you send are changed; omit the rest. Sending voice replaces the whole voice object.',
|
|
83
|
+
input: {
|
|
84
|
+
id,
|
|
85
|
+
...Object.fromEntries(Object.entries(agentFields).map(([k, v]) => [k, v.optional()])),
|
|
86
|
+
},
|
|
87
|
+
annotations: annotate.write,
|
|
88
|
+
scope: 'agents:write',
|
|
89
|
+
handler: (client, { id, ...rest }) => client.patch(`/v1/agents/${encodeURIComponent(id)}`, compact(rest)),
|
|
90
|
+
}),
|
|
91
|
+
defineTool({
|
|
92
|
+
name: 'delete_agent',
|
|
93
|
+
endpoint: 'DELETE /v1/agents/{id}',
|
|
94
|
+
title: 'Delete an agent',
|
|
95
|
+
description: 'Permanently delete an agent. Phone numbers and campaigns pointing at it stop working. Not reversible.',
|
|
96
|
+
input: { id },
|
|
97
|
+
annotations: annotate.destructive,
|
|
98
|
+
scope: 'agents:write',
|
|
99
|
+
handler: async (client, { id }) => {
|
|
100
|
+
await client.delete(`/v1/agents/${encodeURIComponent(id)}`);
|
|
101
|
+
return { deleted: true, id };
|
|
102
|
+
},
|
|
103
|
+
}),
|
|
104
|
+
];
|
|
105
|
+
//# sourceMappingURL=agents.js.map
|