@velaro/mcp-server 0.6.70 → 0.6.71
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/package.json +1 -1
- package/server.js +112 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velaro/mcp-server",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.71",
|
|
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
|
@@ -2617,6 +2617,22 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
2617
2617
|
},
|
|
2618
2618
|
|
|
2619
2619
|
// ── Support Tools (Velaro staff only) ────────────────────────────────────────
|
|
2620
|
+
{
|
|
2621
|
+
name: 'support_add_site_user',
|
|
2622
|
+
description: 'Velaro staff only. Create or ensure a NORMAL user (role agent or administrator, never staff/superadmin) on ANY customer site with an explicit non-forcing password, usable immediately. Idempotent: an existing user just gets the password set. Password goes in the HTTPS body only and is never logged or returned. Composes velaro-messaging SuperAdmin users create + set-password (same staff-WorkspaceUser auth caveat as site_provision: an MCP-key-only session may 403; use `velaro support add-site-user` then).',
|
|
2623
|
+
inputSchema: {
|
|
2624
|
+
type: 'object',
|
|
2625
|
+
properties: {
|
|
2626
|
+
siteId: { type: 'number', description: 'Target customer site ID' },
|
|
2627
|
+
email: { type: 'string' },
|
|
2628
|
+
password: { type: 'string', description: 'Min 8 characters' },
|
|
2629
|
+
role: { type: 'string', enum: ['agent', 'administrator'], description: 'Default agent' },
|
|
2630
|
+
firstName: { type: 'string' },
|
|
2631
|
+
lastName: { type: 'string' },
|
|
2632
|
+
},
|
|
2633
|
+
required: ['siteId', 'email', 'password'],
|
|
2634
|
+
},
|
|
2635
|
+
},
|
|
2620
2636
|
{
|
|
2621
2637
|
name: 'support_agent_lookup',
|
|
2622
2638
|
description: 'Resolve a bare messaging WorkspaceUser.Id (AgentId, e.g. from an AgentPresenceFlapping WARN or AgentConnectionLog entry that carries no SiteId) to its Email/DisplayName/SiteId across ALL sites. Read-only, Velaro staff only. Different ID space from support_user_lookup (which searches ApplicationUsers/login identity, not the per-agent messaging record).',
|
|
@@ -2704,6 +2720,34 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
2704
2720
|
required: ['siteId'],
|
|
2705
2721
|
},
|
|
2706
2722
|
},
|
|
2723
|
+
{
|
|
2724
|
+
name: 'support_connection_timeline',
|
|
2725
|
+
description: 'Raw ordered connection events (connected, disconnected, reconnecting) for ONE agent at a site over a time window, from velaro-messaging AgentConnectionLogs. Velaro staff only, read-only. Defaults to the last 24 hours.',
|
|
2726
|
+
inputSchema: {
|
|
2727
|
+
type: 'object',
|
|
2728
|
+
properties: {
|
|
2729
|
+
siteId: { type: 'number', description: 'Target site ID' },
|
|
2730
|
+
workspaceUserId: { type: 'number', description: 'WorkspaceUser.Id of the agent (see support_site_agents)' },
|
|
2731
|
+
from: { type: 'string', description: 'ISO start (default: 24h before "to")' },
|
|
2732
|
+
to: { type: 'string', description: 'ISO end (default: now)' },
|
|
2733
|
+
limit: { type: 'number', description: 'Max events, 1-5000 (default 2000)' },
|
|
2734
|
+
},
|
|
2735
|
+
required: ['siteId', 'workspaceUserId'],
|
|
2736
|
+
},
|
|
2737
|
+
},
|
|
2738
|
+
{
|
|
2739
|
+
name: 'support_connection_evidence',
|
|
2740
|
+
description: 'Dispute-grade connection evidence for a site and window: Velaro independent probe uptime %, incidents (including ones excluded from uptime, with the reason), per-agent disconnect counts, and client-vs-server reconciliation (disconnects with no unhealthy Velaro probe within 5 minutes are client/network side). Velaro staff only, read-only. Defaults to the last 30 days.',
|
|
2741
|
+
inputSchema: {
|
|
2742
|
+
type: 'object',
|
|
2743
|
+
properties: {
|
|
2744
|
+
siteId: { type: 'number', description: 'Target site ID' },
|
|
2745
|
+
from: { type: 'string', description: 'ISO start (default: 30 days before "to")' },
|
|
2746
|
+
to: { type: 'string', description: 'ISO end (default: now)' },
|
|
2747
|
+
},
|
|
2748
|
+
required: ['siteId'],
|
|
2749
|
+
},
|
|
2750
|
+
},
|
|
2707
2751
|
{
|
|
2708
2752
|
name: 'support_site_health',
|
|
2709
2753
|
description: 'Get a full health snapshot for a customer site: subscription status/expiry, active agent count, last login, 7-day activity count, and integration error count. Velaro staff only.',
|
|
@@ -2722,6 +2766,14 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
2722
2766
|
required: ['siteId'],
|
|
2723
2767
|
},
|
|
2724
2768
|
},
|
|
2769
|
+
{
|
|
2770
|
+
name: 'report_explain',
|
|
2771
|
+
description: 'How to use and interpret a Velaro report: what it answers, data sources, setup prerequisites, how to read the numbers, why a value could be zero or empty, what to do, and related reports. Pass a report key (e.g. experience-impact, missed, surveys, schedule-adherence) or omit to list all keys. Static guidance, no site data.',
|
|
2772
|
+
inputSchema: {
|
|
2773
|
+
type: 'object',
|
|
2774
|
+
properties: { report: { type: 'string', description: 'Report key. Omit to list all.' } },
|
|
2775
|
+
},
|
|
2776
|
+
},
|
|
2725
2777
|
{
|
|
2726
2778
|
name: 'experience_impact_report',
|
|
2727
2779
|
description: 'Experience Impact report: shows how staffing and schedule adherence affect customer experience. Returns a 0-100 experience index (adherence 25, service level 30, missed-chat rate 20, CSAT 25), per-interval staffing vs chat demand (scheduled vs actual agents, missed chats, wait time, CSAT), per-agent rows, a bot-vs-human breakdown (bot only, bot-to-human handoff, human only, with wait, missed, CSAT and bot containment rate), and plain-language insights. Scoped to the caller site.',
|
|
@@ -7622,6 +7674,28 @@ async function handleTool(name, args) {
|
|
|
7622
7674
|
}
|
|
7623
7675
|
|
|
7624
7676
|
// ── Support Tools ─────────────────────────────────────────────────────────
|
|
7677
|
+
case 'support_add_site_user': {
|
|
7678
|
+
const roleMap = { agent: 'Agent', administrator: 'Administrator' };
|
|
7679
|
+
const role = String(args.role || 'agent').toLowerCase();
|
|
7680
|
+
if (!roleMap[role]) throw new Error('role must be agent or administrator.');
|
|
7681
|
+
const email = String(args.email || '').trim().toLowerCase();
|
|
7682
|
+
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) throw new Error('A valid email is required.');
|
|
7683
|
+
if (typeof args.password !== 'string' || args.password.length < 8) throw new Error('password is required (min 8 characters).');
|
|
7684
|
+
const listed = await messagingGet(`/SuperAdmin/users/${args.siteId}`);
|
|
7685
|
+
const users = Array.isArray(listed) ? listed : (listed?.users || []);
|
|
7686
|
+
let u = users.find(x => String(x.email || '').toLowerCase() === email);
|
|
7687
|
+
let created = false;
|
|
7688
|
+
if (!u) {
|
|
7689
|
+
const c = await messagingPost(`/SuperAdmin/users/${args.siteId}`, { email, firstName: args.firstName || '', lastName: args.lastName || '', roles: [roleMap[role]], sendEmail: false });
|
|
7690
|
+
if (!c?.success) throw new Error(`Create failed: ${c?.error || c?.message || 'unknown error'}`);
|
|
7691
|
+
u = { id: c.user.id ?? c.user.Id };
|
|
7692
|
+
created = true;
|
|
7693
|
+
}
|
|
7694
|
+
const sp = await messagingPost(`/SuperAdmin/users/${args.siteId}/${u.id}/set-password`, { newPassword: args.password });
|
|
7695
|
+
if (sp && sp.success === false) throw new Error(`set-password failed: ${sp.error || 'unknown error'}`);
|
|
7696
|
+
return JSON.stringify({ success: true, siteId: args.siteId, userId: u.id, email, created, passwordSet: true });
|
|
7697
|
+
}
|
|
7698
|
+
|
|
7625
7699
|
case 'support_agent_lookup': {
|
|
7626
7700
|
if (!args.id) return 'id is required (WorkspaceUser.Id / AgentId).';
|
|
7627
7701
|
const res = await messagingApi(`/SuperAdmin/agents/${args.id}/lookup`);
|
|
@@ -7691,6 +7765,29 @@ async function handleTool(name, args) {
|
|
|
7691
7765
|
return lines.join('\n');
|
|
7692
7766
|
}
|
|
7693
7767
|
|
|
7768
|
+
case 'support_connection_timeline': {
|
|
7769
|
+
if (!args.siteId || !args.workspaceUserId) return 'siteId and workspaceUserId are required.';
|
|
7770
|
+
const q = new URLSearchParams();
|
|
7771
|
+
if (args.from) q.set('from', args.from);
|
|
7772
|
+
if (args.to) q.set('to', args.to);
|
|
7773
|
+
if (args.limit) q.set('limit', String(args.limit));
|
|
7774
|
+
const qs = q.toString() ? `?${q}` : '';
|
|
7775
|
+
const res = await messagingApi(`/SupportTools/sites/${args.siteId}/agents/${args.workspaceUserId}/connection-timeline${qs}`);
|
|
7776
|
+
if (res?.error) return `Error: ${res.error}`;
|
|
7777
|
+
return JSON.stringify(res, null, 2);
|
|
7778
|
+
}
|
|
7779
|
+
|
|
7780
|
+
case 'support_connection_evidence': {
|
|
7781
|
+
if (!args.siteId) return 'siteId is required.';
|
|
7782
|
+
const q = new URLSearchParams();
|
|
7783
|
+
if (args.from) q.set('from', args.from);
|
|
7784
|
+
if (args.to) q.set('to', args.to);
|
|
7785
|
+
const qs = q.toString() ? `?${q}` : '';
|
|
7786
|
+
const res = await messagingApi(`/SupportTools/sites/${args.siteId}/connection-evidence${qs}`);
|
|
7787
|
+
if (res?.error) return `Error: ${res.error}`;
|
|
7788
|
+
return JSON.stringify(res, null, 2);
|
|
7789
|
+
}
|
|
7790
|
+
|
|
7694
7791
|
case 'support_site_health': {
|
|
7695
7792
|
const h = await api('GET', `/SupportTools/sites/${args.siteId}/health`);
|
|
7696
7793
|
const sub = h.subscription;
|
|
@@ -7717,6 +7814,15 @@ async function handleTool(name, args) {
|
|
|
7717
7814
|
).join('\n');
|
|
7718
7815
|
}
|
|
7719
7816
|
|
|
7817
|
+
case 'report_explain': {
|
|
7818
|
+
const all = JSON.parse(_readFileSync(_join(_dirname(_ftu(import.meta.url)), '..', 'cli', 'lib', 'report-explain.json'), 'utf8'));
|
|
7819
|
+
const key = String(args.report ?? '').trim().toLowerCase();
|
|
7820
|
+
if (!key) return Object.entries(all).map(([k, r]) => `${k}: ${r.name}`).join('\n');
|
|
7821
|
+
const r = all[key];
|
|
7822
|
+
if (!r) return `Unknown report "${key}". Valid keys: ${Object.keys(all).join(', ')}`;
|
|
7823
|
+
return [`=== ${r.name} ===`, `Answers: ${r.answers}`, `Sources: ${r.sources}`, `Setup: ${r.prerequisites}`, `How to read: ${r.interpret}`, `Why zero/empty: ${r.whyZero}`, `What to do: ${r.fix}`, `Related: ${r.related}`].join('\n');
|
|
7824
|
+
}
|
|
7825
|
+
|
|
7720
7826
|
case 'experience_impact_report': {
|
|
7721
7827
|
const qs = new URLSearchParams();
|
|
7722
7828
|
for (const k of ['from', 'to', 'teamId']) if (args[k] != null && args[k] !== '') qs.set(k, String(args[k]));
|
|
@@ -7739,6 +7845,12 @@ async function handleTool(name, args) {
|
|
|
7739
7845
|
lines.push(` ${label}: ${x.chats} chats | avg wait ${x.avgWaitSec}s | missed ${x.missed} | CSAT ${x.csatResponses ? x.csatAvg : '-'} (${x.csatResponses ?? 0})`);
|
|
7740
7846
|
}
|
|
7741
7847
|
}
|
|
7848
|
+
// Additive fields from the rebuilt report (absent on older backends): CSAT coverage + per-KPI reasons.
|
|
7849
|
+
if (r.coverage) {
|
|
7850
|
+
const c = r.coverage;
|
|
7851
|
+
lines.push(`CSAT coverage: ${(c.sources ?? []).map(x => `${x.label} ${x.responses} (avg ${x.avg ?? '-'})`).join(' | ')} | survey submissions ${c.surveySubmissions ?? 0}, rated ${c.surveyRated ?? 0}, response rate ${c.responseRatePct ?? 0}% | CSAT survey configured: ${c.csatSurveyConfigured ? 'yes' : 'no'}`);
|
|
7852
|
+
}
|
|
7853
|
+
for (const x of r.reasons ?? []) lines.push(` Why ${x.kpi} is low/empty [${x.code}]: ${x.message}${x.action ? ' Action: ' + x.action : ''}`);
|
|
7742
7854
|
for (const a of r.agents ?? []) lines.push(` ${a.name}: index ${a.experienceIndex} | adherence ${a.adherencePct}% | CSAT ${a.csatAvg ?? '-'} | handled ${a.handled}`);
|
|
7743
7855
|
return lines.join('\n');
|
|
7744
7856
|
}
|