@velaro/mcp-server 0.6.74 → 0.6.75

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 +97 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velaro/mcp-server",
3
- "version": "0.6.74",
3
+ "version": "0.6.75",
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
@@ -187,6 +187,18 @@ function execInsightsRange(days) {
187
187
 
188
188
  const messagingDel = (path) => messagingRequest('DELETE', path);
189
189
 
190
+ // Skill-based routing CRUD helper for SkillRouting/{Skills|Assignments|Requirements}.
191
+ async function skillRoutingCrud(resource, args, fields) {
192
+ const body = Object.fromEntries(Object.entries(fields).filter(([, v]) => v !== undefined));
193
+ switch (args.action) {
194
+ case 'list': return await messagingGet('/SkillRouting/' + resource);
195
+ case 'create': return await messagingPost('/SkillRouting/' + resource, body);
196
+ case 'update': return await messagingPut('/SkillRouting/' + resource + '/' + args.id, body);
197
+ case 'delete': return await messagingDel('/SkillRouting/' + resource + '/' + args.id);
198
+ default: throw new Error('action must be list|create|update|delete');
199
+ }
200
+ }
201
+
190
202
  async function api(method, path, body, base = API_BASE) {
191
203
  // Normalize: a path without a leading slash would glue onto the host ("...comScraperJobs/...") and fail as "fetch failed".
192
204
  if (!path.startsWith('/')) path = '/' + path;
@@ -771,6 +783,8 @@ const TOOLS = [
771
783
  startDate: { type: 'string', description: 'ISO date (defaults to 90 days ago)' },
772
784
  endDate: { type: 'string', description: 'ISO date (defaults to today)' },
773
785
  groupBy: { type: 'string', description: '"month" or "week" (default month)' },
786
+ deploymentId: { type: 'number', description: 'Optional website (deployment row id) filter' },
787
+ teamId: { type: 'number', description: 'Optional team filter' },
774
788
  },
775
789
  },
776
790
  },
@@ -4986,6 +5000,21 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
4986
5000
  description: 'Get the Focus Inbox draft-pregeneration usage/cap report for this site -- whether the "Always Learning" background draft-pregeneration addon is entitled (EnableFocusDraftPregeneration), plus the live usage snapshot (used/max/percent) against the site\'s monthly draft-pregeneration cap. Use to check whether the addon is active and how close the site is to its cap.',
4987
5001
  inputSchema: { type: 'object', properties: {} },
4988
5002
  },
5003
+ {"name":"sentiment_report","description":"Sentiment report (v20). kind = overview | breakdown | conversation-overview | conversation-breakdown | contact-overview | agent-breakdown. Optional deploymentId (website) and teamId filters, verified server-side against your site.","inputSchema":{"type":"object","properties":{"kind":{"type":"string","description":"overview (default), breakdown, conversation-overview, conversation-breakdown, contact-overview, agent-breakdown"},"startDate":{"type":"string","description":"ISO date (default 30 days ago)"},"endDate":{"type":"string","description":"ISO date (default now)"},"groupBy":{"type":"string","description":"day (default), week, month"},"excludeBots":{"type":"boolean"},"deploymentId":{"type":"number","description":"Optional website (deployment row id) filter; must belong to your site"},"teamId":{"type":"number","description":"Optional team filter"}}}},
5004
+ {"name":"quality_agent_performance","description":"Conversation Quality agent performance (AI scores per agent). Optional deploymentId (website) and teamId filters.","inputSchema":{"type":"object","properties":{"days":{"type":"number","description":"Window in days (default 30)"},"deploymentId":{"type":"number","description":"Optional website (deployment row id) filter; must belong to your site"},"teamId":{"type":"number","description":"Optional team filter"}}}},
5005
+ {"name":"keyword_intelligence_top","description":"Top keywords/phrases customers use over a date range. Optional groupBy, ngram size, limit, teamId, agentId, website.","inputSchema":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"groupBy":{"type":"string","description":"none (default) or a grouping dimension"},"ngram":{"type":"number","description":"Phrase length 1-3 (default 3)"},"limit":{"type":"number","description":"Default 50"},"teamId":{"type":"number"},"agentId":{"type":"number"},"website":{"type":"string"}},"required":["from","to"]}},
5006
+ {"name":"keyword_intelligence_conversations","description":"Drill-down: conversations containing a keyword in a date range.","inputSchema":{"type":"object","properties":{"keyword":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"teamId":{"type":"number"},"agentId":{"type":"number"}},"required":["keyword","from","to"]}},
5007
+ {"name":"skill_routing_skills","description":"Skill-based routing: manage the skill catalog. action = list | create | update | delete. Requires the EnableSkillBasedRouting entitlement (403 otherwise).","inputSchema":{"type":"object","properties":{"action":{"type":"string"},"id":{"type":"number"},"name":{"type":"string"},"description":{"type":"string"}},"required":["action"]}},
5008
+ {"name":"skill_routing_assignments","description":"Skill-based routing: assign skills to agents with proficiency 1-5. action = list | create | update | delete.","inputSchema":{"type":"object","properties":{"action":{"type":"string"},"id":{"type":"number"},"workspaceUserId":{"type":"number"},"agentSkillId":{"type":"number"},"proficiency":{"type":"number"}},"required":["action"]}},
5009
+ {"name":"skill_routing_requirements","description":"Skill-based routing: required/preferred skills per deployment and/or team. action = list | create | update | delete. Update is partial. Requirements are disabled by default; set isEnabled true to turn on.","inputSchema":{"type":"object","properties":{"action":{"type":"string"},"id":{"type":"number"},"deploymentId":{"type":"number"},"teamId":{"type":"number"},"requiredSkillIds":{"type":"array","items":{"type":"number"}},"preferredSkillIds":{"type":"array","items":{"type":"number"}},"overflowWaitSeconds":{"type":"number"},"isEnabled":{"type":"boolean"}},"required":["action"]}},
5010
+ {"name":"skill_routing_simulate","description":"Dry-run skill routing for a team: shows which agents would be narrowed to and why. Never assigns a conversation or writes the decision log.","inputSchema":{"type":"object","properties":{"teamId":{"type":"number"},"waitedSeconds":{"type":"number"}}}},
5011
+ {"name":"qa_rubric","description":"Conversation Quality QA rubrics. action = list | get | default | create | update | delete. Pass rubric fields in \"rubric\". Requires EnableConversationQuality.","inputSchema":{"type":"object","properties":{"action":{"type":"string"},"id":{"type":"number"},"rubric":{"type":"object"}},"required":["action"]}},
5012
+ {"name":"qa_low_scores","description":"Conversations scoring below the rubric threshold, for QA review.","inputSchema":{"type":"object","properties":{"threshold":{"type":"number"},"days":{"type":"number"},"agentId":{"type":"number"},"skip":{"type":"number"},"take":{"type":"number"}}}},
5013
+ {"name":"ai_field_extraction_get_config","description":"Get the AI field extraction config (opt-in, default off; monthly cap). Requires the ai_field_extraction entitlement.","inputSchema":{"type":"object","properties":{}}},
5014
+ {"name":"ai_field_extraction_update_config","description":"Update AI field extraction config (partial). enabled, monthlyCap (null = 500 default, hard ceiling 50000), createThemeTags.","inputSchema":{"type":"object","properties":{"enabled":{"type":"boolean"},"monthlyCap":{"type":"number"},"createThemeTags":{"type":"boolean"}}}},
5015
+ {"name":"ai_field_extraction_correct_field","description":"Agent correction of an extracted field on a conversation.","inputSchema":{"type":"object","properties":{"conversationId":{"type":"number"},"fieldName":{"type":"string"},"value":{"type":"string"}},"required":["conversationId","fieldName","value"]}},
5016
+ {"name":"qa_calibration","description":"QA calibration report (AI score vs human review) for the last N days.","inputSchema":{"type":"object","properties":{"days":{"type":"number"}}}},
5017
+ {"name":"qa_alert_settings","description":"Get or set quality alert settings. Omit \"settings\" to read; pass it to update.","inputSchema":{"type":"object","properties":{"settings":{"type":"object"}}}},
4989
5018
  ];
4990
5019
 
4991
5020
  // ── IVR business-hours helper ─────────────────────────────────────────────────
@@ -5469,6 +5498,8 @@ async function handleTool(name, args) {
5469
5498
  if (args.startDate) qs.set('startDate', args.startDate);
5470
5499
  if (args.endDate) qs.set('endDate', args.endDate);
5471
5500
  qs.set('groupBy', args.groupBy ?? 'month');
5501
+ if (args.deploymentId != null) qs.set('deploymentId', String(args.deploymentId));
5502
+ if (args.teamId != null) qs.set('teamId', String(args.teamId));
5472
5503
  return await messagingGet(`/Reports/chat-intelligence/themes?${qs.toString()}`);
5473
5504
  }
5474
5505
  case 'chat_intelligence_recommendations':
@@ -9859,6 +9890,72 @@ async function handleTool(name, args) {
9859
9890
  return JSON.stringify(result, null, 2);
9860
9891
  }
9861
9892
 
9893
+
9894
+ // -- Wave: sentiment / quality / keyword intelligence / skill routing / QA rubric --
9895
+ case 'sentiment_report': {
9896
+ const routes = { 'overview': 'sentiment-overview', 'breakdown': 'sentiment-breakdown', 'conversation-overview': 'conversation-sentiment-overview', 'conversation-breakdown': 'conversation-sentiment-breakdown', 'contact-overview': 'contact-sentiment-overview', 'agent-breakdown': 'agent-sentiment-breakdown' };
9897
+ const kind = args.kind ?? 'overview';
9898
+ if (!routes[kind]) throw new Error('kind must be one of: ' + Object.keys(routes).join(', '));
9899
+ const end = args.endDate ? new Date(args.endDate) : new Date();
9900
+ const start = args.startDate ? new Date(args.startDate) : new Date(end.getTime() - 30 * 86400000);
9901
+ const body = { Start: start.toISOString(), End: end.toISOString(), GroupBy: args.groupBy ?? 'day', ExcludeBots: args.excludeBots === true };
9902
+ if (args.deploymentId != null) body.DeploymentId = args.deploymentId;
9903
+ if (args.teamId != null) body.TeamId = args.teamId;
9904
+ return await messagingPost('/Reports/' + routes[kind], body);
9905
+ }
9906
+ case 'quality_agent_performance': {
9907
+ const qs = new URLSearchParams({ days: String(args.days ?? 30) });
9908
+ if (args.deploymentId != null) qs.set('deploymentId', String(args.deploymentId));
9909
+ if (args.teamId != null) qs.set('teamId', String(args.teamId));
9910
+ return await messagingGet('/api/admin/Reports/AgentPerformance?' + qs.toString());
9911
+ }
9912
+ case 'keyword_intelligence_top': {
9913
+ const qs = new URLSearchParams({ from: args.from, to: args.to, groupBy: args.groupBy ?? 'none', ngram: String(args.ngram ?? 3), limit: String(args.limit ?? 50) });
9914
+ for (const k of ['teamId', 'agentId', 'website']) if (args[k] != null) qs.set(k, String(args[k]));
9915
+ return await messagingGet('/api/keyword-intelligence/top?' + qs.toString());
9916
+ }
9917
+ case 'keyword_intelligence_conversations': {
9918
+ const qs = new URLSearchParams({ keyword: args.keyword, from: args.from, to: args.to });
9919
+ for (const k of ['teamId', 'agentId']) if (args[k] != null) qs.set(k, String(args[k]));
9920
+ return await messagingGet('/api/keyword-intelligence/conversations?' + qs.toString());
9921
+ }
9922
+ case 'skill_routing_skills':
9923
+ return await skillRoutingCrud('Skills', args, { Name: args.name, Description: args.description });
9924
+ case 'skill_routing_assignments':
9925
+ return await skillRoutingCrud('Assignments', args, { WorkspaceUserId: args.workspaceUserId, AgentSkillId: args.agentSkillId, Proficiency: args.proficiency });
9926
+ case 'skill_routing_requirements':
9927
+ return await skillRoutingCrud('Requirements', args, { DeploymentId: args.deploymentId, TeamId: args.teamId, RequiredSkillIds: args.requiredSkillIds, PreferredSkillIds: args.preferredSkillIds, OverflowWaitSeconds: args.overflowWaitSeconds, IsEnabled: args.isEnabled });
9928
+ case 'skill_routing_simulate':
9929
+ return await messagingPost('/SkillRouting/Simulate', { TeamId: args.teamId ?? null, WaitedSeconds: args.waitedSeconds ?? null });
9930
+ case 'qa_rubric': {
9931
+ const a = args.action;
9932
+ if (a === 'list') return await messagingGet('/api/admin/QualityQa/rubrics');
9933
+ if (a === 'default') return await messagingGet('/api/admin/QualityQa/rubrics/default');
9934
+ if (a === 'get') return await messagingGet('/api/admin/QualityQa/rubrics/' + args.id);
9935
+ if (a === 'create') return await messagingPost('/api/admin/QualityQa/rubrics', args.rubric ?? {});
9936
+ if (a === 'update') return await messagingPut('/api/admin/QualityQa/rubrics/' + args.id, args.rubric ?? {});
9937
+ if (a === 'delete') return await messagingDel('/api/admin/QualityQa/rubrics/' + args.id);
9938
+ throw new Error('action must be list|get|default|create|update|delete');
9939
+ }
9940
+ case 'qa_low_scores': {
9941
+ const qs = new URLSearchParams({ days: String(args.days ?? 30), skip: String(args.skip ?? 0), take: String(args.take ?? 50) });
9942
+ if (args.threshold != null) qs.set('threshold', String(args.threshold));
9943
+ if (args.agentId != null) qs.set('agentId', String(args.agentId));
9944
+ return await messagingGet('/api/admin/QualityQa/low-scores?' + qs.toString());
9945
+ }
9946
+ case 'ai_field_extraction_get_config':
9947
+ return await messagingGet('/AiFieldExtraction/Config');
9948
+ case 'ai_field_extraction_update_config': {
9949
+ const body = Object.fromEntries(Object.entries({ Enabled: args.enabled, MonthlyCap: args.monthlyCap, CreateThemeTags: args.createThemeTags }).filter(([, v]) => v !== undefined));
9950
+ return await messagingPut('/AiFieldExtraction/Config', body);
9951
+ }
9952
+ case 'ai_field_extraction_correct_field':
9953
+ return await messagingPut('/AiFieldExtraction/Conversation/' + args.conversationId + '/Fields/' + encodeURIComponent(args.fieldName), { Value: args.value });
9954
+ case 'qa_calibration':
9955
+ return await messagingGet('/api/admin/QualityQa/calibration?days=' + (args.days ?? 90));
9956
+ case 'qa_alert_settings':
9957
+ return args.settings ? await messagingPut('/api/admin/QualityQa/alert-settings', args.settings) : await messagingGet('/api/admin/QualityQa/alert-settings');
9958
+
9862
9959
  default:
9863
9960
  throw new Error(`Unknown tool: ${name}`);
9864
9961
  }