@velaro/mcp-server 0.6.100 → 0.6.102

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 +122 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velaro/mcp-server",
3
- "version": "0.6.100",
3
+ "version": "0.6.102",
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
@@ -842,6 +842,7 @@ const TOOLS = [
842
842
  groupBy: { type: 'string', description: '"month" or "week" (default month)' },
843
843
  deploymentId: { type: 'number', description: 'Optional website (deployment row id) filter' },
844
844
  teamId: { type: 'number', description: 'Optional team filter' },
845
+ includeSecondary: { type: 'boolean', description: 'Also return secondary topics per conversation (needs the site multi-topic setting on). Response becomes { report, secondary: [{ theme, conversations, avgConfidence }] }.' },
845
846
  },
846
847
  },
847
848
  },
@@ -895,6 +896,16 @@ const TOOLS = [
895
896
  description: 'Replace the active topic list (max 60 topics, 60 chars each, duplicates removed). Used for new classifications only; existing history is untouched. Optionally load a template first with industry.',
896
897
  inputSchema: { type: 'object', properties: { topics: { type: 'array', items: { type: 'string' } }, industry: { type: 'string', description: 'Load a template instead: insurance, healthcare, retail, ecommerce, financial, saas, government, manufacturing' } } },
897
898
  },
899
+ {
900
+ name: 'chat_topics_settings_get',
901
+ description: 'Chat Intelligence multi-topic site setting: { themeMultiTopicEnabled (default off), themeReEvalEveryNMessages (1-50, default 5) }. Customer-writable by site supervisors.',
902
+ inputSchema: { type: 'object', properties: {} },
903
+ },
904
+ {
905
+ name: 'chat_topics_settings_set',
906
+ description: 'Turn multi-topic tracking on or off for this site and/or set how many new visitor messages trigger a topic re-check (1-50). Partial and idempotent: omit a field to leave it unchanged. Supervisor only.',
907
+ inputSchema: { type: 'object', properties: { themeMultiTopicEnabled: { type: 'boolean' }, themeReEvalEveryNMessages: { type: 'number' } } },
908
+ },
898
909
  {
899
910
  name: 'chat_topics_edit',
900
911
  description: 'Merge, rename, retire or group topics. Applied when reports are read, so history follows the new names with zero AI cost. op = merge|rename|retire|group; from = topic names; to = target (merge/rename); group = group name (empty clears).',
@@ -1139,10 +1150,25 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
1139
1150
  },
1140
1151
  {
1141
1152
  name: 'survey_upsert',
1142
- description: 'Create (omit id or set id=0) or update (set id) a survey. body must be the full SurveyViewModel JSON shape (id, name, questions[], each question with type/text/options/required/variable/etc.). Use survey_get on an existing survey to fetch this full shape as a template rather than guessing the question schema from scratch.',
1143
- inputSchema: {
1144
- type: 'object',
1145
- properties: { body: { type: 'object', description: 'Full SurveyViewModel JSON' } },
1153
+ description: 'Create (omit id or set id=0) or update (set id) a survey. body must be the full SurveyViewModel JSON shape (id, name, questions[], each question with type/text/options/required/variable/etc.). Use survey_get on an existing survey to fetch this full shape as a template rather than guessing the question schema from scratch. Each question also accepts isThemeAnchor (boolean, default false: this answer sets the Chat Intelligence topic) and themeMapping (string: JSON object mapping answer text to a site topic, e.g. "{\\"Pay my bill\\":\\"Billing Questions\\"}"). Both only take effect when the site has the multi-topic setting on.',
1154
+ inputSchema: {
1155
+ type: 'object',
1156
+ properties: { body: {
1157
+ type: 'object',
1158
+ description: 'Full SurveyViewModel JSON',
1159
+ properties: {
1160
+ questions: {
1161
+ type: 'array',
1162
+ items: {
1163
+ type: 'object',
1164
+ properties: {
1165
+ isThemeAnchor: { type: 'boolean', description: 'Use the answer to this question as the Chat Intelligence topic (default false)' },
1166
+ themeMapping: { type: 'string', description: 'JSON object string mapping answer text to a site topic; invalid or empty is stored as null' },
1167
+ },
1168
+ },
1169
+ },
1170
+ },
1171
+ } },
1146
1172
  required: ['body'],
1147
1173
  },
1148
1174
  },
@@ -1562,6 +1588,23 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
1562
1588
  },
1563
1589
  },
1564
1590
 
1591
+ // ── Dynamics per-team overrides (effective = team override ?? connection default) ──
1592
+ {
1593
+ name: 'dynamics_team_overrides_get',
1594
+ description: 'List per-team (group) Dynamics overrides of custom field mappings and activity type for a Dynamics config, plus the config\'s own "apply to all groups" defaults. Site is resolved server-side.',
1595
+ inputSchema: { type: 'object', properties: { configId: { type: 'number' } }, required: ['configId'] },
1596
+ },
1597
+ {
1598
+ name: 'dynamics_team_overrides_set',
1599
+ description: 'Create/update one team\'s Dynamics override. Apply-if-present: omitted fields are unchanged; an empty string clears that field back to the default. Fields: activityLogicalName (e.g. phonecall, task), customFieldMappingsJson (JSON array string).',
1600
+ inputSchema: { type: 'object', properties: { configId: { type: 'number' }, teamId: { type: 'number' }, activityLogicalName: { type: 'string' }, customFieldMappingsJson: { type: 'string' } }, required: ['configId', 'teamId'] },
1601
+ },
1602
+ {
1603
+ name: 'dynamics_team_overrides_reset',
1604
+ description: 'Reset a team to the Dynamics default (removes its override).',
1605
+ inputSchema: { type: 'object', properties: { configId: { type: 'number' }, teamId: { type: 'number' } }, required: ['configId', 'teamId'] },
1606
+ },
1607
+
1565
1608
  // ── Teams ─────────────────────────────────────────────────────────────────
1566
1609
  {
1567
1610
  name: 'team_list',
@@ -1824,6 +1867,25 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
1824
1867
  required: ['v10_site_id'],
1825
1868
  },
1826
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
+ },
1827
1889
  {
1828
1890
  name: 'livefluence_export',
1829
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.',
@@ -3474,6 +3536,18 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
3474
3536
  },
3475
3537
  },
3476
3538
 
3539
+ // -- Image Analysis (analyze_image) limits (superadmin) --
3540
+ {
3541
+ name: 'image_analysis_limits',
3542
+ description: 'Show a customer site Image Analysis (photo analysis) add-on limits: entitlement, monthly cap (MaxImageAnalysesPerMonth), usage this month, per-chat cap and extra-block size. Velaro admin only. To change the cap use support_set_limit with key MaxImageAnalysesPerMonth.',
3543
+ inputSchema: {
3544
+ type: 'object',
3545
+ properties: {
3546
+ siteId: { type: 'number', description: 'Site ID to check' },
3547
+ },
3548
+ required: ['siteId'],
3549
+ },
3550
+ },
3477
3551
  // ── AI Video Avatar management (superadmin) ────────────────────────────────
3478
3552
  {
3479
3553
  name: 'avatar_get_config',
@@ -6398,6 +6472,7 @@ async function handleTool(name, args) {
6398
6472
  qs.set('groupBy', args.groupBy ?? 'month');
6399
6473
  if (args.deploymentId != null) qs.set('deploymentId', String(args.deploymentId));
6400
6474
  if (args.teamId != null) qs.set('teamId', String(args.teamId));
6475
+ if (args.includeSecondary === true) qs.set('includeSecondary', 'true');
6401
6476
  return await messagingGet(`/Reports/chat-intelligence/themes?${qs.toString()}`);
6402
6477
  }
6403
6478
  case 'chat_topics_get':
@@ -6406,6 +6481,13 @@ async function handleTool(name, args) {
6406
6481
  return args.industry
6407
6482
  ? await messagingPost('/ChatIntelligenceTopics/template', { industry: args.industry })
6408
6483
  : await messagingPut('/ChatIntelligenceTopics', { topics: args.topics ?? [] });
6484
+ case 'chat_topics_settings_get':
6485
+ return await messagingGet('/ChatIntelligenceTopics/settings');
6486
+ case 'chat_topics_settings_set':
6487
+ return await messagingPut('/ChatIntelligenceTopics/settings', {
6488
+ themeMultiTopicEnabled: typeof args.themeMultiTopicEnabled === 'boolean' ? args.themeMultiTopicEnabled : null,
6489
+ themeReEvalEveryNMessages: typeof args.themeReEvalEveryNMessages === 'number' ? args.themeReEvalEveryNMessages : null,
6490
+ });
6409
6491
  case 'chat_topics_edit':
6410
6492
  return await messagingPost('/ChatIntelligenceTopics/mapping', { ops: [{ op: args.op, from: args.from ?? [], to: args.to ?? null, group: args.group ?? null }] });
6411
6493
  case 'chat_topics_group_suggestions':
@@ -6993,6 +7075,19 @@ async function handleTool(name, args) {
6993
7075
  return await api('PUT', '/TeamsBot/PushSettings', body);
6994
7076
  }
6995
7077
 
7078
+ case 'dynamics_team_overrides_get':
7079
+ return await api('GET', `/Dynamics/Configs/${Number(args.configId)}/team-overrides`);
7080
+
7081
+ case 'dynamics_team_overrides_set': {
7082
+ const body = {};
7083
+ for (const k of ['activityLogicalName', 'customFieldMappingsJson'])
7084
+ if (args[k] !== undefined) body[k] = args[k];
7085
+ return await api('PUT', `/Dynamics/Configs/${Number(args.configId)}/team-overrides/${Number(args.teamId)}`, body);
7086
+ }
7087
+
7088
+ case 'dynamics_team_overrides_reset':
7089
+ return await api('DELETE', `/Dynamics/Configs/${Number(args.configId)}/team-overrides/${Number(args.teamId)}`);
7090
+
6996
7091
  case 'teams_channel_config_get':
6997
7092
  return await api('GET', '/TeamsBot/ChannelConfig');
6998
7093
 
@@ -7436,6 +7531,17 @@ async function handleTool(name, args) {
7436
7531
  return JSON.stringify(result, null, 2);
7437
7532
  }
7438
7533
 
7534
+ case 'livefluence_conversion_advisor': {
7535
+ const result = await api('POST', '/DatabaseTool/ConversionAdvisor', {
7536
+ v10SiteId: args.intents?.length ? null : (args.v10_site_id ?? null),
7537
+ v20SiteId: args.v20_site_id,
7538
+ apply: !!args.apply,
7539
+ includeNonRouting: !!args.include_non_routing,
7540
+ intents: args.intents ?? null,
7541
+ });
7542
+ return JSON.stringify(result, null, 2);
7543
+ }
7544
+
7439
7545
  case 'livefluence_migrate': {
7440
7546
  const result = await api('POST', '/DatabaseTool/V10Migrate', {
7441
7547
  v10SiteId: args.v10_site_id,
@@ -9275,6 +9381,18 @@ async function handleTool(name, args) {
9275
9381
  }
9276
9382
 
9277
9383
  // ── AI Video Avatar ────────────────────────────────────────────────────
9384
+ // -- Image Analysis limits --
9385
+ case 'image_analysis_limits': {
9386
+ const d = await api('GET', `/ImageAnalysisLimits/superadmin?siteId=${args.siteId}`);
9387
+ return [
9388
+ `Site ${args.siteId}: Image Analysis ${d.entitled === null ? 'entitlement unknown' : d.entitled ? 'ENTITLED' : 'NOT entitled'}`,
9389
+ ` Monthly cap: ${d.monthlyCap} (effective ${d.effectiveMonthlyCap}, hard cap, no automatic overage)`,
9390
+ ` Used this month: ${d.usedThisMonth === null ? 'unknown' : d.usedThisMonth}`,
9391
+ ` Per-chat cap: ${d.perConversationCap}`,
9392
+ ` Extra block size: ${d.blockSize}`,
9393
+ ].join('\n');
9394
+ }
9395
+
9278
9396
  case 'avatar_get_config': {
9279
9397
  const data = await api('GET', `/Avatar/superadmin/status?siteId=${args.siteId}`);
9280
9398
  if (!data.configured) return `Site ${args.siteId}: AI Video Avatar NOT configured (no saved config).`;