@velaro/mcp-server 2.0.0 → 2.0.1
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 +160 -1
- package/tool-annotations.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velaro/mcp-server",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
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
|
@@ -1067,6 +1067,8 @@ Key node shapes:
|
|
|
1067
1067
|
propName:"myAnswerVar" } // variable that stores the result as JSON array string
|
|
1068
1068
|
• condition: { type:"action", actionType:"condition", conditionOptions:[...] }
|
|
1069
1069
|
• transferToAI: { type:"action", actionType:"transferToAI", aiConfigId:N }
|
|
1070
|
+
• selectPreChat: { type:"action", actionType:"selectPreChat", surveyId:N, surveyCompact:true|false|null, child:N }
|
|
1071
|
+
surveyCompact (optional tri-state): null/omitted = follow the survey's own compactMode, true = compact, false = regular.
|
|
1070
1072
|
• sendSurvey: { type:"action", actionType:"sendSurvey", sendSurveyId:N, surveyDeliveryMode:"conversational"|"form", closeAfterSurvey:true|false, child:N }
|
|
1071
1073
|
closeAfterSurvey (optional, default false): when true the chat closes once the visitor completes the survey (use for Unavailable/after-hours surveys that replace a live chat). Omit to keep the old behaviour.
|
|
1072
1074
|
AI follow-up suggestions ("AI mode"): add suggestFollowUps:true|false (omit = use the account default, set via ai_followups_site_set), suggestFollowUpCount:2-4, suggestFollowUpInstruction:"<=300 chars". After each web-chat bot reply the bot offers short tappable follow-up replies; typing stays available.
|
|
@@ -1132,13 +1134,14 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
1132
1134
|
},
|
|
1133
1135
|
{
|
|
1134
1136
|
name: 'survey_upsert',
|
|
1135
|
-
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.',
|
|
1137
|
+
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. body.compactMode is tri-state: null/omitted = follow default (regular size), true = compact, false = regular.',
|
|
1136
1138
|
inputSchema: {
|
|
1137
1139
|
type: 'object',
|
|
1138
1140
|
properties: { body: {
|
|
1139
1141
|
type: 'object',
|
|
1140
1142
|
description: 'Full SurveyViewModel JSON',
|
|
1141
1143
|
properties: {
|
|
1144
|
+
compactMode: { type: ['boolean', 'null'], description: 'Tri-state survey size: null/omitted = follow default (regular size), true = compact, false = regular' },
|
|
1142
1145
|
questions: {
|
|
1143
1146
|
type: 'array',
|
|
1144
1147
|
items: {
|
|
@@ -1582,6 +1585,28 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
1582
1585
|
},
|
|
1583
1586
|
},
|
|
1584
1587
|
|
|
1588
|
+
{
|
|
1589
|
+
name: 'agent_force_sign_out',
|
|
1590
|
+
description: 'Security control: force one agent to sign in again. Revokes every active session of that agent now (their existing tokens stop working) and sets them Offline. Administrator only; the agent must belong to your site; audited (who/when/target). You cannot force sign out your own account.',
|
|
1591
|
+
inputSchema: {
|
|
1592
|
+
type: 'object',
|
|
1593
|
+
properties: { userId: { type: 'number', description: 'Agent user id from agent_list' } },
|
|
1594
|
+
required: ['userId'],
|
|
1595
|
+
},
|
|
1596
|
+
},
|
|
1597
|
+
{
|
|
1598
|
+
name: 'agent_set_status',
|
|
1599
|
+
description: 'Set an agent availability status (Available, Busy, Away, Offline). Use Offline or Away to make an agent Unavailable for routing. Site manager only; the agent must belong to your site; audited with the acting admin.',
|
|
1600
|
+
inputSchema: {
|
|
1601
|
+
type: 'object',
|
|
1602
|
+
properties: {
|
|
1603
|
+
userId: { type: 'number', description: 'Agent user id from agent_list' },
|
|
1604
|
+
status: { type: 'string', enum: ['Available', 'Busy', 'Away', 'Offline'] },
|
|
1605
|
+
},
|
|
1606
|
+
required: ['userId', 'status'],
|
|
1607
|
+
},
|
|
1608
|
+
},
|
|
1609
|
+
|
|
1585
1610
|
// ── Dynamics per-team overrides (effective = team override ?? connection default) ──
|
|
1586
1611
|
{
|
|
1587
1612
|
name: 'dynamics_team_overrides_get',
|
|
@@ -2061,6 +2086,27 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
2061
2086
|
},
|
|
2062
2087
|
},
|
|
2063
2088
|
},
|
|
2089
|
+
{
|
|
2090
|
+
name: 'safety_policy_get',
|
|
2091
|
+
description: 'Get the safety controls policy: per control (emergency_self_harm, abuse_ladder, threat_detection, input_jailbreak, output_filter) whether it is on for AI bot and human agent, any overrides, the always-on floor, a warning when anything is off, and the acknowledgement text and version needed to turn a control off. Wraps GET SafetyPolicy.',
|
|
2092
|
+
inputSchema: { type: 'object', properties: {} },
|
|
2093
|
+
},
|
|
2094
|
+
{
|
|
2095
|
+
name: 'safety_policy_set',
|
|
2096
|
+
description: 'Turn a safety control on, off, or back to default. Every control is ON by default. Turning one OFF is refused unless acknowledged=true AND ackTextVersion equals the current acknowledgement version (read it from safety_policy_get and show the acknowledgement text to the account owner first). This tool never accepts the acknowledgement on anyone\'s behalf. Turning on or resetting needs no acknowledgement. Wraps PUT SafetyPolicy.',
|
|
2097
|
+
inputSchema: {
|
|
2098
|
+
type: 'object',
|
|
2099
|
+
properties: {
|
|
2100
|
+
control: { type: 'string', enum: ['emergency_self_harm', 'abuse_ladder', 'threat_detection', 'input_jailbreak', 'output_filter'] },
|
|
2101
|
+
audience: { type: 'string', enum: ['ai_bot', 'human_agent'] },
|
|
2102
|
+
featureKey: { type: 'string', description: 'Optional per-feature/channel scope (chat, voice, sms, whatsapp, email). Omit for the whole account.' },
|
|
2103
|
+
enabled: { type: ['boolean', 'null'], description: 'true = on, false = off, null = clear the override (default on)' },
|
|
2104
|
+
acknowledged: { type: 'boolean', description: 'Required true when enabled=false: the account owner accepted the acknowledgement text' },
|
|
2105
|
+
ackTextVersion: { type: 'string', description: 'Required when enabled=false: the acknowledgement version from safety_policy_get' },
|
|
2106
|
+
},
|
|
2107
|
+
required: ['control', 'audience', 'enabled'],
|
|
2108
|
+
},
|
|
2109
|
+
},
|
|
2064
2110
|
{
|
|
2065
2111
|
name: 'safety_settings_test',
|
|
2066
2112
|
description: 'Send a test safety alert to the configured recipients. Wraps POST SafetyEvents/settings/test.',
|
|
@@ -3314,6 +3360,34 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
3314
3360
|
},
|
|
3315
3361
|
|
|
3316
3362
|
|
|
3363
|
+
{
|
|
3364
|
+
name: 'magento_get_sidebar_fields',
|
|
3365
|
+
description: 'Get the Magento fields shown in the agent sidebar panel for the authenticated site (empty list = out-of-box defaults). Calls messaging GET Magento/data/sidebar-fields. Site comes from the bearer token only. Read-only.',
|
|
3366
|
+
inputSchema: { type: 'object', properties: {} },
|
|
3367
|
+
},
|
|
3368
|
+
{
|
|
3369
|
+
name: 'magento_set_sidebar_fields',
|
|
3370
|
+
description: 'Set the Magento fields shown in the agent sidebar panel for the authenticated site. Partial update: omit fields to leave the saved list untouched; an empty array clears it. Site comes from the bearer token only. Calls messaging PUT Magento/data/sidebar-fields.',
|
|
3371
|
+
inputSchema: {
|
|
3372
|
+
type: 'object',
|
|
3373
|
+
properties: {
|
|
3374
|
+
fields: {
|
|
3375
|
+
type: 'array',
|
|
3376
|
+
description: 'Sidebar fields to show, in order',
|
|
3377
|
+
items: {
|
|
3378
|
+
type: 'object',
|
|
3379
|
+
properties: {
|
|
3380
|
+
fieldName: { type: 'string', description: 'Magento field name, e.g. "email"' },
|
|
3381
|
+
entity: { type: 'string', description: 'Entity the field belongs to, e.g. "customer" or "order"' },
|
|
3382
|
+
label: { type: 'string', description: 'Optional display label' },
|
|
3383
|
+
},
|
|
3384
|
+
required: ['fieldName'],
|
|
3385
|
+
},
|
|
3386
|
+
},
|
|
3387
|
+
},
|
|
3388
|
+
},
|
|
3389
|
+
},
|
|
3390
|
+
|
|
3317
3391
|
{
|
|
3318
3392
|
name: 'business_action_list',
|
|
3319
3393
|
description: 'List the shared business actions registered on the messaging API (e.g. get_customer_pricing, create_quote): name, whether it is a write, data class, freshness window, request JSON schema and the AI skill tool names that project it. One definition is served by the Velaro catalog or a connected ERP (SAP) beneath it. Site scope comes from the caller\'s auth context. Calls GET /BusinessActions.',
|
|
@@ -3480,6 +3554,29 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
3480
3554
|
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
3481
3555
|
},
|
|
3482
3556
|
|
|
3557
|
+
{
|
|
3558
|
+
name: 'teams_phone_list_agents',
|
|
3559
|
+
description: "List the site's agents with their Microsoft Teams user Object ID mapping (agent -> Entra user), used to route inbound Teams Phone calls to the right agent. Admin only. Lives in velaro-messaging — requires VELARO_MESSAGING_API.",
|
|
3560
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
3561
|
+
},
|
|
3562
|
+
{
|
|
3563
|
+
name: 'teams_phone_set_agent',
|
|
3564
|
+
description: 'Map one Velaro agent (workspace user id) to a Microsoft Entra user Object ID (GUID) so inbound Teams Phone calls reach them. Upsert; pass "" to clear. Must be unique per site. Lives in velaro-messaging — requires VELARO_MESSAGING_API.',
|
|
3565
|
+
inputSchema: {
|
|
3566
|
+
type: 'object',
|
|
3567
|
+
properties: {
|
|
3568
|
+
agentId: { type: 'number', description: 'Velaro agent (workspace user) id from teams_phone_list_agents.' },
|
|
3569
|
+
teamsUserId: { type: 'string', description: 'Entra user Object ID (GUID). "" clears the mapping.' },
|
|
3570
|
+
},
|
|
3571
|
+
required: ['agentId', 'teamsUserId'],
|
|
3572
|
+
},
|
|
3573
|
+
},
|
|
3574
|
+
{
|
|
3575
|
+
name: 'teams_phone_delete_agent',
|
|
3576
|
+
description: "Clear one agent's Teams user mapping. Calls to that Teams user will no longer route to the agent.",
|
|
3577
|
+
inputSchema: { type: 'object', properties: { agentId: { type: 'number', description: 'Velaro agent (workspace user) id.' } }, required: ['agentId'] },
|
|
3578
|
+
},
|
|
3579
|
+
|
|
3483
3580
|
// ── Webflow (config CRUD) ──────────────────────────────────────────────────
|
|
3484
3581
|
// Lives in velaro-admin's own WebflowController.cs (this API), not velaro-messaging.
|
|
3485
3582
|
// The other 6 Webflow AI skills (webflow_list_sites, webflow_get_site,
|
|
@@ -3827,6 +3924,8 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
3827
3924
|
},
|
|
3828
3925
|
},
|
|
3829
3926
|
|
|
3927
|
+
// ── Billing agents + package builder (staff; docs/architecture/billing-agents-and-package-builder.md) ──
|
|
3928
|
+
{ name: 'package_builder_my', description: 'Customer-safe: the caller\'s own package name and what it includes. No prices or staff data.', inputSchema: { type: 'object', properties: {} } },
|
|
3830
3929
|
// ── Pricing Catalog ───────────────────────────────────────────────────────
|
|
3831
3930
|
{
|
|
3832
3931
|
name: 'pricing_catalog_list',
|
|
@@ -5809,6 +5908,19 @@ reply: ${r?.reply}`;
|
|
|
5809
5908
|
case 'agent_list':
|
|
5810
5909
|
return await rpc('agent_list', args);
|
|
5811
5910
|
|
|
5911
|
+
case 'agent_force_sign_out': {
|
|
5912
|
+
if (!Number.isInteger(args.userId) || args.userId <= 0) return 'userId is required (positive integer).';
|
|
5913
|
+
await messagingPost(`/Users/${args.userId}/ForceSignOut`, {});
|
|
5914
|
+
return `Agent ${args.userId} was signed out of every session and set to Offline. They must sign in again.`;
|
|
5915
|
+
}
|
|
5916
|
+
|
|
5917
|
+
case 'agent_set_status': {
|
|
5918
|
+
if (!Number.isInteger(args.userId) || args.userId <= 0) return 'userId is required (positive integer).';
|
|
5919
|
+
if (!['Available', 'Busy', 'Away', 'Offline'].includes(args.status)) return 'status must be Available, Busy, Away or Offline.';
|
|
5920
|
+
await messagingPost('/UserStatus/admin', { userId: args.userId, status: args.status });
|
|
5921
|
+
return `Agent ${args.userId} set to ${args.status}.`;
|
|
5922
|
+
}
|
|
5923
|
+
|
|
5812
5924
|
// ── Teams ──────────────────────────────────────────────────────────────
|
|
5813
5925
|
case 'team_list':
|
|
5814
5926
|
return await rpc('team_list', args);
|
|
@@ -6386,6 +6498,21 @@ reply: ${r?.reply}`;
|
|
|
6386
6498
|
}
|
|
6387
6499
|
return JSON.stringify(await messagingPut('/SafetyEvents/settings', next), null, 2);
|
|
6388
6500
|
}
|
|
6501
|
+
case 'safety_policy_get':
|
|
6502
|
+
return JSON.stringify(await messagingGet('/SafetyPolicy'), null, 2);
|
|
6503
|
+
case 'safety_policy_set': {
|
|
6504
|
+
if (args.enabled === false && (args.acknowledged !== true || !args.ackTextVersion)) {
|
|
6505
|
+
throw new Error('Turning a safety control off requires acknowledged=true and ackTextVersion (from safety_policy_get). This tool never accepts the acknowledgement automatically.');
|
|
6506
|
+
}
|
|
6507
|
+
const body = {
|
|
6508
|
+
control: args.control,
|
|
6509
|
+
audience: args.audience,
|
|
6510
|
+
featureKey: args.featureKey ?? null,
|
|
6511
|
+
enabled: args.enabled === undefined ? null : args.enabled,
|
|
6512
|
+
...(args.enabled === false ? { acknowledged: true, ackTextVersion: args.ackTextVersion } : {}),
|
|
6513
|
+
};
|
|
6514
|
+
return JSON.stringify(await messagingPut('/SafetyPolicy', body), null, 2);
|
|
6515
|
+
}
|
|
6389
6516
|
case 'safety_settings_test':
|
|
6390
6517
|
return JSON.stringify(await messagingPost('/SafetyEvents/settings/test'), null, 2);
|
|
6391
6518
|
case 'safety_need_help':
|
|
@@ -7577,6 +7704,21 @@ reply: ${r?.reply}`;
|
|
|
7577
7704
|
return lines.join('\n');
|
|
7578
7705
|
}
|
|
7579
7706
|
|
|
7707
|
+
case 'magento_get_sidebar_fields': {
|
|
7708
|
+
const r = await messagingRequest('GET', '/Magento/data/sidebar-fields');
|
|
7709
|
+
return JSON.stringify(r, null, 2);
|
|
7710
|
+
}
|
|
7711
|
+
|
|
7712
|
+
case 'magento_set_sidebar_fields': {
|
|
7713
|
+
const body = {};
|
|
7714
|
+
if (args.fields !== undefined) {
|
|
7715
|
+
if (!Array.isArray(args.fields)) return 'fields must be an array.';
|
|
7716
|
+
body.fields = args.fields;
|
|
7717
|
+
}
|
|
7718
|
+
const r = await messagingRequest('PUT', '/Magento/data/sidebar-fields', body);
|
|
7719
|
+
return JSON.stringify(r, null, 2);
|
|
7720
|
+
}
|
|
7721
|
+
|
|
7580
7722
|
case 'business_action_list': {
|
|
7581
7723
|
const r = await messagingRequest('GET', '/BusinessActions');
|
|
7582
7724
|
return JSON.stringify(r, null, 2);
|
|
@@ -7730,6 +7872,20 @@ reply: ${r?.reply}`;
|
|
|
7730
7872
|
return lines.join(String.fromCharCode(10));
|
|
7731
7873
|
}
|
|
7732
7874
|
|
|
7875
|
+
case 'teams_phone_list_agents': {
|
|
7876
|
+
const agents = await messagingGet('/TeamsPhone/Agents');
|
|
7877
|
+
if (!Array.isArray(agents) || agents.length === 0) return 'No agents found.';
|
|
7878
|
+
return agents.map(a => `${a.id} ${`${a.firstName ?? ''} ${a.lastName ?? ''}`.trim()} ${a.email ?? ''} ${a.teamsUserId || '(unmapped)'}`).join(String.fromCharCode(10));
|
|
7879
|
+
}
|
|
7880
|
+
case 'teams_phone_set_agent': {
|
|
7881
|
+
const r = await messagingPut(`/TeamsPhone/Agents/${encodeURIComponent(args.agentId)}`, { teamsUserId: args.teamsUserId });
|
|
7882
|
+
return r?.configured ? `Agent ${args.agentId} mapped to Teams user ${r.teamsUserId}.` : `Agent ${args.agentId} mapping cleared.`;
|
|
7883
|
+
}
|
|
7884
|
+
case 'teams_phone_delete_agent': {
|
|
7885
|
+
await messagingDel(`/TeamsPhone/Agents/${encodeURIComponent(args.agentId)}`);
|
|
7886
|
+
return `Agent ${args.agentId} mapping cleared.`;
|
|
7887
|
+
}
|
|
7888
|
+
|
|
7733
7889
|
// ── Shopify write policy (velaro-messaging /api/Shopify/WritePolicy) ───────
|
|
7734
7890
|
case 'shopify_get_write_policy': {
|
|
7735
7891
|
return JSON.stringify(await messagingGet('/Shopify/WritePolicy'), null, 2);
|
|
@@ -8154,6 +8310,9 @@ ${JSON.stringify(result, null, 2)}`;
|
|
|
8154
8310
|
return lines.join('\n');
|
|
8155
8311
|
}
|
|
8156
8312
|
|
|
8313
|
+
// ── Billing agents + package builder ──────────────────────────────────────
|
|
8314
|
+
case 'package_builder_my': return JSON.stringify(await api('GET', '/PackageBuilder/my'), null, 2);
|
|
8315
|
+
|
|
8157
8316
|
// ── Pricing Catalog ───────────────────────────────────────────────────────
|
|
8158
8317
|
case 'pricing_catalog_list': {
|
|
8159
8318
|
const pkgs = await api('GET', '/Pricing/catalog');
|
package/tool-annotations.js
CHANGED
|
@@ -26,7 +26,7 @@ const MUTATING = new Set([
|
|
|
26
26
|
'pickup_update_config', 'payment_recovery_update_config', 'recruiting_sync_jobs',
|
|
27
27
|
'ai_config_set_reply_format', 'ai_model_set_site_thinking', 'ai_model_set_site_pin',
|
|
28
28
|
'entitlement_reconcile', 'entitlement_sync_stripe', 'entitlement_backfill_subscriptions',
|
|
29
|
-
'calendly_configure', 'acuity_configure', 'ms_bookings_configure',
|
|
29
|
+
'calendly_configure', 'acuity_configure', 'ms_bookings_configure', 'magento_set_sidebar_fields',
|
|
30
30
|
'zoom_phone_set_config',
|
|
31
31
|
]);
|
|
32
32
|
|