@velaro/mcp-server 0.6.101 → 0.6.103
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 +61 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velaro/mcp-server",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.103",
|
|
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
|
@@ -1867,6 +1867,25 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
1867
1867
|
required: ['v10_site_id'],
|
|
1868
1868
|
},
|
|
1869
1869
|
},
|
|
1870
|
+
{
|
|
1871
|
+
name: 'livefluence_conversion_advisor',
|
|
1872
|
+
description: 'Velaro staff only (superadmin). Livefluence conversion advisor: reads a v10 site\'s groups and routing rules, clusters them by intent and returns a consolidated v20 design (one workflow per intent; page-path + device + geo conditions; team availability check with AI-node fallback), diffed against what already exists on the v20 site. Or pass intents (a structured list built from a customer description) instead of v10_site_id. apply=false (default) is a dry run; apply=true creates missing teams and workflows, ALWAYS DISABLED, idempotent by name. Always dry-run first. Same as CLI `velaro migrate advise`.',
|
|
1873
|
+
inputSchema: {
|
|
1874
|
+
type: 'object',
|
|
1875
|
+
properties: {
|
|
1876
|
+
v10_site_id: { type: 'number', description: 'V10 (Livefluence) site to read. Omit when passing intents.' },
|
|
1877
|
+
v20_site_id: { type: 'number', description: 'V20 destination site ID' },
|
|
1878
|
+
apply: { type: 'boolean', description: 'Create missing teams and DISABLED workflows. Default false (dry run + diff).' },
|
|
1879
|
+
include_non_routing: { type: 'boolean', description: 'Also read v10 rules with IsRouting=false (group-assignment rules). Default false.' },
|
|
1880
|
+
intents: {
|
|
1881
|
+
type: 'array',
|
|
1882
|
+
description: 'Structured intents: [{intent, paths[], device: any|mobile|desktop, countries[], excludeCountries[], target: "Service team + troubleshooting AI node" (or team / aiNode), mode: humanFirst|botFirst|aiOnly, priority}]',
|
|
1883
|
+
items: { type: 'object' },
|
|
1884
|
+
},
|
|
1885
|
+
},
|
|
1886
|
+
required: ['v20_site_id'],
|
|
1887
|
+
},
|
|
1888
|
+
},
|
|
1870
1889
|
{
|
|
1871
1890
|
name: 'livefluence_export',
|
|
1872
1891
|
description: 'Export V10 (Livefluence) routing rules for a site and show a preview of what would be created in V20. Auto-suggests V20 team and AI config matches by name. Use this before livefluence_migrate to confirm the mapping is correct.',
|
|
@@ -3336,11 +3355,11 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
3336
3355
|
},
|
|
3337
3356
|
{
|
|
3338
3357
|
name: 'enterprise_reports',
|
|
3339
|
-
description: 'Enterprise Reports package (enterprise-internal, default OFF; every report returns 403 when the site does not hold that package item). report: program_breakdown (compare websites, teams, platforms, devices or entry pages: volume, missed, transfers, wait, first reply, QA score and coverage, sentiment), agent_scorecard (per agent by name: resolution, transfers, handle time, AI score, supervisor-reviewed score, sentiment impact), qa_coverage (share of resolved chats AI-scored and supervisor-reviewed by week and program), coaching_queue (low-scoring chats nobody reviewed, per agent), sentiment_breakdown (by website, team, agent or topic with change vs prior period), topic_radar (topics by volume, growth, transfer rate), weekly_brief (preview of the Monday brief sections), weekly_brief_send_test (emails this week\'s brief to the signed-in user). Scoped to the caller site.',
|
|
3358
|
+
description: 'Enterprise Reports package (enterprise-internal, default OFF; every report returns 403 when the site does not hold that package item). report: program_breakdown (compare websites, teams, platforms, devices or entry pages: volume, missed, transfers, wait, first reply, QA score and coverage, sentiment), agent_scorecard (per agent by name: resolution, transfers, handle time, AI score, supervisor-reviewed score, sentiment impact), qa_coverage (share of resolved chats AI-scored and supervisor-reviewed by week and program), coaching_queue (low-scoring chats nobody reviewed, per agent), sentiment_breakdown (by website, team, agent or topic with change vs prior period), topic_radar (topics by volume, growth, transfer rate), weekly_brief (preview of the Monday brief sections), weekly_brief_send_test (emails this week\'s brief to the signed-in user), year_in_review (builds the 12-month Year in review document in the background: from/to yyyy-MM-dd inclusive, default the last 12 whole Pacific months, returns a build id; call again with buildId to get status and the download link). Scoped to the caller site.',
|
|
3340
3359
|
inputSchema: {
|
|
3341
3360
|
type: 'object',
|
|
3342
3361
|
properties: {
|
|
3343
|
-
report: { type: 'string', enum: ['program_breakdown', 'agent_scorecard', 'qa_coverage', 'coaching_queue', 'sentiment_breakdown', 'topic_radar', 'weekly_brief', 'weekly_brief_send_test', 'repeat_contact', 'demand_coverage', 'bot_containment', 'effort_index', 'promise_ledger', 'promise_dismiss'] },
|
|
3362
|
+
report: { type: 'string', enum: ['program_breakdown', 'agent_scorecard', 'qa_coverage', 'coaching_queue', 'sentiment_breakdown', 'topic_radar', 'weekly_brief', 'weekly_brief_send_test', 'repeat_contact', 'demand_coverage', 'bot_containment', 'effort_index', 'promise_ledger', 'promise_dismiss', 'year_in_review'] },
|
|
3344
3363
|
from: { type: 'string', description: 'yyyy-MM-dd start (default: 30 days ago).' },
|
|
3345
3364
|
to: { type: 'string', description: 'yyyy-MM-dd end, inclusive (default: today).' },
|
|
3346
3365
|
groupBy: { type: 'string', description: 'program_breakdown: website|team|platform|device|entrypage. sentiment_breakdown: website|team|agent|theme.' },
|
|
@@ -3358,6 +3377,7 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
3358
3377
|
lowScore: { type: 'number', description: 'bot_containment: QA score below which a handed-off chat counts as regret (1-100, default 60).' },
|
|
3359
3378
|
includeDemo: { type: 'boolean', description: 'true = show only the seeded sample (demo) data. Default false.' },
|
|
3360
3379
|
promiseId: { type: 'string', description: 'promise_dismiss: the promise id to dismiss (managers only).' },
|
|
3380
|
+
buildId: { type: 'string', description: 'year_in_review: the build id returned by a start call; when given, returns that build\'s status (queued|building|completed|failed) and download link instead of starting a new build.' },
|
|
3361
3381
|
},
|
|
3362
3382
|
required: ['report'],
|
|
3363
3383
|
},
|
|
@@ -7512,6 +7532,17 @@ async function handleTool(name, args) {
|
|
|
7512
7532
|
return JSON.stringify(result, null, 2);
|
|
7513
7533
|
}
|
|
7514
7534
|
|
|
7535
|
+
case 'livefluence_conversion_advisor': {
|
|
7536
|
+
const result = await api('POST', '/DatabaseTool/ConversionAdvisor', {
|
|
7537
|
+
v10SiteId: args.intents?.length ? null : (args.v10_site_id ?? null),
|
|
7538
|
+
v20SiteId: args.v20_site_id,
|
|
7539
|
+
apply: !!args.apply,
|
|
7540
|
+
includeNonRouting: !!args.include_non_routing,
|
|
7541
|
+
intents: args.intents ?? null,
|
|
7542
|
+
});
|
|
7543
|
+
return JSON.stringify(result, null, 2);
|
|
7544
|
+
}
|
|
7545
|
+
|
|
7515
7546
|
case 'livefluence_migrate': {
|
|
7516
7547
|
const result = await api('POST', '/DatabaseTool/V10Migrate', {
|
|
7517
7548
|
v10SiteId: args.v10_site_id,
|
|
@@ -9223,8 +9254,35 @@ async function handleTool(name, args) {
|
|
|
9223
9254
|
if (!args.promiseId) throw new Error('promiseId is required for promise_dismiss');
|
|
9224
9255
|
return JSON.stringify(await messagingPost('/api/enterprise-reports/promise-ledger/' + encodeURIComponent(String(args.promiseId)) + '/dismiss', {}), null, 2);
|
|
9225
9256
|
}
|
|
9257
|
+
if (args.report === 'year_in_review') {
|
|
9258
|
+
// POST starts a build (202 {id}); GET .../{id} -> {status, downloadUrl, error}. 403 when EnableEnterpriseReportsYearInReview is off.
|
|
9259
|
+
if (args.buildId) return JSON.stringify(await messagingGet('/api/enterprise-reports/year-in-review/' + encodeURIComponent(String(args.buildId))), null, 2);
|
|
9260
|
+
const zone = 'America/Los_Angeles';
|
|
9261
|
+
const keyRe = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
9262
|
+
const addDays = (k, n) => { const m = keyRe.exec(k); return new Date(Date.UTC(+m[1], +m[2] - 1, +m[3] + n)).toISOString().slice(0, 10); };
|
|
9263
|
+
const offsetMs = (ms) => {
|
|
9264
|
+
const ps = new Intl.DateTimeFormat('en-US', { timeZone: zone, hourCycle: 'h23', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }).formatToParts(new Date(ms));
|
|
9265
|
+
const g = (t) => Number(ps.find((p) => p.type === t).value);
|
|
9266
|
+
return Date.UTC(g('year'), g('month') - 1, g('day'), g('hour'), g('minute'), g('second')) - Math.floor(ms / 1000) * 1000;
|
|
9267
|
+
};
|
|
9268
|
+
const midnightIso = (k) => {
|
|
9269
|
+
if (!keyRe.test(k || '')) throw new Error('from/to must be yyyy-MM-dd');
|
|
9270
|
+
const m = keyRe.exec(k);
|
|
9271
|
+
const wall = Date.UTC(+m[1], +m[2] - 1, +m[3]);
|
|
9272
|
+
let t = wall - offsetMs(wall);
|
|
9273
|
+
t = wall - offsetMs(t);
|
|
9274
|
+
return new Date(t).toISOString();
|
|
9275
|
+
};
|
|
9276
|
+
const today = new Intl.DateTimeFormat('en-CA', { timeZone: zone, year: 'numeric', month: '2-digit', day: '2-digit' }).format(new Date());
|
|
9277
|
+
const defFrom = String(Number(today.slice(0, 4)) - 1).padStart(4, '0') + '-' + today.slice(5, 7) + '-01';
|
|
9278
|
+
const defTo = addDays(today.slice(0, 7) + '-01', -1);
|
|
9279
|
+
const f = args.from || defFrom;
|
|
9280
|
+
const t = args.to || defTo;
|
|
9281
|
+
if (f > t) throw new Error('from must be on or before to');
|
|
9282
|
+
return JSON.stringify(await messagingPost('/api/enterprise-reports/year-in-review', { from: midnightIso(f), to: midnightIso(addDays(t, 1)) }), null, 2);
|
|
9283
|
+
}
|
|
9226
9284
|
const seg = ER_PATHS[args.report];
|
|
9227
|
-
if (!seg) throw new Error('report must be one of: ' + Object.keys(ER_PATHS).join(', '));
|
|
9285
|
+
if (!seg) throw new Error('report must be one of: ' + Object.keys(ER_PATHS).join(', ') + ', promise_dismiss, year_in_review');
|
|
9228
9286
|
if (args.report === 'weekly_brief_send_test') return JSON.stringify(await messagingPost('/api/enterprise-reports/' + seg, {}), null, 2);
|
|
9229
9287
|
const qs = new URLSearchParams();
|
|
9230
9288
|
for (const k of ['from', 'to', 'groupBy', 'deploymentId', 'teamId', 'threshold', 'perAgent', 'limit', 'days', 'windowDays', 'weeks', 'handleMinutes', 'maxConcurrent', 'timeZone', 'lowScore', 'includeDemo']) {
|