@rymi/mcp 2.2.0 → 2.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 (3) hide show
  1. package/README.md +7 -3
  2. package/dist/index.js +210 -67
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -63,7 +63,7 @@ Run the server on your own machine — it speaks **stdio** by default and talks
63
63
  }
64
64
  ```
65
65
 
66
- > **Options:** `RYMI_MCP_READONLY=1` hides every mutating tool (including `create_call`, `batch_call`, `publish_agent`).
66
+ > **Options:** `RYMI_MCP_READONLY=1` hides every mutating tool (including `create_call`, `batch_call`, `publish_agent`). `RYMI_WORKSPACE` makes the local server act in that workspace (sent as the `Rymi-Workspace` header). On the hosted endpoint, send the `Rymi-Workspace` header on the HTTP request instead.
67
67
  >
68
68
  > This package speaks **stdio** only. `--transport http` was removed in 2.0.0 — use the hosted endpoint above, which the local server could never match on auth (it has no OAuth, and no per-key tool gating).
69
69
 
@@ -76,8 +76,8 @@ Run the server on your own machine — it speaks **stdio** by default and talks
76
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
77
  </tr>
78
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>
79
+ <td><b>Agent tools & secrets</b></td>
80
+ <td><code>set_agent_tools</code> · <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
81
  </tr>
82
82
  <tr>
83
83
  <td><b>Share link</b></td>
@@ -135,6 +135,10 @@ Run the server on your own machine — it speaks **stdio** by default and talks
135
135
  <td><b>Billing & cost</b></td>
136
136
  <td><code>estimate_call_cost</code> · <code>set_auto_recharge</code> · <code>set_spend_alerts</code></td>
137
137
  </tr>
138
+ <tr>
139
+ <td><b>Workspaces</b></td>
140
+ <td><code>list_workspaces</code> · <code>create_workspace</code></td>
141
+ </tr>
138
142
  </table>
139
143
 
140
144
  ### ⚠️ Gated tools
package/dist/index.js CHANGED
@@ -34,6 +34,68 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
34
34
  ));
35
35
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
36
 
37
+ // ../shared-types/dist/safeUrl.js
38
+ var safeUrl_exports = {};
39
+ __export(safeUrl_exports, {
40
+ isSafeUrl: () => isSafeUrl
41
+ });
42
+ function unmapIpv4(v6) {
43
+ const dotted = /^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/.exec(v6);
44
+ if (dotted)
45
+ return dotted[1];
46
+ const hex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(v6);
47
+ if (!hex)
48
+ return null;
49
+ const high = parseInt(hex[1], 16);
50
+ const low = parseInt(hex[2], 16);
51
+ return [high >> 8, high & 255, low >> 8, low & 255].join(".");
52
+ }
53
+ function isBlockedHost(host) {
54
+ const bare = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
55
+ if (bare === "localhost" || bare === "0.0.0.0" || bare === "::")
56
+ return true;
57
+ if (bare.endsWith(".local") || bare.endsWith(".internal") || bare.endsWith(".localhost"))
58
+ return true;
59
+ if (/^127\./.test(bare))
60
+ return true;
61
+ if (/^10\./.test(bare))
62
+ return true;
63
+ if (/^192\.168\./.test(bare))
64
+ return true;
65
+ if (/^172\.(1[6-9]|2\d|3[01])\./.test(bare))
66
+ return true;
67
+ if (/^169\.254\./.test(bare))
68
+ return true;
69
+ const v6 = bare.toLowerCase();
70
+ if (v6 === "::1")
71
+ return true;
72
+ if (/^f[cd][0-9a-f]{2}:/.test(v6))
73
+ return true;
74
+ if (/^fe[89ab][0-9a-f]:/.test(v6))
75
+ return true;
76
+ const mapped = unmapIpv4(v6);
77
+ if (mapped)
78
+ return isBlockedHost(mapped);
79
+ return false;
80
+ }
81
+ function isSafeUrl(raw, options = {}) {
82
+ const protocols = options.protocols ?? ["http:", "https:"];
83
+ let url;
84
+ try {
85
+ url = new URL(raw);
86
+ } catch {
87
+ return false;
88
+ }
89
+ if (!protocols.includes(url.protocol))
90
+ return false;
91
+ return !isBlockedHost(url.hostname.toLowerCase());
92
+ }
93
+ var init_safeUrl = __esm({
94
+ "../shared-types/dist/safeUrl.js"() {
95
+ "use strict";
96
+ }
97
+ });
98
+
37
99
  // ../shared-types/dist/agentTools.js
38
100
  var agentTools_exports = {};
39
101
  __export(agentTools_exports, {
@@ -43,9 +105,32 @@ __export(agentTools_exports, {
43
105
  API_TOOL_RESERVED_FIELD_NAMES: () => API_TOOL_RESERVED_FIELD_NAMES,
44
106
  API_TOOL_SECRET_REF_PATTERN: () => API_TOOL_SECRET_REF_PATTERN,
45
107
  BUILTIN_TOOL_CATALOG: () => BUILTIN_TOOL_CATALOG,
108
+ MCP_CONNECT_TIMEOUT_MS: () => MCP_CONNECT_TIMEOUT_MS,
109
+ MCP_SERVER_TOOL_ID: () => MCP_SERVER_TOOL_ID,
46
110
  SECRET_NAME_PATTERN: () => SECRET_NAME_PATTERN,
111
+ connectionStatus: () => connectionStatus,
112
+ isAgentToolEnabled: () => isAgentToolEnabled,
113
+ readMcpServerBinding: () => readMcpServerBinding,
47
114
  toToolCapabilitySafeView: () => toToolCapabilitySafeView
48
115
  });
116
+ function readMcpServerBinding(binding) {
117
+ const raw = binding?.provider_settings ?? {};
118
+ const url = typeof raw.url === "string" ? raw.url.trim() : "";
119
+ if (!isSafeUrl(url, { protocols: ["https:"] }))
120
+ return null;
121
+ const allowlist = Array.isArray(raw.allowlist) ? [...new Set(raw.allowlist.filter((t) => typeof t === "string" && t.trim() !== "").map((t) => t.trim()))].slice(0, MAX_MCP_ALLOWLIST) : [];
122
+ if (allowlist.length === 0)
123
+ return null;
124
+ const headers = {};
125
+ if (raw.headers && typeof raw.headers === "object" && !Array.isArray(raw.headers)) {
126
+ for (const [key, value] of Object.entries(raw.headers)) {
127
+ if (key.trim() && typeof value === "string")
128
+ headers[key.trim()] = value;
129
+ }
130
+ }
131
+ const name = typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : new URL(url).hostname;
132
+ return { name, url, headers, allowlist };
133
+ }
49
134
  function toToolCapabilitySafeView(state) {
50
135
  return {
51
136
  toolId: state.toolId,
@@ -54,10 +139,27 @@ function toToolCapabilitySafeView(state) {
54
139
  sideEffect: state.sideEffect
55
140
  };
56
141
  }
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;
142
+ function isAgentToolEnabled(bindings, defaultOn) {
143
+ if (bindings?.some((binding) => binding.enabled === true))
144
+ return true;
145
+ if (bindings?.some((binding) => binding.enabled === false))
146
+ return false;
147
+ return defaultOn;
148
+ }
149
+ function connectionStatus(row) {
150
+ if (row.is_active === false)
151
+ return "error";
152
+ const creds = row.credentials || {};
153
+ const hasRefreshToken = typeof creds.refresh_token === "string" && creds.refresh_token.trim().length > 0;
154
+ const expiresAt = typeof creds.expires_at === "string" ? new Date(creds.expires_at) : null;
155
+ const accessTokenExpired = expiresAt && !isNaN(expiresAt.getTime()) && expiresAt.getTime() < Date.now();
156
+ return accessTokenExpired && !hasRefreshToken ? "expired" : "connected";
157
+ }
158
+ 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, MCP_SERVER_TOOL_ID, MCP_CONNECT_TIMEOUT_MS, MAX_MCP_ALLOWLIST, BUILTIN_TOOL_CATALOG;
58
159
  var init_agentTools = __esm({
59
160
  "../shared-types/dist/agentTools.js"() {
60
161
  "use strict";
162
+ init_safeUrl();
61
163
  API_TOOL_NAME_PATTERN = /^[a-z][a-z0-9_]{2,40}$/;
62
164
  SECRET_NAME_PATTERN = /^[A-Z][A-Z0-9_]{1,63}$/;
63
165
  API_SECRETS_PROVIDER = "api_secrets";
@@ -101,6 +203,9 @@ var init_agentTools = __esm({
101
203
  ]);
102
204
  API_TOOL_AUTH_HEADER_PATTERN = /^(authorization|x-api-key|api[-_]?key|.*token.*|.*secret.*)$/i;
103
205
  API_TOOL_SECRET_REF_PATTERN = /\{\{\s*secrets\.[A-Z][A-Z0-9_]{1,63}\s*\}\}/;
206
+ MCP_SERVER_TOOL_ID = "mcp_server";
207
+ MCP_CONNECT_TIMEOUT_MS = 3e3;
208
+ MAX_MCP_ALLOWLIST = 50;
104
209
  BUILTIN_TOOL_CATALOG = [
105
210
  {
106
211
  tool_id: "handoff_to_human",
@@ -111,6 +216,15 @@ var init_agentTools = __esm({
111
216
  default_timeout_ms: 1e3,
112
217
  requires_credential: false
113
218
  },
219
+ {
220
+ tool_id: "schedule_callback",
221
+ label: "Scheduled callbacks",
222
+ description: "Let the agent schedule a call back to the caller at a time they choose, and place it itself at that time (Indian mobile numbers, 9 am to 9 pm IST). Needs a phone number attached to the agent or the workspace; no calendar or messaging connection is required.",
223
+ category: "call_control",
224
+ side_effect: "write",
225
+ default_timeout_ms: 4e3,
226
+ requires_credential: false
227
+ },
114
228
  {
115
229
  tool_id: "check_calendar_availability",
116
230
  label: "Check calendar availability",
@@ -220,73 +334,20 @@ var init_agentTools = __esm({
220
334
  // The endpoint lives in the binding's provider_settings and its secrets in
221
335
  // the tenant's api_secrets row — nothing to connect in Settings → Connectors.
222
336
  requires_credential: false
337
+ },
338
+ {
339
+ tool_id: "mcp_server",
340
+ label: "MCP server",
341
+ description: "Give the agent tools from your own MCP server. Only the tools you allowlist are offered; header secrets stay encrypted and are sent only to that server.",
342
+ category: "webhook",
343
+ side_effect: "write",
344
+ default_timeout_ms: MCP_CONNECT_TIMEOUT_MS,
345
+ requires_credential: false
223
346
  }
224
347
  ];
225
348
  }
226
349
  });
227
350
 
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
- });
289
-
290
351
  // ../ops-tools/dist/index.js
291
352
  var require_dist = __commonJS({
292
353
  "../ops-tools/dist/index.js"(exports2, module2) {
@@ -1270,7 +1331,7 @@ var require_dist = __commonJS({
1270
1331
  ];
1271
1332
  var import_zod11 = require("zod");
1272
1333
  var import_agentTools = (init_agentTools(), __toCommonJS(agentTools_exports));
1273
- var import_safeUrl = (init_safeUrl(), __toCommonJS(safeUrl_exports));
1334
+ var import_safeUrl2 = (init_safeUrl(), __toCommonJS(safeUrl_exports));
1274
1335
  var DEFAULT_NAME = "call_webhook";
1275
1336
  var METHODS = ["GET", "POST", "PUT", "PATCH"];
1276
1337
  var FIELD_NAME = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
@@ -1308,7 +1369,7 @@ var require_dist = __commonJS({
1308
1369
  const url = typeof s.url === "string" ? s.url.trim() : "";
1309
1370
  if (!url) errors.push("url is required.");
1310
1371
  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.");
1372
+ else if (!(0, import_safeUrl2.isSafeUrl)(url, { protocols: ["https:"] })) errors.push("url must be a valid public host; private and loopback addresses are refused at call time.");
1312
1373
  if (!METHODS.includes(s.method)) errors.push(`method must be one of ${METHODS.join(", ")}.`);
1313
1374
  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
1375
  const seen = /* @__PURE__ */ new Set();
@@ -1351,6 +1412,49 @@ var require_dist = __commonJS({
1351
1412
  }
1352
1413
  return found;
1353
1414
  }
1415
+ var ALWAYS_ON_TOOL_IDS = ["datetime_now", "knowledge_search", "end_call", "get_caller_history", "forget_me"];
1416
+ var SWITCHABLE_CATALOG = import_agentTools.BUILTIN_TOOL_CATALOG.filter((t) => t.tool_id !== "call_webhook" && t.tool_id !== "mcp_server");
1417
+ var TOOL_GROUPS = {
1418
+ calendar: [
1419
+ "check_calendar_availability",
1420
+ "list_calendar_events",
1421
+ "create_calendar_event",
1422
+ "update_calendar_event",
1423
+ "delete_calendar_event"
1424
+ ],
1425
+ tickets: ["lookup_ticket", "create_ticket"]
1426
+ };
1427
+ var SWITCHABLE_IDS = [...ALWAYS_ON_TOOL_IDS, ...SWITCHABLE_CATALOG.map((t) => t.tool_id)];
1428
+ function expandToolIds(requested) {
1429
+ const ids = /* @__PURE__ */ new Set();
1430
+ const unknown = [];
1431
+ for (const raw of requested) {
1432
+ const name = raw.trim();
1433
+ if (TOOL_GROUPS[name]) TOOL_GROUPS[name].forEach((id) => ids.add(id));
1434
+ else if (SWITCHABLE_IDS.includes(name)) ids.add(name);
1435
+ else unknown.push(name);
1436
+ }
1437
+ if (unknown.length) {
1438
+ throw new Error(`Unknown tool ${unknown.map((u) => `"${u}"`).join(", ")}. Use one of: ${[...Object.keys(TOOL_GROUPS), ...SWITCHABLE_IDS].join(", ")}. API tools use add/update/remove_agent_tool.`);
1439
+ }
1440
+ return [...ids];
1441
+ }
1442
+ function setToolsEnabled(tools, toolIds, enabled) {
1443
+ const next = tools.map((t) => toolIds.includes(t.tool_id) ? { ...t, enabled } : t);
1444
+ for (const toolId of toolIds) {
1445
+ if (next.some((t) => t.tool_id === toolId)) continue;
1446
+ const entry = SWITCHABLE_CATALOG.find((t) => t.tool_id === toolId);
1447
+ next.push({
1448
+ tool_id: toolId,
1449
+ enabled,
1450
+ credential_ref: null,
1451
+ timeout_ms: entry?.default_timeout_ms ?? 3e3,
1452
+ side_effect: entry?.side_effect ?? (toolId === "end_call" || toolId === "forget_me" ? "write" : "read"),
1453
+ provider_settings: {}
1454
+ });
1455
+ }
1456
+ return next;
1457
+ }
1354
1458
  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
1459
  var updateShape = {
1356
1460
  agent_id: import_zod11.z.string().describe("The agent UUID"),
@@ -1458,6 +1562,22 @@ var require_dist = __commonJS({
1458
1562
  return { status: "removed", agent_id: agentId, name, remaining: tools.filter(isApiTool).map(bindingName), note: LIVE_NOTE };
1459
1563
  }
1460
1564
  }),
1565
+ defineTool({
1566
+ name: "set_agent_tools",
1567
+ description: `Switch built-in tools on or off for one agent: calendar (check/list/create/update/delete), lookup_customer, lookup_ticket/create_ticket, send_whatsapp_message, send_telegram_message, send_asset, handoff_to_human, schedule_callback, and the always-on ones (end_call, forget_me, knowledge_search, get_caller_history, datetime_now). Groups: "calendar" (all five calendar tools), "tickets". Connected-app tools are opt-in per agent: connecting the app for the workspace makes them available, and an agent gets one only when switched on here or in Studio; it also needs the app connected (Settings \u2192 Connectors) to work on calls. Other agents are not affected. ${LIVE_NOTE}`,
1568
+ scope: "agent",
1569
+ risk: "write",
1570
+ input: {
1571
+ agent_id: import_zod11.z.string().describe("The agent UUID"),
1572
+ tools: import_zod11.z.array(import_zod11.z.string()).min(1).describe('Tool ids or groups, e.g. ["calendar"] or ["send_whatsapp_message", "send_asset"].'),
1573
+ enabled: import_zod11.z.boolean().describe("true switches them on for this agent, false switches them off.")
1574
+ },
1575
+ run: async (client, { agent_id, tools: requested, enabled }) => {
1576
+ const toolIds = expandToolIds(requested);
1577
+ const { agentId } = await writeTools(client, agent_id, (tools) => setToolsEnabled(tools, toolIds, enabled));
1578
+ return { status: enabled ? "enabled" : "disabled", agent_id: agentId, tools: toolIds, note: LIVE_NOTE };
1579
+ }
1580
+ }),
1461
1581
  defineTool({
1462
1582
  name: "list_tool_secrets",
1463
1583
  description: "List the workspace's API-tool secret names and the host each is pinned to. Values are never returned.",
@@ -1517,6 +1637,28 @@ var require_dist = __commonJS({
1517
1637
  run: (client, { agent_id }) => client.agents.regenerateShareLink(agent_id)
1518
1638
  })
1519
1639
  ];
1640
+ var import_zod13 = require("zod");
1641
+ var workspaceTools = [
1642
+ defineTool({
1643
+ name: "list_workspaces",
1644
+ description: "List the workspaces this credential can act in, marking the current one. Act in another by setting RYMI_WORKSPACE (local MCP) or the Rymi-Workspace header.",
1645
+ scope: "account",
1646
+ risk: "read",
1647
+ input: {},
1648
+ run: (client) => client.workspaces.list()
1649
+ }),
1650
+ defineTool({
1651
+ name: "create_workspace",
1652
+ description: "Create a standalone workspace you own, with its own agents, numbers, keys and balance. It gets no free monthly credit.",
1653
+ scope: "account",
1654
+ risk: "write",
1655
+ input: {
1656
+ name: import_zod13.z.string().min(1).max(80).describe("Workspace name"),
1657
+ operating_country: import_zod13.z.string().length(2).optional().describe('ISO-3166 alpha-2 country, e.g. "IN"')
1658
+ },
1659
+ run: (client, params) => client.workspaces.create(params)
1660
+ })
1661
+ ];
1520
1662
  var import_agentTools2 = (init_agentTools(), __toCommonJS(agentTools_exports));
1521
1663
  var REDACTED = "[redacted]";
1522
1664
  function redactToolSecrets(value) {
@@ -1550,7 +1692,8 @@ var require_dist = __commonJS({
1550
1692
  ...webhookTools,
1551
1693
  ...billingTools,
1552
1694
  ...campaignTools,
1553
- ...shareLinkTools
1695
+ ...shareLinkTools,
1696
+ ...workspaceTools
1554
1697
  ].map((t) => ({ ...t, run: async (client, params) => redactToolSecrets(await t.run(client, params)) }));
1555
1698
  var names = /* @__PURE__ */ new Set();
1556
1699
  for (const tool of opsToolCatalog2) {
@@ -1586,7 +1729,7 @@ function withToolErrors(handler) {
1586
1729
  // package.json
1587
1730
  var package_default = {
1588
1731
  name: "@rymi/mcp",
1589
- version: "2.2.0",
1732
+ version: "2.4.0",
1590
1733
  description: "Rymi MCP server \u2014 manage AI voice agents via Model Context Protocol",
1591
1734
  license: "MIT",
1592
1735
  author: "Rymi AI <engineering@rymi.live>",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rymi/mcp",
3
- "version": "2.2.0",
3
+ "version": "2.4.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.2.0",
47
+ "@rymi/node": "^2.3.0",
48
48
  "zod": "^3.23.0"
49
49
  },
50
50
  "devDependencies": {