@velaro/mcp-server 0.6.59 → 0.6.60

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 (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +60 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velaro/mcp-server",
3
- "version": "0.6.59",
3
+ "version": "0.6.60",
4
4
  "description": "Velaro MCP server — connect Claude and other AI agents directly to your Velaro account: KB, workflows, bots, conversations, contacts, routing, and more.",
5
5
  "type": "module",
6
6
  "bin": {
package/server.js CHANGED
@@ -245,19 +245,73 @@ function mcpFindUnresolved(value) {
245
245
  .map(([k]) => k);
246
246
  }
247
247
 
248
+ // The hosted gateway requires an initialized session (Mcp-Session-Id + MCP-Protocol-Version) on
249
+ // every call after "initialize". Cache one per process and re-initialize when it expires (404).
250
+ let gatewaySession = null;
251
+ async function gatewayInit() {
252
+ const res = await fetch(`${API_BASE}/mcp`, {
253
+ method: 'POST',
254
+ headers: { Authorization: authHeader(), 'Content-Type': 'application/json' },
255
+ body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: '2025-11-25', capabilities: {}, clientInfo: { name: 'velaro-mcp-server', version: '1' } } }),
256
+ });
257
+ if (!res.ok) {
258
+ const text = await res.text().catch(() => '');
259
+ throw new Error(`Velaro MCP gateway initialize -> ${res.status}: ${text.slice(0, 300)}`);
260
+ }
261
+ const sid = res.headers.get('mcp-session-id');
262
+ if (!sid) throw new Error('Velaro MCP gateway initialize returned no Mcp-Session-Id');
263
+ gatewaySession = { sid, version: res.headers.get('mcp-protocol-version') || '2025-11-25' };
264
+ return gatewaySession;
265
+ }
266
+
267
+ // Tools served by velaro-messaging's admin-tools gateway (McpAdminGatewayController, POST /mcp/v1/admin-tools/call,
268
+ // no session). The admin /mcp gateway only serves kb_* tools, so these used to fail there.
269
+ const MESSAGING_ADMIN_TOOLS = new Set([
270
+ 'workflow_create', 'workflow_list', 'workflow_get', 'workflow_toggle',
271
+ 'bot_create', 'bot_list', 'bot_get', 'bot_update_prompt', 'bot_set_knowledge',
272
+ 'ai_config_attach_index', 'call_pop_settings_get', 'call_pop_settings_set',
273
+ 'agent_list', 'team_list', 'conversation_list', 'conversation_get', 'conversation_search',
274
+ 'contact_search', 'contact_get', 'routing_list', 'routing_get', 'site_info',
275
+ 'ms_bookings_cancel_appointment', 'ms_bookings_check_availability_range', 'ms_bookings_reschedule_appointment',
276
+ 'outlook_calendar_cancel', 'outlook_calendar_get_available_range',
277
+ ]);
278
+
279
+ async function messagingAdminRpc(toolName, args) {
280
+ if (!MESSAGING_API) throw new Error('VELARO_MESSAGING_API is not configured.');
281
+ const res = await fetch(`${MESSAGING_API}/mcp/v1/admin-tools/call`, {
282
+ method: 'POST',
283
+ headers: { Authorization: authHeader(), 'Content-Type': 'application/json' },
284
+ body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name: toolName, arguments: args ?? {} } }),
285
+ signal: AbortSignal.timeout(30000),
286
+ });
287
+ const data = await res.json().catch(() => ({}));
288
+ if (!res.ok || data.error) {
289
+ throw new Error(`Velaro admin-tools ${toolName} -> ${res.status}: ${data.error?.message || JSON.stringify(data).slice(0, 300)}`);
290
+ }
291
+ const content = data.result?.content?.[0]?.text;
292
+ if (content === undefined) throw new Error('Empty response from admin-tools gateway');
293
+ return content;
294
+ }
295
+
248
296
  // Call the hosted MCP gateway (JSON-RPC) for tools that are dispatched server-side.
249
297
  async function rpc(toolName, args) {
298
+ if (MESSAGING_ADMIN_TOOLS.has(toolName)) return messagingAdminRpc(toolName, args);
250
299
  const body = {
251
300
  jsonrpc: '2.0',
252
301
  id: 1,
253
302
  method: 'tools/call',
254
303
  params: { name: toolName, arguments: args ?? {} },
255
304
  };
256
- const res = await fetch(`${API_BASE}/mcp`, {
257
- method: 'POST',
258
- headers: { Authorization: authHeader(), 'Content-Type': 'application/json' },
259
- body: JSON.stringify(body),
260
- });
305
+ const send = async () => {
306
+ const s = gatewaySession || await gatewayInit();
307
+ return fetch(`${API_BASE}/mcp`, {
308
+ method: 'POST',
309
+ headers: { Authorization: authHeader(), 'Content-Type': 'application/json', 'Mcp-Session-Id': s.sid, 'MCP-Protocol-Version': s.version },
310
+ body: JSON.stringify(body),
311
+ });
312
+ };
313
+ let res = await send();
314
+ if (res.status === 404) { gatewaySession = null; res = await send(); }
261
315
  if (!res.ok) {
262
316
  const text = await res.text().catch(() => '');
263
317
  throw new Error(`Velaro MCP gateway ${toolName} -> ${res.status}: ${text.slice(0, 300)}`);
@@ -8249,7 +8303,7 @@ async function handleTool(name, args) {
8249
8303
  }
8250
8304
 
8251
8305
  case 'billing_plan_status': {
8252
- const s = await api('GET', '/BillingPayment/plan-status');
8306
+ const s = await api('GET', '/BillingPayment/plan-status', undefined, MESSAGING_API);
8253
8307
  const lines = [`Site ${s.siteId} — Subscription Status`];
8254
8308
  if (s.subscription) {
8255
8309
  lines.push(`Seats: ${s.subscription.maxLicensedSeats} | Conv/mo: ${s.subscription.maxConversationsPerMonth || '∞'} | Self-serve: ${s.subscription.enableSelfServeSeats ? 'YES' : 'no'}`);