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.
Files changed (76) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/LICENSE +21 -0
  3. package/README.md +127 -0
  4. package/dist/client.d.ts +69 -0
  5. package/dist/client.js +137 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/guide.d.ts +11 -0
  8. package/dist/guide.js +86 -0
  9. package/dist/guide.js.map +1 -0
  10. package/dist/http.d.ts +80 -0
  11. package/dist/http.js +281 -0
  12. package/dist/http.js.map +1 -0
  13. package/dist/index.d.ts +17 -0
  14. package/dist/index.js +88 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/prompts.d.ts +7 -0
  17. package/dist/prompts.js +83 -0
  18. package/dist/prompts.js.map +1 -0
  19. package/dist/schemas.d.ts +105 -0
  20. package/dist/schemas.js +122 -0
  21. package/dist/schemas.js.map +1 -0
  22. package/dist/server.d.ts +16 -0
  23. package/dist/server.js +58 -0
  24. package/dist/server.js.map +1 -0
  25. package/dist/site.d.ts +12 -0
  26. package/dist/site.js +17 -0
  27. package/dist/site.js.map +1 -0
  28. package/dist/tooling.d.ts +59 -0
  29. package/dist/tooling.js +129 -0
  30. package/dist/tooling.js.map +1 -0
  31. package/dist/tools/agents.d.ts +97 -0
  32. package/dist/tools/agents.js +105 -0
  33. package/dist/tools/agents.js.map +1 -0
  34. package/dist/tools/api-keys.d.ts +37 -0
  35. package/dist/tools/api-keys.js +61 -0
  36. package/dist/tools/api-keys.js.map +1 -0
  37. package/dist/tools/appointments.d.ts +30 -0
  38. package/dist/tools/appointments.js +77 -0
  39. package/dist/tools/appointments.js.map +1 -0
  40. package/dist/tools/billing.d.ts +29 -0
  41. package/dist/tools/billing.js +72 -0
  42. package/dist/tools/billing.js.map +1 -0
  43. package/dist/tools/calls.d.ts +37 -0
  44. package/dist/tools/calls.js +98 -0
  45. package/dist/tools/calls.js.map +1 -0
  46. package/dist/tools/campaigns.d.ts +13 -0
  47. package/dist/tools/campaigns.js +76 -0
  48. package/dist/tools/campaigns.js.map +1 -0
  49. package/dist/tools/engines.d.ts +4 -0
  50. package/dist/tools/engines.js +43 -0
  51. package/dist/tools/engines.js.map +1 -0
  52. package/dist/tools/index.d.ts +5 -0
  53. package/dist/tools/index.js +37 -0
  54. package/dist/tools/index.js.map +1 -0
  55. package/dist/tools/knowledge-bases.d.ts +27 -0
  56. package/dist/tools/knowledge-bases.js +69 -0
  57. package/dist/tools/knowledge-bases.js.map +1 -0
  58. package/dist/tools/leads.d.ts +28 -0
  59. package/dist/tools/leads.js +88 -0
  60. package/dist/tools/leads.js.map +1 -0
  61. package/dist/tools/phone-numbers.d.ts +19 -0
  62. package/dist/tools/phone-numbers.js +72 -0
  63. package/dist/tools/phone-numbers.js.map +1 -0
  64. package/dist/tools/realtime.d.ts +8 -0
  65. package/dist/tools/realtime.js +28 -0
  66. package/dist/tools/realtime.js.map +1 -0
  67. package/dist/tools/sip-trunks.d.ts +45 -0
  68. package/dist/tools/sip-trunks.js +118 -0
  69. package/dist/tools/sip-trunks.js.map +1 -0
  70. package/dist/tools/webhooks.d.ts +52 -0
  71. package/dist/tools/webhooks.js +90 -0
  72. package/dist/tools/webhooks.js.map +1 -0
  73. package/dist/version.d.ts +7 -0
  74. package/dist/version.js +8 -0
  75. package/dist/version.js.map +1 -0
  76. package/package.json +65 -0
package/dist/http.js ADDED
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Streamable HTTP mode: the hosted server at mcp.voice.wixzel.com, and the
3
+ * same thing on a laptop with `--http`.
4
+ *
5
+ * Stateless by design. Every request carries its own `Authorization: Bearer`,
6
+ * which is a Wixzel Voice API key — either pasted by a developer into
7
+ * `claude mcp add --header`, or issued by the API's OAuth server after the
8
+ * user consented in the console. Either way this process builds a fresh MCP
9
+ * server bound to that key, answers the request, and forgets it. Nothing here
10
+ * can mix two users up, because nothing here remembers anyone.
11
+ *
12
+ * The OAuth half lives in the API (api/oauth/index.ts there). This side only
13
+ * has to say where it is: RFC 9728 protected-resource metadata, and a 401 that
14
+ * points at it, are what make claude.ai's "add custom connector" flow work.
15
+ */
16
+ import { createHash } from 'node:crypto';
17
+ import { createServer as createNodeServer } from 'node:http';
18
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
19
+ import { DEFAULT_BASE_URL } from './client.js';
20
+ import { scopes } from './schemas.js';
21
+ import { createServer, SERVER_VERSION } from './server.js';
22
+ import { consoleUrl, DEFAULT_CONSOLE_URL } from './site.js';
23
+ const LOOPBACK = new Set(['localhost', '127.0.0.1', '[::1]', '::1']);
24
+ /**
25
+ * The hosted server's names. It was mcp.phone.wixzel.com from 8 to 29 September
26
+ * 2026, and that name keeps serving so connectors added then keep working. An
27
+ * MCP client refuses protected-resource metadata whose resource is on another
28
+ * origin than the URL it connected to (the TypeScript SDK's
29
+ * checkResourceAllowed), so each name has to be advertised as itself.
30
+ */
31
+ const HOSTED_MCP_HOSTS = ['mcp.voice.wixzel.com', 'mcp.phone.wixzel.com'];
32
+ /** The other names of the host in publicUrl, if it is the hosted server; none otherwise. */
33
+ export function hostAliases(publicUrl) {
34
+ const host = new URL(publicUrl).host.toLowerCase();
35
+ return HOSTED_MCP_HOSTS.includes(host) ? HOSTED_MCP_HOSTS.filter((h) => h !== host) : [];
36
+ }
37
+ /**
38
+ * The resource a request addressed: publicUrl, or the same URL on the alias
39
+ * host it arrived on (nginx passes the client's Host through). Any other Host
40
+ * gets publicUrl, so a forged header can only pick between our own names.
41
+ */
42
+ export function resourceFor(publicUrl, aliases, hostHeader) {
43
+ const host = (hostHeader ?? '').trim().toLowerCase();
44
+ if (!host || !aliases.includes(host))
45
+ return publicUrl;
46
+ const url = new URL(publicUrl);
47
+ url.host = host;
48
+ return url.href.replace(/\/+$/, '');
49
+ }
50
+ function isLoopbackUrl(url) {
51
+ try {
52
+ return LOOPBACK.has(new URL(url).hostname);
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
58
+ /**
59
+ * Environment → options, with the one guard that matters: a fallback key on a
60
+ * host anyone can reach would hand that key's account to every anonymous
61
+ * caller. Refuse to start rather than trust the operator noticed.
62
+ */
63
+ export function resolveHttpOptions(env, cliPort) {
64
+ const port = cliPort ?? (Number(env.MCP_PORT) || 3939);
65
+ const bind = env.MCP_BIND || '127.0.0.1';
66
+ const publicUrl = (env.MCP_PUBLIC_URL || `http://localhost:${port}/mcp`).replace(/\/+$/, '');
67
+ const fallbackKey = env.WIXZEL_API_KEY || undefined;
68
+ if (fallbackKey && !isLoopbackUrl(publicUrl)) {
69
+ throw new Error(`WIXZEL_API_KEY is set but MCP_PUBLIC_URL (${publicUrl}) is not a loopback address. ` +
70
+ 'A fallback key on a public host would be handed to every anonymous caller. Unset one of them.');
71
+ }
72
+ return {
73
+ port,
74
+ bind,
75
+ publicUrl,
76
+ hostAliases: hostAliases(publicUrl),
77
+ apiBaseUrl: (env.WIXZEL_API_BASE_URL || DEFAULT_BASE_URL).replace(/\/+$/, ''),
78
+ consoleUrl: consoleUrl(env),
79
+ apiVersion: env.WIXZEL_API_VERSION || undefined,
80
+ fallbackKey,
81
+ };
82
+ }
83
+ const PROBE_OK_MS = 60_000;
84
+ const PROBE_REJECTED_MS = 10_000;
85
+ export class TokenProbe {
86
+ apiBaseUrl;
87
+ fetchImpl;
88
+ cache = new Map();
89
+ constructor(apiBaseUrl, fetchImpl) {
90
+ this.apiBaseUrl = apiBaseUrl;
91
+ this.fetchImpl = fetchImpl;
92
+ }
93
+ async check(apiKey) {
94
+ const id = createHash('sha256').update(apiKey).digest('hex');
95
+ const hit = this.cache.get(id);
96
+ if (hit && hit.until > Date.now())
97
+ return hit.verdict;
98
+ let verdict;
99
+ try {
100
+ const res = await this.fetchImpl(`${this.apiBaseUrl}/v1/engines`, {
101
+ headers: { Authorization: `Bearer ${apiKey}`, Accept: 'application/json' },
102
+ signal: AbortSignal.timeout(5_000),
103
+ });
104
+ verdict = res.status === 401 ? 'rejected' : res.status < 500 ? 'ok' : 'unknown';
105
+ }
106
+ catch {
107
+ verdict = 'unknown';
108
+ }
109
+ if (verdict !== 'unknown') {
110
+ this.cache.set(id, { verdict, until: Date.now() + (verdict === 'ok' ? PROBE_OK_MS : PROBE_REJECTED_MS) });
111
+ }
112
+ if (this.cache.size > 10_000)
113
+ this.cache.clear();
114
+ return verdict;
115
+ }
116
+ }
117
+ // ─── The handler ────────────────────────────────────────────────────────────
118
+ function bearerFrom(req) {
119
+ const header = req.headers.authorization;
120
+ if (!header)
121
+ return undefined;
122
+ const match = /^Bearer\s+(.+)$/i.exec(header);
123
+ return match?.[1]?.trim() || undefined;
124
+ }
125
+ /** No cookies exist on this host, so a wildcard is safe and browser-based MCP clients need it. */
126
+ function cors(res) {
127
+ res.setHeader('Access-Control-Allow-Origin', '*');
128
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
129
+ res.setHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type, Accept, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID');
130
+ res.setHeader('Access-Control-Expose-Headers', 'WWW-Authenticate, Mcp-Session-Id, Mcp-Protocol-Version');
131
+ res.setHeader('Access-Control-Max-Age', '86400');
132
+ }
133
+ function json(res, status, body, headers = {}) {
134
+ res.writeHead(status, { 'content-type': 'application/json', 'cache-control': 'no-store', ...headers });
135
+ res.end(JSON.stringify(body));
136
+ }
137
+ export function protectedResourceMetadata(opts, resource = opts.publicUrl) {
138
+ return {
139
+ resource,
140
+ authorization_servers: [opts.apiBaseUrl],
141
+ bearer_methods_supported: ['header'],
142
+ scopes_supported: [...scopes],
143
+ resource_name: 'Wixzel Voice',
144
+ resource_documentation: 'https://docs.voice.wixzel.com/mcp-server',
145
+ };
146
+ }
147
+ /** RFC 9728 §3: the well-known path carries the resource's own path as a suffix. */
148
+ export function resourceMetadataUrl(publicUrl) {
149
+ const url = new URL(publicUrl);
150
+ const suffix = url.pathname === '/' ? '' : url.pathname;
151
+ return `${url.origin}/.well-known/oauth-protected-resource${suffix}`;
152
+ }
153
+ export function createHttpHandler(opts) {
154
+ const fetchImpl = opts.fetch ?? globalThis.fetch;
155
+ const probe = new TokenProbe(opts.apiBaseUrl, fetchImpl);
156
+ const log = opts.log ?? ((line) => process.stderr.write(`${line}\n`));
157
+ const metadataPaths = new Set(['/.well-known/oauth-protected-resource', new URL(resourceMetadataUrl(opts.publicUrl)).pathname]);
158
+ const mcpPath = new URL(opts.publicUrl).pathname === '/' ? '/mcp' : new URL(opts.publicUrl).pathname;
159
+ const aliases = (opts.hostAliases ?? hostAliases(opts.publicUrl)).map((h) => h.toLowerCase());
160
+ const challenge = (resource, error) => `Bearer realm="wixzel-voice-mcp", resource_metadata="${resourceMetadataUrl(resource)}"` +
161
+ (error ? `, error="${error}"` : '');
162
+ return async (req, res) => {
163
+ const url = new URL(req.url ?? '/', 'http://localhost');
164
+ const resource = resourceFor(opts.publicUrl, aliases, req.headers.host);
165
+ cors(res);
166
+ if (req.method === 'OPTIONS') {
167
+ res.writeHead(204);
168
+ res.end();
169
+ return;
170
+ }
171
+ if (url.pathname === '/healthz') {
172
+ return json(res, 200, { ok: true, name: 'wixzel-voice-mcp', version: SERVER_VERSION });
173
+ }
174
+ // People do open the bare host in a browser, and connector UIs that
175
+ // want an icon parse this page for one. A sentence and a few links.
176
+ if (url.pathname === '/' && (req.method === 'GET' || req.method === 'HEAD')) {
177
+ res.writeHead(200, { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'public, max-age=3600' });
178
+ res.end(LANDING_HTML(mcpPath, opts.publicUrl, (opts.consoleUrl ?? consoleUrl()).replace(/\/+$/, '')));
179
+ return;
180
+ }
181
+ if (metadataPaths.has(url.pathname)) {
182
+ // Varies by Host now that one process answers for two names.
183
+ return json(res, 200, protectedResourceMetadata(opts, resource), { 'cache-control': 'public, max-age=300', vary: 'Host' });
184
+ }
185
+ if (url.pathname !== mcpPath) {
186
+ return json(res, 404, { error: 'not_found', message: `MCP is served at ${mcpPath}` });
187
+ }
188
+ const presented = bearerFrom(req);
189
+ const apiKey = presented ?? opts.fallbackKey;
190
+ if (!apiKey) {
191
+ return json(res, 401, {
192
+ error: 'unauthorized',
193
+ message: 'Send a Wixzel Voice API key as "Authorization: Bearer wv_live_…", or connect through OAuth.',
194
+ }, { 'www-authenticate': challenge(resource) });
195
+ }
196
+ if (presented && (await probe.check(presented)) === 'rejected') {
197
+ return json(res, 401, {
198
+ error: 'invalid_token',
199
+ message: 'That API key is invalid, revoked or expired. Reconnect to obtain a new one.',
200
+ }, { 'www-authenticate': challenge(resource, 'invalid_token') });
201
+ }
202
+ const clientOptions = {
203
+ apiKey,
204
+ baseUrl: opts.apiBaseUrl,
205
+ apiVersion: opts.apiVersion,
206
+ fetch: fetchImpl,
207
+ };
208
+ const server = createServer({ client: clientOptions });
209
+ const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
210
+ // The transport decides most 4xx answers itself and says why only
211
+ // through this hook; without it a client's "couldn't load tools" is
212
+ // a status code and nothing else in the logs.
213
+ transport.onerror = (error) => log(`wixzel-voice-mcp: transport: ${error.message}`);
214
+ server.server.onerror = (error) => log(`wixzel-voice-mcp: server: ${error.message}`);
215
+ res.on('finish', () => {
216
+ if (res.statusCode >= 400) {
217
+ const h = req.headers;
218
+ log(`wixzel-voice-mcp: ${res.statusCode} ${req.method} ${url.pathname}` +
219
+ ` accept=${JSON.stringify(h.accept ?? null)} content-type=${JSON.stringify(h['content-type'] ?? null)}` +
220
+ ` length=${h['content-length'] ?? '?'} protocol=${h['mcp-protocol-version'] ?? '-'} session=${h['mcp-session-id'] ? 'yes' : 'no'}` +
221
+ ` ua=${JSON.stringify(h['user-agent'] ?? null)}`);
222
+ }
223
+ });
224
+ res.on('close', () => {
225
+ void transport.close();
226
+ void server.close();
227
+ });
228
+ try {
229
+ await server.connect(transport);
230
+ await transport.handleRequest(req, res);
231
+ }
232
+ catch (error) {
233
+ log(`wixzel-voice-mcp: request failed: ${error.message}`);
234
+ if (!res.headersSent)
235
+ json(res, 500, { error: 'internal_error' });
236
+ }
237
+ };
238
+ }
239
+ const LANDING_HTML = (mcpPath, publicUrl, consoleBase) => {
240
+ // Our product pages only on our own server. A self-hosted install links
241
+ // its own console and the public docs, and nothing that sells.
242
+ const product = consoleBase === DEFAULT_CONSOLE_URL
243
+ ? ` · <a href="${DEFAULT_CONSOLE_URL}/solutions/ai-agents-mcp">What you can build</a> · <a href="${DEFAULT_CONSOLE_URL}">Wixzel Voice</a>`
244
+ : '';
245
+ return `<!doctype html>
246
+ <html lang="en"><head><meta charset="utf-8"><title>Wixzel Voice MCP server</title>
247
+ <meta name="viewport" content="width=device-width,initial-scale=1">
248
+ <meta name="description" content="Connect Claude, ChatGPT, Cursor or any other MCP client to Wixzel Voice and build AI agents that place and answer real phone calls.">
249
+ <link rel="icon" href="/favicon.ico"><link rel="icon" type="image/png" sizes="192x192" href="/icon-192.png">
250
+ <link rel="apple-touch-icon" href="/apple-touch-icon.png">
251
+ <style>body{margin:0;min-height:100vh;display:grid;place-items:center;background:#0d0d0d;color:#e8e8e8;font:15px/1.5 system-ui,sans-serif}main{max-width:32rem;padding:2rem}code{background:#1a1a1a;padding:.15em .4em;border-radius:.3em}a{color:#a0d425}</style>
252
+ </head><body><main>
253
+ <img src="/icon-192.png" alt="" width="48" height="48">
254
+ <h1>Wixzel Voice MCP server</h1>
255
+ <p>Connect Claude, ChatGPT, Cursor or any other MCP client to Wixzel Voice and build AI agents that place and answer real phone calls.</p>
256
+ <p>This host speaks the Model Context Protocol at <code>${mcpPath}</code>. Add it as a connector in claude.ai or Claude Desktop, or run <code>claude mcp add --transport http wixzel-voice ${publicUrl}</code>.</p>
257
+ <p><a href="https://docs.voice.wixzel.com/mcp-server">Documentation</a> · <a href="${consoleBase}/connect">Connect your account</a>${product}</p>
258
+ </main></body></html>
259
+ `;
260
+ };
261
+ export async function startHttp(opts) {
262
+ const handler = createHttpHandler(opts);
263
+ const server = createNodeServer((req, res) => {
264
+ void handler(req, res);
265
+ });
266
+ await new Promise((resolve, reject) => {
267
+ server.once('error', reject);
268
+ server.listen(opts.port, opts.bind, () => {
269
+ server.off('error', reject);
270
+ resolve();
271
+ });
272
+ });
273
+ const address = server.address();
274
+ const port = typeof address === 'object' && address ? address.port : opts.port;
275
+ return {
276
+ server,
277
+ port,
278
+ close: () => new Promise((resolve) => server.close(() => resolve())),
279
+ };
280
+ }
281
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * wixzel-voice-mcp
4
+ *
5
+ * wixzel-voice-mcp stdio transport, key from WIXZEL_API_KEY
6
+ * wixzel-voice-mcp --http [port] Streamable HTTP on /mcp; each request's
7
+ * Authorization: Bearer is the API key
8
+ *
9
+ * Environment:
10
+ * WIXZEL_API_KEY wv_live_… or wv_test_… (required for stdio; a local-only fallback for --http)
11
+ * WIXZEL_API_BASE_URL default https://api.voice.wixzel.com
12
+ * WIXZEL_API_VERSION optional Wixzel-Version date pin
13
+ * MCP_PORT --http port (default 3939)
14
+ * MCP_BIND --http interface (default 127.0.0.1)
15
+ * MCP_PUBLIC_URL the URL clients use, e.g. https://mcp.voice.wixzel.com/mcp
16
+ */
17
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * wixzel-voice-mcp
4
+ *
5
+ * wixzel-voice-mcp stdio transport, key from WIXZEL_API_KEY
6
+ * wixzel-voice-mcp --http [port] Streamable HTTP on /mcp; each request's
7
+ * Authorization: Bearer is the API key
8
+ *
9
+ * Environment:
10
+ * WIXZEL_API_KEY wv_live_… or wv_test_… (required for stdio; a local-only fallback for --http)
11
+ * WIXZEL_API_BASE_URL default https://api.voice.wixzel.com
12
+ * WIXZEL_API_VERSION optional Wixzel-Version date pin
13
+ * MCP_PORT --http port (default 3939)
14
+ * MCP_BIND --http interface (default 127.0.0.1)
15
+ * MCP_PUBLIC_URL the URL clients use, e.g. https://mcp.voice.wixzel.com/mcp
16
+ */
17
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
18
+ import { DEFAULT_BASE_URL } from './client.js';
19
+ import { resolveHttpOptions, startHttp } from './http.js';
20
+ import { createServer, SERVER_VERSION } from './server.js';
21
+ import { consoleUrl } from './site.js';
22
+ const HELP = `wixzel-voice-mcp ${SERVER_VERSION}
23
+
24
+ Usage:
25
+ wixzel-voice-mcp Run over stdio (for Claude Code, Claude Desktop, Cursor…)
26
+ wixzel-voice-mcp --http [port] Run a Streamable HTTP server (default http://127.0.0.1:3939/mcp)
27
+ wixzel-voice-mcp --help
28
+
29
+ Environment:
30
+ WIXZEL_API_KEY Your API key. Required for stdio. For --http it is only accepted on a loopback MCP_PUBLIC_URL.
31
+ WIXZEL_API_BASE_URL Defaults to ${DEFAULT_BASE_URL}
32
+ WIXZEL_API_VERSION Optional Wixzel-Version date pin, e.g. 2026-09-01
33
+ MCP_PORT, MCP_BIND, MCP_PUBLIC_URL --http settings; see README
34
+ `;
35
+ async function runStdio() {
36
+ const apiKey = process.env.WIXZEL_API_KEY;
37
+ if (!apiKey) {
38
+ process.stderr.write('wixzel-voice-mcp: WIXZEL_API_KEY is not set.\n' +
39
+ `Create a key at ${consoleUrl()}/connect and pass it as an environment variable.\n`);
40
+ process.exit(1);
41
+ }
42
+ const server = createServer({
43
+ client: {
44
+ apiKey,
45
+ baseUrl: process.env.WIXZEL_API_BASE_URL || undefined,
46
+ apiVersion: process.env.WIXZEL_API_VERSION || undefined,
47
+ },
48
+ });
49
+ await server.connect(new StdioServerTransport());
50
+ // stdout is the protocol channel; everything human goes to stderr.
51
+ process.stderr.write(`wixzel-voice-mcp ${SERVER_VERSION} ready on stdio (${apiKey.slice(0, 8)}…)\n`);
52
+ }
53
+ async function runHttp(cliPort) {
54
+ const opts = resolveHttpOptions(process.env, cliPort);
55
+ const running = await startHttp(opts);
56
+ process.stderr.write(`wixzel-voice-mcp ${SERVER_VERSION} listening on http://${opts.bind}:${running.port}${new URL(opts.publicUrl).pathname}` +
57
+ ` as ${opts.publicUrl}` +
58
+ (opts.fallbackKey ? ' (WIXZEL_API_KEY fallback, loopback only)' : ' (bearer or OAuth required)') +
59
+ '\n');
60
+ const shutdown = () => {
61
+ void running.close().then(() => process.exit(0));
62
+ };
63
+ process.on('SIGTERM', shutdown);
64
+ process.on('SIGINT', shutdown);
65
+ }
66
+ async function main() {
67
+ const args = process.argv.slice(2);
68
+ if (args.includes('--help') || args.includes('-h')) {
69
+ process.stdout.write(HELP);
70
+ return;
71
+ }
72
+ if (args.includes('--version') || args.includes('-v')) {
73
+ process.stdout.write(`${SERVER_VERSION}\n`);
74
+ return;
75
+ }
76
+ const httpIndex = args.indexOf('--http');
77
+ if (httpIndex !== -1) {
78
+ const explicit = args[httpIndex + 1];
79
+ await runHttp(explicit && /^\d+$/.test(explicit) ? Number(explicit) : undefined);
80
+ return;
81
+ }
82
+ await runStdio();
83
+ }
84
+ main().catch((error) => {
85
+ process.stderr.write(`wixzel-voice-mcp: ${error.message}\n`);
86
+ process.exit(1);
87
+ });
88
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ /**
3
+ * Prompts are the slash-command surface: in Claude Code they appear as
4
+ * /mcp__wixzel-voice__<name>. Each one is a worked procedure, phrased as a
5
+ * request the user would make.
6
+ */
7
+ export declare function registerPrompts(server: McpServer): void;
@@ -0,0 +1,83 @@
1
+ import { z } from 'zod/v4';
2
+ import { GUIDE } from './guide.js';
3
+ /**
4
+ * Prompts are the slash-command surface: in Claude Code they appear as
5
+ * /mcp__wixzel-voice__<name>. Each one is a worked procedure, phrased as a
6
+ * request the user would make.
7
+ */
8
+ export function registerPrompts(server) {
9
+ server.registerPrompt('quickstart', {
10
+ title: 'Set up Wixzel Voice from nothing',
11
+ description: 'Walk through connecting a carrier, registering a number, building an agent and placing a first call, checking in with the user at each step that costs money or needs their credentials.',
12
+ argsSchema: {
13
+ goal: z
14
+ .string()
15
+ .optional()
16
+ .describe('What the agent should do on calls, e.g. "confirm dental appointments". Optional.'),
17
+ },
18
+ }, ({ goal }) => ({
19
+ messages: [
20
+ {
21
+ role: 'user',
22
+ content: {
23
+ type: 'text',
24
+ text: `${GUIDE}\n\n---\n\n` +
25
+ `Set up my Wixzel Voice account so an agent can make calls${goal ? ` to ${goal}` : ''}. ` +
26
+ 'Start by checking what already exists (list_sip_trunks, list_phone_numbers, list_agents, get_balance) so nothing is duplicated. ' +
27
+ 'Then follow the setup order in the guide. Ask me for carrier credentials rather than inventing them, ' +
28
+ 'and stop to confirm before anything that spends money or dials a phone. ' +
29
+ 'At the end, tell me exactly what was created (with ids) and what I still have to do at my carrier.',
30
+ },
31
+ },
32
+ ],
33
+ }));
34
+ server.registerPrompt('diagnose_call', {
35
+ title: 'Diagnose a failed or odd call',
36
+ description: 'Pull the call record, its usage events, the trunk status and recent SIP logs, and explain what happened and what to change.',
37
+ argsSchema: {
38
+ call_id: z.string().describe('The call id from list_calls or place_call.'),
39
+ },
40
+ }, ({ call_id }) => ({
41
+ messages: [
42
+ {
43
+ role: 'user',
44
+ content: {
45
+ type: 'text',
46
+ text: `Diagnose Wixzel Voice call ${call_id}. ` +
47
+ 'Fetch it with get_call and read status, failure_code, failure_reason, errors and transfers. ' +
48
+ 'Pull list_usage_events with its session_id to see what was billed. ' +
49
+ 'If it did not connect, find the phone number and trunk it used (list_phone_numbers, get_sip_trunk), run check_sip_trunk_status and get_sip_trunk_logs, ' +
50
+ 'and read the transcript if there is one. ' +
51
+ 'Report: what happened in one paragraph, the evidence (quote codes and log lines), and the concrete fix, ' +
52
+ 'distinguishing carrier-side configuration (allowlisting platform_ip, origination URI, credentials) from agent configuration. ' +
53
+ 'Do not place any new calls while diagnosing.',
54
+ },
55
+ },
56
+ ],
57
+ }));
58
+ server.registerPrompt('spend_report', {
59
+ title: 'Explain recent spend',
60
+ description: 'Summarise what the account spent over a period, by component and by call, in plain dollars.',
61
+ argsSchema: {
62
+ period: z
63
+ .string()
64
+ .optional()
65
+ .describe('Human phrase such as "this month", "last 7 days", or an ISO date range. Defaults to this month.'),
66
+ },
67
+ }, ({ period }) => ({
68
+ messages: [
69
+ {
70
+ role: 'user',
71
+ content: {
72
+ type: 'text',
73
+ text: `Explain my Wixzel Voice spend for ${period ?? 'this month'}. ` +
74
+ 'Use get_usage_summary for the totals by component and model, get_balance for what is left, and list_calls (with started_after/started_before) to find the most expensive calls, ' +
75
+ 'then list_usage_events by session_id for the top two or three. ' +
76
+ 'Convert micro-USD to dollars (1,000,000 = $1.00). Present a short table by component, the top calls with duration and cost, and one or two suggestions for reducing cost, ' +
77
+ 'such as a cheaper model from list_engines or a lower max_tokens.',
78
+ },
79
+ },
80
+ ],
81
+ }));
82
+ }
83
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAC3B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC7C,MAAM,CAAC,cAAc,CACjB,YAAY,EACZ;QACI,KAAK,EAAE,kCAAkC;QACzC,WAAW,EACP,0LAA0L;QAC9L,UAAU,EAAE;YACR,IAAI,EAAE,CAAC;iBACF,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,kFAAkF,CAAC;SACpG;KACJ,EACD,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE;YACN;gBACI,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACL,IAAI,EAAE,MAAM;oBACZ,IAAI,EACA,GAAG,KAAK,aAAa;wBACrB,4DAA4D,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI;wBACzF,kIAAkI;wBAClI,uGAAuG;wBACvG,0EAA0E;wBAC1E,oGAAoG;iBAC3G;aACJ;SACJ;KACJ,CAAC,CACL,CAAC;IAEF,MAAM,CAAC,cAAc,CACjB,eAAe,EACf;QACI,KAAK,EAAE,+BAA+B;QACtC,WAAW,EAAE,6HAA6H;QAC1I,UAAU,EAAE;YACR,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;SAC7E;KACJ,EACD,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QACd,QAAQ,EAAE;YACN;gBACI,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACL,IAAI,EAAE,MAAM;oBACZ,IAAI,EACA,8BAA8B,OAAO,IAAI;wBACzC,8FAA8F;wBAC9F,qEAAqE;wBACrE,yJAAyJ;wBACzJ,2CAA2C;wBAC3C,0GAA0G;wBAC1G,+HAA+H;wBAC/H,8CAA8C;iBACrD;aACJ;SACJ;KACJ,CAAC,CACL,CAAC;IAEF,MAAM,CAAC,cAAc,CACjB,cAAc,EACd;QACI,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EAAE,6FAA6F;QAC1G,UAAU,EAAE;YACR,MAAM,EAAE,CAAC;iBACJ,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,iGAAiG,CAAC;SACnH;KACJ,EACD,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QACb,QAAQ,EAAE;YACN;gBACI,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACL,IAAI,EAAE,MAAM;oBACZ,IAAI,EACA,qCAAqC,MAAM,IAAI,YAAY,IAAI;wBAC/D,kLAAkL;wBAClL,iEAAiE;wBACjE,4KAA4K;wBAC5K,kEAAkE;iBACzE;aACJ;SACJ;KACJ,CAAC,CACL,CAAC;AACN,CAAC"}
@@ -0,0 +1,105 @@
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 declare const id: z.ZodString;
9
+ export declare const pagination: {
10
+ limit: z.ZodOptional<z.ZodNumber>;
11
+ starting_after: z.ZodOptional<z.ZodString>;
12
+ ending_before: z.ZodOptional<z.ZodString>;
13
+ };
14
+ export declare const isoDate: z.ZodString;
15
+ export declare const e164: z.ZodString;
16
+ export declare const sttConfig: z.ZodObject<{
17
+ model: z.ZodString;
18
+ language: z.ZodOptional<z.ZodString>;
19
+ endpointing_ms: z.ZodOptional<z.ZodNumber>;
20
+ }, z.core.$strip>;
21
+ export declare const llmConfig: z.ZodObject<{
22
+ model: z.ZodString;
23
+ temperature: z.ZodOptional<z.ZodNumber>;
24
+ max_tokens: z.ZodOptional<z.ZodNumber>;
25
+ }, z.core.$strip>;
26
+ export declare const ttsConfig: z.ZodObject<{
27
+ model: z.ZodString;
28
+ voice: z.ZodOptional<z.ZodString>;
29
+ stability: z.ZodOptional<z.ZodNumber>;
30
+ similarity_boost: z.ZodOptional<z.ZodNumber>;
31
+ speed: z.ZodOptional<z.ZodNumber>;
32
+ }, z.core.$strip>;
33
+ export declare const realtimeConfig: z.ZodObject<{
34
+ model: z.ZodString;
35
+ voice: z.ZodOptional<z.ZodString>;
36
+ language: z.ZodOptional<z.ZodString>;
37
+ }, z.core.$strip>;
38
+ export declare const turnTaking: z.ZodObject<{
39
+ interrupt_sensitivity: z.ZodOptional<z.ZodEnum<{
40
+ low: "low";
41
+ normal: "normal";
42
+ high: "high";
43
+ }>>;
44
+ silence_wait_ms: z.ZodOptional<z.ZodNumber>;
45
+ }, z.core.$strip>;
46
+ export declare const voiceConfig: z.ZodObject<{
47
+ stt: z.ZodOptional<z.ZodObject<{
48
+ model: z.ZodString;
49
+ language: z.ZodOptional<z.ZodString>;
50
+ endpointing_ms: z.ZodOptional<z.ZodNumber>;
51
+ }, z.core.$strip>>;
52
+ llm: z.ZodOptional<z.ZodObject<{
53
+ model: z.ZodString;
54
+ temperature: z.ZodOptional<z.ZodNumber>;
55
+ max_tokens: z.ZodOptional<z.ZodNumber>;
56
+ }, z.core.$strip>>;
57
+ tts: z.ZodOptional<z.ZodObject<{
58
+ model: z.ZodString;
59
+ voice: z.ZodOptional<z.ZodString>;
60
+ stability: z.ZodOptional<z.ZodNumber>;
61
+ similarity_boost: z.ZodOptional<z.ZodNumber>;
62
+ speed: z.ZodOptional<z.ZodNumber>;
63
+ }, z.core.$strip>>;
64
+ realtime: z.ZodOptional<z.ZodObject<{
65
+ model: z.ZodString;
66
+ voice: z.ZodOptional<z.ZodString>;
67
+ language: z.ZodOptional<z.ZodString>;
68
+ }, z.core.$strip>>;
69
+ turn_taking: z.ZodOptional<z.ZodObject<{
70
+ interrupt_sensitivity: z.ZodOptional<z.ZodEnum<{
71
+ low: "low";
72
+ normal: "normal";
73
+ high: "high";
74
+ }>>;
75
+ silence_wait_ms: z.ZodOptional<z.ZodNumber>;
76
+ }, z.core.$strip>>;
77
+ }, z.core.$strip>;
78
+ export declare const scopes: readonly ["agents:read", "agents:write", "calls:read", "calls:write", "leads:read", "leads:write", "campaigns:read", "campaigns:write", "knowledge_bases:read", "knowledge_bases:write", "phone_numbers:read", "phone_numbers:write", "sip_trunks:read", "sip_trunks:write", "appointments:read", "appointments:write", "webhooks:read", "webhooks:write", "api_keys:read", "api_keys:write", "usage:read", "billing:read", "billing:write"];
79
+ export declare const scope: z.ZodEnum<{
80
+ "agents:read": "agents:read";
81
+ "agents:write": "agents:write";
82
+ "calls:read": "calls:read";
83
+ "calls:write": "calls:write";
84
+ "leads:read": "leads:read";
85
+ "leads:write": "leads:write";
86
+ "campaigns:read": "campaigns:read";
87
+ "campaigns:write": "campaigns:write";
88
+ "knowledge_bases:read": "knowledge_bases:read";
89
+ "knowledge_bases:write": "knowledge_bases:write";
90
+ "phone_numbers:read": "phone_numbers:read";
91
+ "phone_numbers:write": "phone_numbers:write";
92
+ "sip_trunks:read": "sip_trunks:read";
93
+ "sip_trunks:write": "sip_trunks:write";
94
+ "appointments:read": "appointments:read";
95
+ "appointments:write": "appointments:write";
96
+ "webhooks:read": "webhooks:read";
97
+ "webhooks:write": "webhooks:write";
98
+ "api_keys:read": "api_keys:read";
99
+ "api_keys:write": "api_keys:write";
100
+ "usage:read": "usage:read";
101
+ "billing:read": "billing:read";
102
+ "billing:write": "billing:write";
103
+ }>;
104
+ export declare const arbitraryFields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
105
+ export declare const idempotencyKey: z.ZodOptional<z.ZodString>;