@rymi/mcp 2.0.0 → 2.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 +34 -2
- package/dist/index.js +618 -15
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -73,7 +73,15 @@ Run the server on your own machine — it speaks **stdio** by default and talks
|
|
|
73
73
|
<tr><th>Group</th><th>Tools</th></tr>
|
|
74
74
|
<tr>
|
|
75
75
|
<td><b>Agents</b></td>
|
|
76
|
-
<td><code>list_agents</code> · <code>get_agent</code> · <code>create_agent</code> · <code>update_agent</code> · <code>delete_agent</code> · <code>clone_agent</code> · <code>apply_agent_changes</code> · <code>generate_agent_draft</code> · <code>enrich_company</code> · <code>validate_agent_publish</code> · <code>preview_stack</code></td>
|
|
76
|
+
<td><code>list_agents</code> · <code>get_agent</code> · <code>create_agent</code> · <code>update_agent</code> · <code>delete_agent</code> · <code>clone_agent</code> · <code>apply_agent_changes</code> · <code>generate_agent_draft</code> · <code>enrich_company</code> · <code>validate_agent_publish</code> · <code>preview_stack</code> · <code>publish_agent</code></td>
|
|
77
|
+
</tr>
|
|
78
|
+
<tr>
|
|
79
|
+
<td><b>API tools & secrets</b></td>
|
|
80
|
+
<td><code>list_agent_tools</code> · <code>add_agent_tool</code> · <code>update_agent_tool</code> · <code>remove_agent_tool</code> · <code>list_tool_secrets</code> · <code>set_tool_secret</code></td>
|
|
81
|
+
</tr>
|
|
82
|
+
<tr>
|
|
83
|
+
<td><b>Share link</b></td>
|
|
84
|
+
<td><code>get_share_link</code> · <code>set_share_link</code> · <code>regenerate_share_link</code></td>
|
|
77
85
|
</tr>
|
|
78
86
|
<tr>
|
|
79
87
|
<td><b>Discovery</b></td>
|
|
@@ -85,13 +93,17 @@ Run the server on your own machine — it speaks **stdio** by default and talks
|
|
|
85
93
|
</tr>
|
|
86
94
|
<tr>
|
|
87
95
|
<td><b>Insight</b></td>
|
|
88
|
-
<td><code>get_usage_summary</code> (minutes-based) · <code>list_agent_templates</code> · <code>run_evals</code> · <code>list_eval_runs</code> · <code>get_eval_run</code></td>
|
|
96
|
+
<td><code>get_usage_summary</code> (minutes-based) · <code>list_agent_templates</code> · <code>run_evals</code> · <code>run_eval_suite</code> · <code>list_eval_runs</code> · <code>get_eval_run</code></td>
|
|
89
97
|
</tr>
|
|
90
98
|
<tr>
|
|
91
99
|
<td><b>Calls</b> <sub>(read-only)</sub></td>
|
|
92
100
|
<td><code>list_calls</code> · <code>list_active_calls</code> · <code>get_call</code> · <code>get_call_summary</code> · <code>get_call_transcript</code> · <code>get_call_recording</code> · <code>get_call_queue_stats</code> · <code>reprocess_call</code> · <code>list_calls_for_agent</code></td>
|
|
93
101
|
</tr>
|
|
94
102
|
<tr>
|
|
103
|
+
<td><b>Call control</b></td>
|
|
104
|
+
<td><code>create_call</code> · <code>batch_call</code> · <code>end_call</code> · <code>add_call_participant</code></td>
|
|
105
|
+
</tr>
|
|
106
|
+
<tr>
|
|
95
107
|
<td><b>Numbers</b></td>
|
|
96
108
|
<td><code>list_numbers</code> · <code>register_number</code> · <code>attach_number</code> · <code>remove_number</code></td>
|
|
97
109
|
</tr>
|
|
@@ -103,6 +115,26 @@ Run the server on your own machine — it speaks **stdio** by default and talks
|
|
|
103
115
|
<td><b>Keys</b> <sub>(read-only)</sub></td>
|
|
104
116
|
<td><code>list_publishable_keys</code></td>
|
|
105
117
|
</tr>
|
|
118
|
+
<tr>
|
|
119
|
+
<td><b>Campaigns</b></td>
|
|
120
|
+
<td><code>list_campaigns</code> · <code>get_campaign</code> · <code>get_campaign_report</code> · <code>list_campaign_attempts</code> · <code>list_campaign_suggestions</code> · <code>list_contacts</code> · <code>create_campaign</code> · <code>import_campaign_contacts</code> · <code>launch_campaign</code> · <code>pause_campaign</code> · <code>resume_campaign</code> · <code>accept_campaign_suggestion</code></td>
|
|
121
|
+
</tr>
|
|
122
|
+
<tr>
|
|
123
|
+
<td><b>Lead intake</b></td>
|
|
124
|
+
<td><code>get_campaign_intake</code> · <code>set_campaign_intake</code> · <code>rotate_campaign_intake</code> · <code>disable_campaign_intake</code></td>
|
|
125
|
+
</tr>
|
|
126
|
+
<tr>
|
|
127
|
+
<td><b>Do-Not-Call</b></td>
|
|
128
|
+
<td><code>list_dnc</code> · <code>check_dnc</code> · <code>add_dnc</code> · <code>add_dnc_batch</code> · <code>remove_dnc</code></td>
|
|
129
|
+
</tr>
|
|
130
|
+
<tr>
|
|
131
|
+
<td><b>Webhooks</b></td>
|
|
132
|
+
<td><code>list_webhooks</code> · <code>create_webhook</code> · <code>update_webhook</code> · <code>delete_webhook</code></td>
|
|
133
|
+
</tr>
|
|
134
|
+
<tr>
|
|
135
|
+
<td><b>Billing & cost</b></td>
|
|
136
|
+
<td><code>estimate_call_cost</code> · <code>set_auto_recharge</code> · <code>set_spend_alerts</code></td>
|
|
137
|
+
</tr>
|
|
106
138
|
</table>
|
|
107
139
|
|
|
108
140
|
### ⚠️ Gated tools
|
package/dist/index.js
CHANGED
|
@@ -6,9 +6,16 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
9
12
|
var __commonJS = (cb, mod) => function __require() {
|
|
10
13
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
11
14
|
};
|
|
15
|
+
var __export = (target, all) => {
|
|
16
|
+
for (var name in all)
|
|
17
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
18
|
+
};
|
|
12
19
|
var __copyProps = (to, from, except, desc) => {
|
|
13
20
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
21
|
for (let key of __getOwnPropNames(from))
|
|
@@ -25,6 +32,260 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
32
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
33
|
mod
|
|
27
34
|
));
|
|
35
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
36
|
+
|
|
37
|
+
// ../shared-types/dist/agentTools.js
|
|
38
|
+
var agentTools_exports = {};
|
|
39
|
+
__export(agentTools_exports, {
|
|
40
|
+
API_SECRETS_PROVIDER: () => API_SECRETS_PROVIDER,
|
|
41
|
+
API_TOOL_AUTH_HEADER_PATTERN: () => API_TOOL_AUTH_HEADER_PATTERN,
|
|
42
|
+
API_TOOL_NAME_PATTERN: () => API_TOOL_NAME_PATTERN,
|
|
43
|
+
API_TOOL_RESERVED_FIELD_NAMES: () => API_TOOL_RESERVED_FIELD_NAMES,
|
|
44
|
+
API_TOOL_SECRET_REF_PATTERN: () => API_TOOL_SECRET_REF_PATTERN,
|
|
45
|
+
BUILTIN_TOOL_CATALOG: () => BUILTIN_TOOL_CATALOG,
|
|
46
|
+
SECRET_NAME_PATTERN: () => SECRET_NAME_PATTERN,
|
|
47
|
+
toToolCapabilitySafeView: () => toToolCapabilitySafeView
|
|
48
|
+
});
|
|
49
|
+
function toToolCapabilitySafeView(state) {
|
|
50
|
+
return {
|
|
51
|
+
toolId: state.toolId,
|
|
52
|
+
available: state.authorized && state.runtimeRegistered,
|
|
53
|
+
unavailableReason: state.unavailableReason,
|
|
54
|
+
sideEffect: state.sideEffect
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
var API_TOOL_NAME_PATTERN, SECRET_NAME_PATTERN, API_SECRETS_PROVIDER, API_TOOL_RESERVED_FIELD_NAMES, API_TOOL_AUTH_HEADER_PATTERN, API_TOOL_SECRET_REF_PATTERN, BUILTIN_TOOL_CATALOG;
|
|
58
|
+
var init_agentTools = __esm({
|
|
59
|
+
"../shared-types/dist/agentTools.js"() {
|
|
60
|
+
"use strict";
|
|
61
|
+
API_TOOL_NAME_PATTERN = /^[a-z][a-z0-9_]{2,40}$/;
|
|
62
|
+
SECRET_NAME_PATTERN = /^[A-Z][A-Z0-9_]{1,63}$/;
|
|
63
|
+
API_SECRETS_PROVIDER = "api_secrets";
|
|
64
|
+
API_TOOL_RESERVED_FIELD_NAMES = /* @__PURE__ */ new Set([
|
|
65
|
+
"False",
|
|
66
|
+
"None",
|
|
67
|
+
"True",
|
|
68
|
+
"and",
|
|
69
|
+
"as",
|
|
70
|
+
"assert",
|
|
71
|
+
"async",
|
|
72
|
+
"await",
|
|
73
|
+
"break",
|
|
74
|
+
"class",
|
|
75
|
+
"continue",
|
|
76
|
+
"def",
|
|
77
|
+
"del",
|
|
78
|
+
"elif",
|
|
79
|
+
"else",
|
|
80
|
+
"except",
|
|
81
|
+
"finally",
|
|
82
|
+
"for",
|
|
83
|
+
"from",
|
|
84
|
+
"global",
|
|
85
|
+
"if",
|
|
86
|
+
"import",
|
|
87
|
+
"in",
|
|
88
|
+
"is",
|
|
89
|
+
"lambda",
|
|
90
|
+
"nonlocal",
|
|
91
|
+
"not",
|
|
92
|
+
"or",
|
|
93
|
+
"pass",
|
|
94
|
+
"raise",
|
|
95
|
+
"return",
|
|
96
|
+
"try",
|
|
97
|
+
"while",
|
|
98
|
+
"with",
|
|
99
|
+
"yield",
|
|
100
|
+
"params"
|
|
101
|
+
]);
|
|
102
|
+
API_TOOL_AUTH_HEADER_PATTERN = /^(authorization|x-api-key|api[-_]?key|.*token.*|.*secret.*)$/i;
|
|
103
|
+
API_TOOL_SECRET_REF_PATTERN = /\{\{\s*secrets\.[A-Z][A-Z0-9_]{1,63}\s*\}\}/;
|
|
104
|
+
BUILTIN_TOOL_CATALOG = [
|
|
105
|
+
{
|
|
106
|
+
tool_id: "handoff_to_human",
|
|
107
|
+
label: "Human handoff",
|
|
108
|
+
description: "Transfer the live call to the configured human destination when escalation is required.",
|
|
109
|
+
category: "call_control",
|
|
110
|
+
side_effect: "write",
|
|
111
|
+
default_timeout_ms: 1e3,
|
|
112
|
+
requires_credential: false
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
tool_id: "check_calendar_availability",
|
|
116
|
+
label: "Check calendar availability",
|
|
117
|
+
description: "Look up open slots in the configured calendar provider.",
|
|
118
|
+
category: "calendar",
|
|
119
|
+
side_effect: "read",
|
|
120
|
+
default_timeout_ms: 4e3,
|
|
121
|
+
requires_credential: true
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
tool_id: "list_calendar_events",
|
|
125
|
+
label: "List calendar events",
|
|
126
|
+
description: "Read scheduled events from the configured calendar provider.",
|
|
127
|
+
category: "calendar",
|
|
128
|
+
side_effect: "read",
|
|
129
|
+
default_timeout_ms: 4e3,
|
|
130
|
+
requires_credential: true
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
tool_id: "create_calendar_event",
|
|
134
|
+
label: "Create calendar event",
|
|
135
|
+
description: "Create a calendar event after the caller explicitly confirms the details.",
|
|
136
|
+
category: "calendar",
|
|
137
|
+
side_effect: "write",
|
|
138
|
+
default_timeout_ms: 6e3,
|
|
139
|
+
requires_credential: true
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
tool_id: "update_calendar_event",
|
|
143
|
+
label: "Update calendar event",
|
|
144
|
+
description: "Move or edit an existing calendar event after explicit caller confirmation.",
|
|
145
|
+
category: "calendar",
|
|
146
|
+
side_effect: "write",
|
|
147
|
+
default_timeout_ms: 6e3,
|
|
148
|
+
requires_credential: true
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
tool_id: "delete_calendar_event",
|
|
152
|
+
label: "Delete calendar event",
|
|
153
|
+
description: "Cancel an existing calendar event after explicit caller confirmation.",
|
|
154
|
+
category: "calendar",
|
|
155
|
+
side_effect: "write",
|
|
156
|
+
default_timeout_ms: 6e3,
|
|
157
|
+
requires_credential: true
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
tool_id: "lookup_customer",
|
|
161
|
+
label: "Look up customer",
|
|
162
|
+
description: "Find a customer record by phone, email, or external id.",
|
|
163
|
+
category: "crm",
|
|
164
|
+
side_effect: "read",
|
|
165
|
+
default_timeout_ms: 4e3,
|
|
166
|
+
requires_credential: true
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
tool_id: "send_whatsapp_message",
|
|
170
|
+
label: "Send WhatsApp message",
|
|
171
|
+
description: "Send a WhatsApp message to the caller mid-call (e.g. confirmation link, address, brochure URL). Outside the 24h customer-care window an approved template must be configured.",
|
|
172
|
+
category: "messaging",
|
|
173
|
+
side_effect: "write",
|
|
174
|
+
default_timeout_ms: 6e3,
|
|
175
|
+
requires_credential: true
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
tool_id: "send_telegram_message",
|
|
179
|
+
label: "Send Telegram message",
|
|
180
|
+
description: "Send a Telegram bot message to the caller mid-call. Requires the caller to have an established chat_id with the tenant's bot (no cold-send by phone).",
|
|
181
|
+
category: "messaging",
|
|
182
|
+
side_effect: "write",
|
|
183
|
+
default_timeout_ms: 6e3,
|
|
184
|
+
requires_credential: true
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
tool_id: "send_asset",
|
|
188
|
+
label: "Send asset",
|
|
189
|
+
description: "Send a configured shareable asset to the caller when they explicitly request a document, brochure, or guide.",
|
|
190
|
+
category: "messaging",
|
|
191
|
+
side_effect: "write",
|
|
192
|
+
default_timeout_ms: 6e3,
|
|
193
|
+
requires_credential: true
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
tool_id: "lookup_ticket",
|
|
197
|
+
label: "Look up ticket",
|
|
198
|
+
description: "Find a support ticket by its number, or the caller's most recent ticket, and read back its status.",
|
|
199
|
+
category: "ticketing",
|
|
200
|
+
side_effect: "read",
|
|
201
|
+
default_timeout_ms: 4e3,
|
|
202
|
+
requires_credential: true
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
tool_id: "create_ticket",
|
|
206
|
+
label: "Create ticket",
|
|
207
|
+
description: "Raise a support ticket from the call after the caller confirms the details, and read the ticket number back to them.",
|
|
208
|
+
category: "ticketing",
|
|
209
|
+
side_effect: "write",
|
|
210
|
+
default_timeout_ms: 6e3,
|
|
211
|
+
requires_credential: true
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
tool_id: "call_webhook",
|
|
215
|
+
label: "API request",
|
|
216
|
+
description: "Call your own HTTPS API mid-call, to look something up or to send details. Each API tool has its own name, purpose, typed parameters and headers; header secrets stay encrypted.",
|
|
217
|
+
category: "webhook",
|
|
218
|
+
side_effect: "read",
|
|
219
|
+
default_timeout_ms: 6e3,
|
|
220
|
+
// The endpoint lives in the binding's provider_settings and its secrets in
|
|
221
|
+
// the tenant's api_secrets row — nothing to connect in Settings → Connectors.
|
|
222
|
+
requires_credential: false
|
|
223
|
+
}
|
|
224
|
+
];
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// ../shared-types/dist/safeUrl.js
|
|
229
|
+
var safeUrl_exports = {};
|
|
230
|
+
__export(safeUrl_exports, {
|
|
231
|
+
isSafeUrl: () => isSafeUrl
|
|
232
|
+
});
|
|
233
|
+
function unmapIpv4(v6) {
|
|
234
|
+
const dotted = /^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/.exec(v6);
|
|
235
|
+
if (dotted)
|
|
236
|
+
return dotted[1];
|
|
237
|
+
const hex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(v6);
|
|
238
|
+
if (!hex)
|
|
239
|
+
return null;
|
|
240
|
+
const high = parseInt(hex[1], 16);
|
|
241
|
+
const low = parseInt(hex[2], 16);
|
|
242
|
+
return [high >> 8, high & 255, low >> 8, low & 255].join(".");
|
|
243
|
+
}
|
|
244
|
+
function isBlockedHost(host) {
|
|
245
|
+
const bare = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
246
|
+
if (bare === "localhost" || bare === "0.0.0.0" || bare === "::")
|
|
247
|
+
return true;
|
|
248
|
+
if (bare.endsWith(".local") || bare.endsWith(".internal") || bare.endsWith(".localhost"))
|
|
249
|
+
return true;
|
|
250
|
+
if (/^127\./.test(bare))
|
|
251
|
+
return true;
|
|
252
|
+
if (/^10\./.test(bare))
|
|
253
|
+
return true;
|
|
254
|
+
if (/^192\.168\./.test(bare))
|
|
255
|
+
return true;
|
|
256
|
+
if (/^172\.(1[6-9]|2\d|3[01])\./.test(bare))
|
|
257
|
+
return true;
|
|
258
|
+
if (/^169\.254\./.test(bare))
|
|
259
|
+
return true;
|
|
260
|
+
const v6 = bare.toLowerCase();
|
|
261
|
+
if (v6 === "::1")
|
|
262
|
+
return true;
|
|
263
|
+
if (/^f[cd][0-9a-f]{2}:/.test(v6))
|
|
264
|
+
return true;
|
|
265
|
+
if (/^fe[89ab][0-9a-f]:/.test(v6))
|
|
266
|
+
return true;
|
|
267
|
+
const mapped = unmapIpv4(v6);
|
|
268
|
+
if (mapped)
|
|
269
|
+
return isBlockedHost(mapped);
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
function isSafeUrl(raw, options = {}) {
|
|
273
|
+
const protocols = options.protocols ?? ["http:", "https:"];
|
|
274
|
+
let url;
|
|
275
|
+
try {
|
|
276
|
+
url = new URL(raw);
|
|
277
|
+
} catch {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
if (!protocols.includes(url.protocol))
|
|
281
|
+
return false;
|
|
282
|
+
return !isBlockedHost(url.hostname.toLowerCase());
|
|
283
|
+
}
|
|
284
|
+
var init_safeUrl = __esm({
|
|
285
|
+
"../shared-types/dist/safeUrl.js"() {
|
|
286
|
+
"use strict";
|
|
287
|
+
}
|
|
288
|
+
});
|
|
28
289
|
|
|
29
290
|
// ../ops-tools/dist/index.js
|
|
30
291
|
var require_dist = __commonJS({
|
|
@@ -34,7 +295,7 @@ var require_dist = __commonJS({
|
|
|
34
295
|
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
35
296
|
var __getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
36
297
|
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
37
|
-
var
|
|
298
|
+
var __export2 = (target, all) => {
|
|
38
299
|
for (var name in all)
|
|
39
300
|
__defProp2(target, name, { get: all[name], enumerable: true });
|
|
40
301
|
};
|
|
@@ -46,14 +307,14 @@ var require_dist = __commonJS({
|
|
|
46
307
|
}
|
|
47
308
|
return to;
|
|
48
309
|
};
|
|
49
|
-
var
|
|
310
|
+
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
|
|
50
311
|
var index_exports = {};
|
|
51
|
-
|
|
312
|
+
__export2(index_exports, {
|
|
52
313
|
defineTool: () => defineTool,
|
|
53
314
|
opsToolCatalog: () => opsToolCatalog2,
|
|
54
315
|
resolveToolDisposition: () => resolveToolDisposition
|
|
55
316
|
});
|
|
56
|
-
module2.exports =
|
|
317
|
+
module2.exports = __toCommonJS2(index_exports);
|
|
57
318
|
function defineTool(def) {
|
|
58
319
|
return def;
|
|
59
320
|
}
|
|
@@ -64,6 +325,20 @@ var require_dist = __commonJS({
|
|
|
64
325
|
return p.risk === "write" ? "propose" : "confirm";
|
|
65
326
|
}
|
|
66
327
|
var import_zod = require("zod");
|
|
328
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
329
|
+
var norm = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
330
|
+
async function resolveAgentId(client, agentId) {
|
|
331
|
+
const raw = String(agentId ?? "").trim();
|
|
332
|
+
if (UUID_RE.test(raw)) return raw;
|
|
333
|
+
const { agents } = await client.agents.list({ limit: 500 });
|
|
334
|
+
const target = norm(raw);
|
|
335
|
+
const matches = agents.filter((a) => norm(a.name ?? "") === target);
|
|
336
|
+
if (matches.length === 1) return matches[0].id;
|
|
337
|
+
if (matches.length > 1) {
|
|
338
|
+
throw new Error(`"${raw}" matches ${matches.length} agents \u2014 call list_agents and pass the exact agent UUID.`);
|
|
339
|
+
}
|
|
340
|
+
throw new Error(`No agent named "${raw}" found \u2014 call list_agents to get a valid agent UUID.`);
|
|
341
|
+
}
|
|
67
342
|
var agentConfigFields = {
|
|
68
343
|
system_prompt: import_zod.z.string().optional().describe("Full system prompt for the agent. If given without persona/playbook, the server auto-structures it."),
|
|
69
344
|
voice: import_zod.z.string().optional().describe('Voice ID (e.g. "Aoede", "Charon"). Call list_llm_options for valid values. Leave empty for realtime LLMs and Deepgram TTS, which carry their own voice.'),
|
|
@@ -86,7 +361,7 @@ var require_dist = __commonJS({
|
|
|
86
361
|
custom_voice_mode: import_zod.z.enum(["rymi", "openai-compat"]).optional().describe("Wire format for custom_voice_url."),
|
|
87
362
|
custom_transcriber_url: import_zod.z.string().nullable().optional().describe("Self-hosted STT endpoint (https:// or wss://). Enterprise only; null clears."),
|
|
88
363
|
prompt_mode: import_zod.z.enum(["builder", "raw"]).optional().describe('How the system prompt is interpreted: "builder" (server structures persona/playbook from system_prompt) or "raw" (use system_prompt verbatim \u2014 requires system_prompt). Defaults to "builder".'),
|
|
89
|
-
persona: import_zod.z.record(import_zod.z.any()).optional().describe("Persona object. Note: callerPersonas must be objects of shape {type, approach, detectedWhen}, NOT plain strings."),
|
|
364
|
+
persona: import_zod.z.record(import_zod.z.any()).optional().describe("Persona object. persona.name is the name the agent speaks and introduces itself as (also shown on share/tester pages); it defaults to the label when omitted. Note: callerPersonas must be objects of shape {type, approach, detectedWhen}, NOT plain strings."),
|
|
90
365
|
playbook: import_zod.z.record(import_zod.z.any()).optional().describe("Playbook configuration object"),
|
|
91
366
|
advanced: import_zod.z.record(import_zod.z.any()).optional(),
|
|
92
367
|
features: import_zod.z.record(import_zod.z.any()).optional(),
|
|
@@ -97,6 +372,25 @@ var require_dist = __commonJS({
|
|
|
97
372
|
if (!prompt_mode) return rest;
|
|
98
373
|
return { ...rest, advanced: { ...rest.advanced || {}, prompt_mode } };
|
|
99
374
|
}
|
|
375
|
+
var LLM_PROVIDER_ALIASES = {
|
|
376
|
+
google: "gemini",
|
|
377
|
+
googleai: "gemini",
|
|
378
|
+
"google-genai": "gemini",
|
|
379
|
+
"google-ai": "gemini",
|
|
380
|
+
vertex: "gemini",
|
|
381
|
+
vertexai: "gemini",
|
|
382
|
+
"vertex-ai": "gemini",
|
|
383
|
+
claude: "anthropic",
|
|
384
|
+
gpt: "openai",
|
|
385
|
+
"azure-openai": "openai",
|
|
386
|
+
azure: "openai"
|
|
387
|
+
};
|
|
388
|
+
function normalizeLlmProvider(params) {
|
|
389
|
+
const p = params.llm_provider;
|
|
390
|
+
if (!p) return params;
|
|
391
|
+
const alias = LLM_PROVIDER_ALIASES[p.toLowerCase()];
|
|
392
|
+
return alias ? { ...params, llm_provider: alias } : params;
|
|
393
|
+
}
|
|
100
394
|
var agentTools = [
|
|
101
395
|
defineTool({
|
|
102
396
|
name: "list_agents",
|
|
@@ -248,10 +542,10 @@ var require_dist = __commonJS({
|
|
|
248
542
|
scope: "agent",
|
|
249
543
|
risk: "write",
|
|
250
544
|
input: {
|
|
251
|
-
name: import_zod.z.string().min(1).describe("
|
|
545
|
+
name: import_zod.z.string().min(1).describe("Studio label: the name shown in the sidebar/agent list only. The name the agent speaks is persona.name."),
|
|
252
546
|
...agentConfigFields
|
|
253
547
|
},
|
|
254
|
-
run: (client, params) => client.agents.create(foldPromptMode(params))
|
|
548
|
+
run: (client, params) => client.agents.create(normalizeLlmProvider(foldPromptMode(params)))
|
|
255
549
|
}),
|
|
256
550
|
defineTool({
|
|
257
551
|
name: "update_agent",
|
|
@@ -260,11 +554,11 @@ var require_dist = __commonJS({
|
|
|
260
554
|
risk: "write",
|
|
261
555
|
input: {
|
|
262
556
|
agent_id: import_zod.z.string().uuid().describe("The agent UUID to update"),
|
|
263
|
-
name: import_zod.z.string().optional(),
|
|
557
|
+
name: import_zod.z.string().optional().describe("Studio label (sidebar/agent list only). To change the spoken name, set persona.name."),
|
|
264
558
|
...agentConfigFields,
|
|
265
559
|
chat_summary: import_zod.z.string().nullable().optional()
|
|
266
560
|
},
|
|
267
|
-
run: (client, { agent_id, ...params }) => client.agents.update(agent_id, foldPromptMode(params))
|
|
561
|
+
run: async (client, { agent_id, ...params }) => client.agents.update(await resolveAgentId(client, agent_id), normalizeLlmProvider(foldPromptMode(params)))
|
|
268
562
|
}),
|
|
269
563
|
defineTool({
|
|
270
564
|
name: "delete_agent",
|
|
@@ -272,7 +566,7 @@ var require_dist = __commonJS({
|
|
|
272
566
|
scope: "agent",
|
|
273
567
|
risk: "sensitive",
|
|
274
568
|
input: { agent_id: import_zod.z.string().uuid().describe("The agent UUID to delete") },
|
|
275
|
-
run: (client, { agent_id }) => client.agents.delete(agent_id)
|
|
569
|
+
run: async (client, { agent_id }) => client.agents.delete(await resolveAgentId(client, agent_id))
|
|
276
570
|
}),
|
|
277
571
|
defineTool({
|
|
278
572
|
name: "clone_agent",
|
|
@@ -280,7 +574,7 @@ var require_dist = __commonJS({
|
|
|
280
574
|
scope: "agent",
|
|
281
575
|
risk: "write",
|
|
282
576
|
input: { agent_id: import_zod.z.string().uuid().describe("The agent UUID to clone") },
|
|
283
|
-
run: (client, { agent_id }) => client.agents.clone(agent_id)
|
|
577
|
+
run: async (client, { agent_id }) => client.agents.clone(await resolveAgentId(client, agent_id))
|
|
284
578
|
})
|
|
285
579
|
];
|
|
286
580
|
var import_zod2 = require("zod");
|
|
@@ -642,7 +936,7 @@ var require_dist = __commonJS({
|
|
|
642
936
|
// handler, a published:false-with-blockers response is NOT flagged as a
|
|
643
937
|
// protocol error — blockers are valid data every consumer (MCP client,
|
|
644
938
|
// studio harness) reads from the result directly.
|
|
645
|
-
run: (client, { agent_id }) => client.agents.publish(agent_id)
|
|
939
|
+
run: async (client, { agent_id }) => client.agents.publish(await resolveAgentId(client, agent_id))
|
|
646
940
|
})
|
|
647
941
|
];
|
|
648
942
|
var import_zod7 = require("zod");
|
|
@@ -933,10 +1227,318 @@ var require_dist = __commonJS({
|
|
|
933
1227
|
suggestion_id: import_zod10.z.string().describe("The suggestion ID to accept")
|
|
934
1228
|
},
|
|
935
1229
|
run: (client, { campaign_id, suggestion_id }) => client.campaigns.acceptSuggestion(campaign_id, suggestion_id)
|
|
1230
|
+
}),
|
|
1231
|
+
defineTool({
|
|
1232
|
+
name: "get_campaign_intake",
|
|
1233
|
+
description: "Get a campaign's lead-intake URL settings (consent and default-country handling, last used). Returns intake: null if none. The URL itself is only shown when created or rotated.",
|
|
1234
|
+
scope: "agent",
|
|
1235
|
+
risk: "read",
|
|
1236
|
+
input: { campaign_id: import_zod10.z.string().describe("The campaign ID") },
|
|
1237
|
+
run: (client, { campaign_id }) => client.campaigns.intake.get(campaign_id)
|
|
1238
|
+
}),
|
|
1239
|
+
defineTool({
|
|
1240
|
+
name: "set_campaign_intake",
|
|
1241
|
+
description: 'Create a lead-intake URL for a campaign, or update its settings. Lead sources (website forms, Typeform, Google Apps Script, Zapier/Make) POST leads to the URL with no API key; a running campaign dials them within its calling window. The URL is returned ONCE on create (url: null on later updates) and anyone holding it can add numbers to the campaign. assume_voice_consent=true treats every posted lead as consenting to calls; default_country (e.g. "IN") makes local numbers without +<code> dialable.',
|
|
1242
|
+
scope: "agent",
|
|
1243
|
+
risk: "sensitive",
|
|
1244
|
+
input: {
|
|
1245
|
+
campaign_id: import_zod10.z.string().describe("The campaign ID"),
|
|
1246
|
+
assume_voice_consent: import_zod10.z.boolean().optional().describe("Treat every posted lead as having voice consent"),
|
|
1247
|
+
default_country: import_zod10.z.string().regex(/^[A-Z]{2}$/).nullable().optional().describe('ISO-3166 alpha-2 country for numbers posted without +<code>, e.g. "IN"')
|
|
1248
|
+
},
|
|
1249
|
+
run: (client, { campaign_id, ...settings }) => client.campaigns.intake.set(campaign_id, settings)
|
|
1250
|
+
}),
|
|
1251
|
+
defineTool({
|
|
1252
|
+
name: "rotate_campaign_intake",
|
|
1253
|
+
description: "Issue a new lead-intake URL for a campaign. The old URL stops accepting leads immediately, so every lead source must be updated.",
|
|
1254
|
+
scope: "agent",
|
|
1255
|
+
risk: "sensitive",
|
|
1256
|
+
input: { campaign_id: import_zod10.z.string().describe("The campaign ID") },
|
|
1257
|
+
run: (client, { campaign_id }) => client.campaigns.intake.rotate(campaign_id)
|
|
1258
|
+
}),
|
|
1259
|
+
defineTool({
|
|
1260
|
+
name: "disable_campaign_intake",
|
|
1261
|
+
description: "Remove a campaign's lead-intake URL. Leads already accepted stay in the campaign.",
|
|
1262
|
+
scope: "agent",
|
|
1263
|
+
risk: "write",
|
|
1264
|
+
input: { campaign_id: import_zod10.z.string().describe("The campaign ID") },
|
|
1265
|
+
run: async (client, { campaign_id }) => {
|
|
1266
|
+
await client.campaigns.intake.disable(campaign_id);
|
|
1267
|
+
return { status: "disabled", campaign_id };
|
|
1268
|
+
}
|
|
1269
|
+
})
|
|
1270
|
+
];
|
|
1271
|
+
var import_zod11 = require("zod");
|
|
1272
|
+
var import_agentTools = (init_agentTools(), __toCommonJS(agentTools_exports));
|
|
1273
|
+
var import_safeUrl = (init_safeUrl(), __toCommonJS(safeUrl_exports));
|
|
1274
|
+
var DEFAULT_NAME = "call_webhook";
|
|
1275
|
+
var METHODS = ["GET", "POST", "PUT", "PATCH"];
|
|
1276
|
+
var FIELD_NAME = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
1277
|
+
var RESERVED_HEADERS = /* @__PURE__ */ new Set(["host", "content-length", "connection", "transfer-encoding"]);
|
|
1278
|
+
var LIVE_NOTE = "Saved to the live agent row: the voice runtime uses it from the next call. There is no separate draft; publish_agent is not required. Undo with list_agent_changes \u2192 undo_agent_change.";
|
|
1279
|
+
var fieldSchema = import_zod11.z.object({
|
|
1280
|
+
name: import_zod11.z.string().describe('Argument name the agent fills in: letters, digits, underscores; not a Python keyword or "params".'),
|
|
1281
|
+
type: import_zod11.z.enum(["string", "number", "integer", "boolean"]).optional().describe('Default "string".'),
|
|
1282
|
+
description: import_zod11.z.string().optional().describe("What the value is, for the agent."),
|
|
1283
|
+
required: import_zod11.z.boolean().optional(),
|
|
1284
|
+
enum: import_zod11.z.array(import_zod11.z.string()).optional().describe("Allowed values, if fixed.")
|
|
1285
|
+
});
|
|
1286
|
+
var settingsShape = {
|
|
1287
|
+
url: import_zod11.z.string().describe("Public https endpoint. Private, loopback and non-https hosts are refused."),
|
|
1288
|
+
method: import_zod11.z.enum(METHODS).optional().describe("Default POST. GET sends fields as query parameters."),
|
|
1289
|
+
purpose: import_zod11.z.string().optional().describe("When the agent should call this tool. Without it the agent rarely fires it."),
|
|
1290
|
+
fields: import_zod11.z.array(fieldSchema).optional().describe("Arguments the agent supplies. Replaces the whole list on update."),
|
|
1291
|
+
headers: import_zod11.z.record(import_zod11.z.string()).optional().describe("Request headers. Credentials must be a {{secrets.NAME}} reference (see set_tool_secret), never a literal key."),
|
|
1292
|
+
send_metadata: import_zod11.z.boolean().optional().describe("Include call metadata (call id, agent id, caller phone). Default true."),
|
|
1293
|
+
response_fields: import_zod11.z.array(import_zod11.z.string()).optional().describe("Dot paths kept from the JSON response; default keeps the (truncated) body."),
|
|
1294
|
+
timeout_ms: import_zod11.z.number().int().min(1e3).max(1e4).optional().describe("Per-request timeout, 1000\u201310000 ms. Default 6000."),
|
|
1295
|
+
enabled: import_zod11.z.boolean().optional().describe("Default true.")
|
|
1296
|
+
};
|
|
1297
|
+
function bindingName(b) {
|
|
1298
|
+
const n = b?.provider_settings?.name;
|
|
1299
|
+
return typeof n === "string" && n.trim() ? n.trim() : DEFAULT_NAME;
|
|
1300
|
+
}
|
|
1301
|
+
var isApiTool = (b) => b?.tool_id === "call_webhook";
|
|
1302
|
+
function webhookBindingErrors(b, opts) {
|
|
1303
|
+
const errors = [];
|
|
1304
|
+
const s = b.provider_settings ?? {};
|
|
1305
|
+
const name = bindingName(b);
|
|
1306
|
+
if (!import_agentTools.API_TOOL_NAME_PATTERN.test(name)) errors.push(`name "${name}": lowercase letters, digits and underscores, starting with a letter, 3\u201341 characters.`);
|
|
1307
|
+
if (opts.otherNames.includes(name)) errors.push(`name "${name}" is already used by another API tool on this agent.`);
|
|
1308
|
+
const url = typeof s.url === "string" ? s.url.trim() : "";
|
|
1309
|
+
if (!url) errors.push("url is required.");
|
|
1310
|
+
else if (!/^https:\/\//i.test(url)) errors.push("url must be https \u2014 the request carries caller details.");
|
|
1311
|
+
else if (!(0, import_safeUrl.isSafeUrl)(url, { protocols: ["https:"] })) errors.push("url must be a valid public host; private and loopback addresses are refused at call time.");
|
|
1312
|
+
if (!METHODS.includes(s.method)) errors.push(`method must be one of ${METHODS.join(", ")}.`);
|
|
1313
|
+
if (!Number.isInteger(b.timeout_ms) || b.timeout_ms < 1e3 || b.timeout_ms > 1e4) errors.push("timeout_ms must be an integer from 1000 to 10000.");
|
|
1314
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1315
|
+
for (const f of Array.isArray(s.fields) ? s.fields : []) {
|
|
1316
|
+
const fname = typeof f?.name === "string" ? f.name.trim() : "";
|
|
1317
|
+
if (!FIELD_NAME.test(fname)) errors.push(`field "${fname}": letters, digits and underscores only, not starting with a digit.`);
|
|
1318
|
+
else if (import_agentTools.API_TOOL_RESERVED_FIELD_NAMES.has(fname)) errors.push(`field "${fname}" is reserved; use e.g. ${fname}_value.`);
|
|
1319
|
+
else if (seen.has(fname)) errors.push(`field "${fname}" is duplicated.`);
|
|
1320
|
+
seen.add(fname);
|
|
1321
|
+
}
|
|
1322
|
+
const headers = s.headers ?? {};
|
|
1323
|
+
for (const key of opts.checkHeaders) {
|
|
1324
|
+
const value = headers[key];
|
|
1325
|
+
if (RESERVED_HEADERS.has(key.trim().toLowerCase())) errors.push(`header "${key}" is set by the runtime and cannot be overridden.`);
|
|
1326
|
+
else if (typeof value !== "string") errors.push(`header "${key}" must be a string.`);
|
|
1327
|
+
else if (import_agentTools.API_TOOL_AUTH_HEADER_PATTERN.test(key.trim()) && !import_agentTools.API_TOOL_SECRET_REF_PATTERN.test(value)) {
|
|
1328
|
+
errors.push(`header "${key}" holds a literal credential. Store it with set_tool_secret and use "{{secrets.NAME}}" instead.`);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
return errors;
|
|
1332
|
+
}
|
|
1333
|
+
function assertValid(b, tools, self, checkHeaders) {
|
|
1334
|
+
const otherNames = tools.filter((t) => isApiTool(t) && t !== self).map(bindingName);
|
|
1335
|
+
const errors = webhookBindingErrors(b, { otherNames, checkHeaders });
|
|
1336
|
+
if (errors.length) throw new Error(`Invalid API tool binding: ${errors.join(" ")}`);
|
|
1337
|
+
}
|
|
1338
|
+
async function writeTools(client, agentRef, mutate) {
|
|
1339
|
+
const agentId = await resolveAgentId(client, agentRef);
|
|
1340
|
+
const agent = await client.agents.retrieve(agentId);
|
|
1341
|
+
if (!Array.isArray(agent.tools)) throw new Error("The API did not return this agent's tool bindings, so a write could delete them. Refusing.");
|
|
1342
|
+
const tools = mutate(agent.tools);
|
|
1343
|
+
await client.agents.update(agentId, { tools });
|
|
1344
|
+
return { agentId, tools };
|
|
1345
|
+
}
|
|
1346
|
+
function findApiTool(tools, name) {
|
|
1347
|
+
const found = tools.find((t) => isApiTool(t) && bindingName(t) === name);
|
|
1348
|
+
if (!found) {
|
|
1349
|
+
const names2 = tools.filter(isApiTool).map(bindingName);
|
|
1350
|
+
throw new Error(`No API tool named "${name}" on this agent. Existing: ${names2.length ? names2.join(", ") : "none"}.`);
|
|
1351
|
+
}
|
|
1352
|
+
return found;
|
|
1353
|
+
}
|
|
1354
|
+
var addShape = { agent_id: import_zod11.z.string().describe("The agent UUID"), name: import_zod11.z.string().describe('LLM-facing tool name, e.g. "lookup_reservation". Unique per agent.'), ...settingsShape };
|
|
1355
|
+
var updateShape = {
|
|
1356
|
+
agent_id: import_zod11.z.string().describe("The agent UUID"),
|
|
1357
|
+
name: import_zod11.z.string().describe("Current name of the API tool to change."),
|
|
1358
|
+
new_name: import_zod11.z.string().optional().describe("Rename the tool."),
|
|
1359
|
+
...settingsShape,
|
|
1360
|
+
url: settingsShape.url.optional(),
|
|
1361
|
+
headers: import_zod11.z.record(import_zod11.z.string().nullable()).optional().describe("Merged into the existing headers by name; null removes one. Headers you omit \u2014 including ones shown as [redacted] \u2014 are kept unchanged.")
|
|
1362
|
+
};
|
|
1363
|
+
var agentToolBindingTools = [
|
|
1364
|
+
defineTool({
|
|
1365
|
+
name: "list_agent_tools",
|
|
1366
|
+
description: "List an agent's tool bindings (API tools / call_webhook, handoff, calendar, \u2026). Header values are shown only as {{secrets.NAME}} references; literal values are [redacted].",
|
|
1367
|
+
scope: "agent",
|
|
1368
|
+
risk: "read",
|
|
1369
|
+
input: { agent_id: import_zod11.z.string().describe("The agent UUID") },
|
|
1370
|
+
run: async (client, { agent_id }) => {
|
|
1371
|
+
const agentId = await resolveAgentId(client, agent_id);
|
|
1372
|
+
const agent = await client.agents.retrieve(agentId);
|
|
1373
|
+
return { agent_id: agentId, tools: agent.tools ?? [] };
|
|
1374
|
+
}
|
|
1375
|
+
}),
|
|
1376
|
+
defineTool({
|
|
1377
|
+
name: "add_agent_tool",
|
|
1378
|
+
description: `Add an API tool (call_webhook) to an agent, keeping its existing tools. The agent can then call the endpoint mid-call with the fields you define. ${LIVE_NOTE}`,
|
|
1379
|
+
scope: "agent",
|
|
1380
|
+
risk: "write",
|
|
1381
|
+
input: addShape,
|
|
1382
|
+
run: async (client, params) => {
|
|
1383
|
+
const p = import_zod11.z.object(addShape).parse(params);
|
|
1384
|
+
const binding = {
|
|
1385
|
+
tool_id: "call_webhook",
|
|
1386
|
+
enabled: p.enabled ?? true,
|
|
1387
|
+
credential_ref: null,
|
|
1388
|
+
timeout_ms: p.timeout_ms ?? 6e3,
|
|
1389
|
+
side_effect: (p.method ?? "POST") === "GET" ? "read" : "write",
|
|
1390
|
+
provider_settings: {
|
|
1391
|
+
name: p.name.trim(),
|
|
1392
|
+
url: p.url.trim(),
|
|
1393
|
+
method: p.method ?? "POST",
|
|
1394
|
+
send_metadata: p.send_metadata ?? true,
|
|
1395
|
+
...p.purpose ? { purpose: p.purpose } : {},
|
|
1396
|
+
...p.fields?.length ? { fields: p.fields } : {},
|
|
1397
|
+
...p.headers && Object.keys(p.headers).length ? { headers: p.headers } : {},
|
|
1398
|
+
...p.response_fields?.length ? { response_fields: p.response_fields } : {}
|
|
1399
|
+
}
|
|
1400
|
+
};
|
|
1401
|
+
const { agentId } = await writeTools(client, p.agent_id, (tools) => {
|
|
1402
|
+
assertValid(binding, tools, null, Object.keys(p.headers ?? {}));
|
|
1403
|
+
return [...tools, binding];
|
|
1404
|
+
});
|
|
1405
|
+
return { status: "added", agent_id: agentId, tool: binding, note: LIVE_NOTE };
|
|
1406
|
+
}
|
|
1407
|
+
}),
|
|
1408
|
+
defineTool({
|
|
1409
|
+
name: "update_agent_tool",
|
|
1410
|
+
description: `Change one API tool (call_webhook) on an agent by name. Only the settings you pass change; fields replaces the whole list, headers merge by name. ${LIVE_NOTE}`,
|
|
1411
|
+
scope: "agent",
|
|
1412
|
+
risk: "write",
|
|
1413
|
+
input: updateShape,
|
|
1414
|
+
run: async (client, params) => {
|
|
1415
|
+
const p = import_zod11.z.object(updateShape).parse(params);
|
|
1416
|
+
let updated = null;
|
|
1417
|
+
const { agentId } = await writeTools(client, p.agent_id, (tools) => {
|
|
1418
|
+
const current = findApiTool(tools, p.name);
|
|
1419
|
+
const prev = current.provider_settings ?? {};
|
|
1420
|
+
const headers = { ...prev.headers ?? {} };
|
|
1421
|
+
for (const [k, v] of Object.entries(p.headers ?? {})) {
|
|
1422
|
+
if (v === null) delete headers[k];
|
|
1423
|
+
else headers[k] = v;
|
|
1424
|
+
}
|
|
1425
|
+
const settings = { ...prev, name: (p.new_name ?? bindingName(current)).trim() };
|
|
1426
|
+
for (const key of ["url", "method", "purpose", "fields", "send_metadata", "response_fields"]) {
|
|
1427
|
+
if (p[key] !== void 0) settings[key] = key === "url" ? p.url.trim() : p[key];
|
|
1428
|
+
}
|
|
1429
|
+
settings.method ??= "POST";
|
|
1430
|
+
if (Object.keys(headers).length) settings.headers = headers;
|
|
1431
|
+
else delete settings.headers;
|
|
1432
|
+
const next = {
|
|
1433
|
+
...current,
|
|
1434
|
+
enabled: p.enabled ?? current.enabled,
|
|
1435
|
+
timeout_ms: p.timeout_ms ?? current.timeout_ms,
|
|
1436
|
+
side_effect: settings.method === "GET" ? "read" : "write",
|
|
1437
|
+
provider_settings: settings
|
|
1438
|
+
};
|
|
1439
|
+
const touched = Object.entries(p.headers ?? {}).filter(([, v]) => v !== null).map(([k]) => k);
|
|
1440
|
+
assertValid(next, tools, current, touched);
|
|
1441
|
+
updated = next;
|
|
1442
|
+
return tools.map((t) => t === current ? next : t);
|
|
1443
|
+
});
|
|
1444
|
+
return { status: "updated", agent_id: agentId, tool: updated, note: LIVE_NOTE };
|
|
1445
|
+
}
|
|
1446
|
+
}),
|
|
1447
|
+
defineTool({
|
|
1448
|
+
name: "remove_agent_tool",
|
|
1449
|
+
description: `Remove one API tool (call_webhook) from an agent by name, keeping its other tools. ${LIVE_NOTE}`,
|
|
1450
|
+
scope: "agent",
|
|
1451
|
+
risk: "write",
|
|
1452
|
+
input: { agent_id: import_zod11.z.string().describe("The agent UUID"), name: import_zod11.z.string().describe("Name of the API tool to remove.") },
|
|
1453
|
+
run: async (client, { agent_id, name }) => {
|
|
1454
|
+
const { agentId, tools } = await writeTools(client, agent_id, (tools2) => {
|
|
1455
|
+
const target = findApiTool(tools2, name);
|
|
1456
|
+
return tools2.filter((t) => t !== target);
|
|
1457
|
+
});
|
|
1458
|
+
return { status: "removed", agent_id: agentId, name, remaining: tools.filter(isApiTool).map(bindingName), note: LIVE_NOTE };
|
|
1459
|
+
}
|
|
1460
|
+
}),
|
|
1461
|
+
defineTool({
|
|
1462
|
+
name: "list_tool_secrets",
|
|
1463
|
+
description: "List the workspace's API-tool secret names and the host each is pinned to. Values are never returned.",
|
|
1464
|
+
scope: "account",
|
|
1465
|
+
risk: "read",
|
|
1466
|
+
input: {},
|
|
1467
|
+
run: (client) => client.toolSecrets.list()
|
|
1468
|
+
}),
|
|
1469
|
+
defineTool({
|
|
1470
|
+
name: "set_tool_secret",
|
|
1471
|
+
description: 'Create or replace a workspace secret for API-tool headers, referenced as "{{secrets.NAME}}" (e.g. header x-api-key: "{{secrets.RESERVATIONS_API_KEY}}"). The value is encrypted, write-only, and only ever sent to `host`. Replacing an existing name changes it for every agent that references it.',
|
|
1472
|
+
scope: "account",
|
|
1473
|
+
risk: "sensitive",
|
|
1474
|
+
input: {
|
|
1475
|
+
name: import_zod11.z.string().describe("UPPER_SNAKE_CASE, 2\u201364 characters."),
|
|
1476
|
+
value: import_zod11.z.string().min(1).max(4096).describe("The secret value. Never echoed back."),
|
|
1477
|
+
host: import_zod11.z.string().describe('Public hostname the secret may be sent to, e.g. "api.example.com".')
|
|
1478
|
+
},
|
|
1479
|
+
run: async (client, { name, value, host }) => {
|
|
1480
|
+
if (!import_agentTools.SECRET_NAME_PATTERN.test(name)) throw new Error("Secret names are UPPER_SNAKE_CASE, 2\u201364 characters, starting with a letter.");
|
|
1481
|
+
await client.toolSecrets.set(name, { value, host });
|
|
1482
|
+
return { status: "saved", name, reference: `{{secrets.${name}}}` };
|
|
1483
|
+
}
|
|
1484
|
+
})
|
|
1485
|
+
];
|
|
1486
|
+
var import_zod12 = require("zod");
|
|
1487
|
+
var shareLinkTools = [
|
|
1488
|
+
defineTool({
|
|
1489
|
+
name: "get_share_link",
|
|
1490
|
+
description: "Get an agent's public share link (URL, limits, minutes used). Returns link: null if none exists yet.",
|
|
1491
|
+
scope: "agent",
|
|
1492
|
+
risk: "read",
|
|
1493
|
+
input: { agent_id: import_zod12.z.string().uuid().describe("The agent UUID") },
|
|
1494
|
+
run: (client, { agent_id }) => client.agents.getShareLink(agent_id)
|
|
1495
|
+
}),
|
|
1496
|
+
defineTool({
|
|
1497
|
+
name: "set_share_link",
|
|
1498
|
+
description: "Create an agent's public share link, or update its settings. Anyone with the URL can talk to the agent in a browser, billed to this workspace. Defaults on create: 30-minute pool, 300 s per call, 2 concurrent calls, 3 calls per IP per hour. Set enabled=false to switch the link off.",
|
|
1499
|
+
scope: "agent",
|
|
1500
|
+
risk: "sensitive",
|
|
1501
|
+
input: {
|
|
1502
|
+
agent_id: import_zod12.z.string().uuid().describe("The agent UUID"),
|
|
1503
|
+
enabled: import_zod12.z.boolean().optional().describe("Turn the link on or off"),
|
|
1504
|
+
minutes_limit: import_zod12.z.number().int().min(0).max(6e3).optional().describe("Total talk-time pool in minutes"),
|
|
1505
|
+
max_call_seconds: import_zod12.z.number().int().min(60).max(1800).optional().describe("Per-call cap in seconds"),
|
|
1506
|
+
max_concurrent: import_zod12.z.number().int().min(1).max(10).optional().describe("Simultaneous calls"),
|
|
1507
|
+
calls_per_ip_hour: import_zod12.z.number().int().min(1).max(30).optional().describe("Calls per caller IP per hour")
|
|
1508
|
+
},
|
|
1509
|
+
run: (client, { agent_id, ...settings }) => client.agents.setShareLink(agent_id, settings)
|
|
1510
|
+
}),
|
|
1511
|
+
defineTool({
|
|
1512
|
+
name: "regenerate_share_link",
|
|
1513
|
+
description: "Issue a new URL for an agent's share link. The old URL stops working immediately.",
|
|
1514
|
+
scope: "agent",
|
|
1515
|
+
risk: "sensitive",
|
|
1516
|
+
input: { agent_id: import_zod12.z.string().uuid().describe("The agent UUID") },
|
|
1517
|
+
run: (client, { agent_id }) => client.agents.regenerateShareLink(agent_id)
|
|
936
1518
|
})
|
|
937
1519
|
];
|
|
1520
|
+
var import_agentTools2 = (init_agentTools(), __toCommonJS(agentTools_exports));
|
|
1521
|
+
var REDACTED = "[redacted]";
|
|
1522
|
+
function redactToolSecrets(value) {
|
|
1523
|
+
if (Array.isArray(value)) return value.map(redactToolSecrets);
|
|
1524
|
+
if (!value || typeof value !== "object") return value;
|
|
1525
|
+
const out = {};
|
|
1526
|
+
for (const [k, v] of Object.entries(value)) out[k] = redactToolSecrets(v);
|
|
1527
|
+
const headers = out.tool_id && out.provider_settings?.headers;
|
|
1528
|
+
if (headers && typeof headers === "object" && !Array.isArray(headers)) {
|
|
1529
|
+
out.provider_settings = {
|
|
1530
|
+
...out.provider_settings,
|
|
1531
|
+
headers: Object.fromEntries(Object.entries(headers).map(([k, v]) => [
|
|
1532
|
+
k,
|
|
1533
|
+
typeof v === "string" && import_agentTools2.API_TOOL_SECRET_REF_PATTERN.test(v) ? v : REDACTED
|
|
1534
|
+
]))
|
|
1535
|
+
};
|
|
1536
|
+
}
|
|
1537
|
+
return out;
|
|
1538
|
+
}
|
|
938
1539
|
var opsToolCatalog2 = [
|
|
939
1540
|
...agentTools,
|
|
1541
|
+
...agentToolBindingTools,
|
|
940
1542
|
...callTools,
|
|
941
1543
|
...numberTools,
|
|
942
1544
|
...telephonyTools,
|
|
@@ -947,8 +1549,9 @@ var require_dist = __commonJS({
|
|
|
947
1549
|
...dncTools,
|
|
948
1550
|
...webhookTools,
|
|
949
1551
|
...billingTools,
|
|
950
|
-
...campaignTools
|
|
951
|
-
|
|
1552
|
+
...campaignTools,
|
|
1553
|
+
...shareLinkTools
|
|
1554
|
+
].map((t) => ({ ...t, run: async (client, params) => redactToolSecrets(await t.run(client, params)) }));
|
|
952
1555
|
var names = /* @__PURE__ */ new Set();
|
|
953
1556
|
for (const tool of opsToolCatalog2) {
|
|
954
1557
|
if (names.has(tool.name)) throw new Error(`Duplicate ops tool name: ${tool.name}`);
|
|
@@ -983,7 +1586,7 @@ function withToolErrors(handler) {
|
|
|
983
1586
|
// package.json
|
|
984
1587
|
var package_default = {
|
|
985
1588
|
name: "@rymi/mcp",
|
|
986
|
-
version: "2.
|
|
1589
|
+
version: "2.2.0",
|
|
987
1590
|
description: "Rymi MCP server \u2014 manage AI voice agents via Model Context Protocol",
|
|
988
1591
|
license: "MIT",
|
|
989
1592
|
author: "Rymi AI <engineering@rymi.live>",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rymi/mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Rymi MCP server — manage AI voice agents via Model Context Protocol",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Rymi AI <engineering@rymi.live>",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@modelcontextprotocol/sdk": "^1.11.1",
|
|
47
|
-
"@rymi/node": "^2.
|
|
47
|
+
"@rymi/node": "^2.2.0",
|
|
48
48
|
"zod": "^3.23.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|