@velaro/mcp-server 0.6.92 → 0.6.93
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 +2 -2
- package/server.js +148 -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.93",
|
|
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": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"node": ">=18.0.0"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
13
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
14
14
|
"qs": "^6.16.0"
|
|
15
15
|
},
|
|
16
16
|
"overrides": {
|
package/server.js
CHANGED
|
@@ -1048,6 +1048,7 @@ Key node shapes:
|
|
|
1048
1048
|
propName:"myAnswerVar" } // variable that stores the result as JSON array string
|
|
1049
1049
|
• condition: { type:"action", actionType:"condition", conditionOptions:[...] }
|
|
1050
1050
|
• transferToAI: { type:"action", actionType:"transferToAI", aiConfigId:N }
|
|
1051
|
+
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.
|
|
1051
1052
|
|
|
1052
1053
|
For multiSelect dynamic options: the variable named in dynamicOptionsVariable must contain a JSON array like [{"label":"Red","value":"red"},{"label":"Blue","value":"blue"}]. Populate it via an HTTP Request node before the ask node.`,
|
|
1053
1054
|
inputSchema: {
|
|
@@ -1061,6 +1062,20 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
1061
1062
|
},
|
|
1062
1063
|
},
|
|
1063
1064
|
|
|
1065
|
+
{
|
|
1066
|
+
name: 'ai_followups_site_get',
|
|
1067
|
+
description: "Read this account's default for AI follow-up suggestions (the AI Chatbot node's \"AI mode\": after each web-chat bot reply the bot offers 2-4 short tappable follow-up replies). A node's own suggestFollowUps setting wins over this default; platform default is off.",
|
|
1068
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
1069
|
+
},
|
|
1070
|
+
{
|
|
1071
|
+
name: 'ai_followups_site_set',
|
|
1072
|
+
description: "Set this account's default for AI follow-up suggestions. enabled=true/false, or omit/null to clear (platform default: off). Per-node settings (workflow_update_node: suggestFollowUps) override this. Returns the value read back from the server.",
|
|
1073
|
+
inputSchema: {
|
|
1074
|
+
type: 'object',
|
|
1075
|
+
properties: { enabled: { type: ['boolean', 'null'], description: 'true = on, false = off, null/omitted = clear' } },
|
|
1076
|
+
required: [],
|
|
1077
|
+
},
|
|
1078
|
+
},
|
|
1064
1079
|
// ── Surveys ──────────────────────────────────────────────────────────────
|
|
1065
1080
|
{
|
|
1066
1081
|
name: 'survey_list',
|
|
@@ -1594,10 +1609,28 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
1594
1609
|
},
|
|
1595
1610
|
buttonLabel: { type: 'string', description: 'Optional action button label' },
|
|
1596
1611
|
buttonUrl: { type: 'string', description: 'Optional action button URL (required if buttonLabel is set)' },
|
|
1612
|
+
mentions: { type: 'array', description: 'People to @mention (real Teams notification). Velaro staff only. Uses the ops Teams sender instead of a webhook.', items: { type: 'object', properties: { user: { type: 'string', description: 'Entra object id or UPN, e.g. andrea@velaro.com' }, name: { type: 'string', description: 'Display name shown in the @mention' } }, required: ['user'] } },
|
|
1613
|
+
destination: { type: 'string', description: 'Named channel in the DevOps team instead of General: prs, workflows, deploys, alerts, qa, general. Velaro staff only; uses the ops Teams sender instead of a webhook.' },
|
|
1597
1614
|
},
|
|
1598
1615
|
required: ['title'],
|
|
1599
1616
|
},
|
|
1600
1617
|
},
|
|
1618
|
+
{
|
|
1619
|
+
name: 'teams_send_direct',
|
|
1620
|
+
description: 'Send a 1:1 Teams message (Adaptive Card) directly to any user in the Velaro tenant by UPN/email or Entra object id. Velaro staff only. Graph chat first, Velaro Bot proactive fallback.',
|
|
1621
|
+
inputSchema: {
|
|
1622
|
+
type: 'object',
|
|
1623
|
+
properties: {
|
|
1624
|
+
user: { type: 'string', description: 'UPN/email (alex@velaro.com) or Entra object id' },
|
|
1625
|
+
title: { type: 'string', description: 'Card title' },
|
|
1626
|
+
message: { type: 'string', description: 'Message text' },
|
|
1627
|
+
fields: { type: 'array', description: 'Optional fact rows', items: { type: 'object', properties: { label: { type: 'string' }, value: { type: 'string' } }, required: ['label', 'value'] } },
|
|
1628
|
+
buttonLabel: { type: 'string', description: 'Optional button label' },
|
|
1629
|
+
buttonUrl: { type: 'string', description: 'Optional button URL' },
|
|
1630
|
+
},
|
|
1631
|
+
required: ['user', 'title'],
|
|
1632
|
+
},
|
|
1633
|
+
},
|
|
1601
1634
|
|
|
1602
1635
|
// ── Slack ─────────────────────────────────────────────────────────────────
|
|
1603
1636
|
{
|
|
@@ -3057,7 +3090,7 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
3057
3090
|
inputSchema: {
|
|
3058
3091
|
type: 'object',
|
|
3059
3092
|
properties: {
|
|
3060
|
-
report: { type: 'string', enum: ['program_breakdown', 'agent_scorecard', 'qa_coverage', 'coaching_queue', 'sentiment_breakdown', 'topic_radar', 'weekly_brief', 'weekly_brief_send_test'] },
|
|
3093
|
+
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'] },
|
|
3061
3094
|
from: { type: 'string', description: 'yyyy-MM-dd start (default: 30 days ago).' },
|
|
3062
3095
|
to: { type: 'string', description: 'yyyy-MM-dd end, inclusive (default: today).' },
|
|
3063
3096
|
groupBy: { type: 'string', description: 'program_breakdown: website|team|platform|device|entrypage. sentiment_breakdown: website|team|agent|theme.' },
|
|
@@ -3067,6 +3100,14 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
3067
3100
|
perAgent: { type: 'number', description: 'coaching_queue: chats listed per agent (default 5).' },
|
|
3068
3101
|
limit: { type: 'number', description: 'topic_radar: max topics (default 25).' },
|
|
3069
3102
|
days: { type: 'number', description: 'weekly_brief: days to cover (default 7).' },
|
|
3103
|
+
windowDays: { type: 'number', description: 'repeat_contact: days a contact has to come back to count as a repeat (1-30, default 7).' },
|
|
3104
|
+
weeks: { type: 'number', description: 'demand_coverage: whole local weeks of history (1-12, default 6). from/to are IGNORED by demand_coverage.' },
|
|
3105
|
+
handleMinutes: { type: 'number', description: 'demand_coverage: assumed minutes per chat (1-120, default 10).' },
|
|
3106
|
+
maxConcurrent: { type: 'number', description: 'demand_coverage: assumed chats an agent handles at once (1-10, default 3).' },
|
|
3107
|
+
timeZone: { type: 'string', description: 'demand_coverage: IANA time zone (default America/Los_Angeles).' },
|
|
3108
|
+
lowScore: { type: 'number', description: 'bot_containment: QA score below which a handed-off chat counts as regret (1-100, default 60).' },
|
|
3109
|
+
includeDemo: { type: 'boolean', description: 'true = show only the seeded sample (demo) data. Default false.' },
|
|
3110
|
+
promiseId: { type: 'string', description: 'promise_dismiss: the promise id to dismiss (managers only).' },
|
|
3070
3111
|
},
|
|
3071
3112
|
required: ['report'],
|
|
3072
3113
|
},
|
|
@@ -3750,6 +3791,15 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
3750
3791
|
required: [],
|
|
3751
3792
|
},
|
|
3752
3793
|
},
|
|
3794
|
+
{
|
|
3795
|
+
name: 'ai_federation',
|
|
3796
|
+
description: 'SuperAdmin: Anthropic Workload Identity Federation for the AI gateway. action=status shows enabled, circuit breaker state, last success/failure reason, federated vs API-key fallback counts and token expiry. action=test does a real token exchange plus a 1-token Haiku message and reports which path (federated, apikey, apikey-fallback) served it. action=reset_breaker closes the breaker so the next call retries federation.',
|
|
3797
|
+
inputSchema: {
|
|
3798
|
+
type: 'object',
|
|
3799
|
+
properties: { action: { type: 'string', enum: ['status', 'test', 'reset_breaker'], description: 'Default status.' } },
|
|
3800
|
+
required: [],
|
|
3801
|
+
},
|
|
3802
|
+
},
|
|
3753
3803
|
{
|
|
3754
3804
|
name: 'status_incident_list',
|
|
3755
3805
|
description: 'Velaro staff only (SuperAdmin). Lists public status page incidents, including component overrides (IncidentType "Override").',
|
|
@@ -4998,6 +5048,7 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
4998
5048
|
properties: {
|
|
4999
5049
|
publicApplyEnabled: { type: 'boolean' },
|
|
5000
5050
|
autoCreateCaseTypeId: { type: 'number', description: 'Case type id; 0 clears the auto-create link' },
|
|
5051
|
+
defaultListingDays: { type: 'number', description: '1-365: how many days a new listing stays live when its feed gives no expiry. Requires the Job Board lifecycle package.' },
|
|
5001
5052
|
},
|
|
5002
5053
|
required: [],
|
|
5003
5054
|
},
|
|
@@ -5103,6 +5154,29 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
5103
5154
|
required: ['sourceId', 'title'],
|
|
5104
5155
|
},
|
|
5105
5156
|
},
|
|
5157
|
+
// -- Job Board listing lifecycle (package "job-board-lifecycle", default OFF: 403 for a site without it) --
|
|
5158
|
+
{
|
|
5159
|
+
name: 'jobboard_lifecycle_status',
|
|
5160
|
+
description: 'Does this site have the Job Board listing lifecycle package (close/renew, expiry, JSON-LD listing pages), and what is its default listing duration? Returns { entitled, defaultListingDays }.',
|
|
5161
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
5162
|
+
},
|
|
5163
|
+
{
|
|
5164
|
+
name: 'jobboard_close_listing',
|
|
5165
|
+
description: 'Close a job listing: it stops appearing in search and the public board, the public listing page answers 410, and applying to it answers 410. Idempotent. Requires the Job Board lifecycle package (403 otherwise); 404 for an id that is not on this site.',
|
|
5166
|
+
inputSchema: { type: 'object', properties: { listingId: { type: 'number' } }, required: ['listingId'] },
|
|
5167
|
+
},
|
|
5168
|
+
{
|
|
5169
|
+
name: 'jobboard_renew_listing',
|
|
5170
|
+
description: 'Renew a job listing: extends its expiry by `days` (default: the site\'s default listing days) from the later of its current expiry and now, increments its renewal count and republishes it if it was closed or expired. Requires the Job Board lifecycle package (403 otherwise).',
|
|
5171
|
+
inputSchema: {
|
|
5172
|
+
type: 'object',
|
|
5173
|
+
properties: {
|
|
5174
|
+
listingId: { type: 'number' },
|
|
5175
|
+
days: { type: 'number', description: '1-365; omit for the site default' },
|
|
5176
|
+
},
|
|
5177
|
+
required: ['listingId'],
|
|
5178
|
+
},
|
|
5179
|
+
},
|
|
5106
5180
|
{
|
|
5107
5181
|
name: 'jobboard_move_application_stage',
|
|
5108
5182
|
description: 'Move a candidate application to a new HR/agency-side pipeline stage on the applicant Kanban board (Applied, Screened, Interview, Offer, Hired, Rejected).',
|
|
@@ -5994,6 +6068,17 @@ async function handleTool(name, args) {
|
|
|
5994
6068
|
// [Authorize] does not accept vel_live_* service keys (only a handful of controllers opt
|
|
5995
6069
|
// into that manually) — these tools need VELARO_JWT, same requirement as the existing
|
|
5996
6070
|
// notifications_get/ai_config_staff_get tools they're modeled on.
|
|
6071
|
+
case 'ai_followups_site_get': {
|
|
6072
|
+
const r = await messagingGet('/SiteSettings/AiFollowUps');
|
|
6073
|
+
return JSON.stringify({ enabled: r?.enabled ?? null }, null, 2);
|
|
6074
|
+
}
|
|
6075
|
+
|
|
6076
|
+
case 'ai_followups_site_set': {
|
|
6077
|
+
await messagingPut('/SiteSettings/AiFollowUps', { enabled: typeof args.enabled === 'boolean' ? args.enabled : null });
|
|
6078
|
+
const r = await messagingGet('/SiteSettings/AiFollowUps');
|
|
6079
|
+
return JSON.stringify({ enabled: r?.enabled ?? null }, null, 2);
|
|
6080
|
+
}
|
|
6081
|
+
|
|
5997
6082
|
case 'survey_list': {
|
|
5998
6083
|
const surveys = (await messagingGet('/Surveys/list')) ?? [];
|
|
5999
6084
|
if (!surveys.length) return 'No surveys found.';
|
|
@@ -6492,7 +6577,26 @@ async function handleTool(name, args) {
|
|
|
6492
6577
|
return await api('PUT', '/TeamsBot/ChannelConfig', body);
|
|
6493
6578
|
}
|
|
6494
6579
|
|
|
6580
|
+
case 'teams_send_direct': {
|
|
6581
|
+
const r = await api('POST', '/TeamsMessaging/Direct', {
|
|
6582
|
+
user: args.user, title: args.title, message: args.message || '',
|
|
6583
|
+
facts: (args.fields || []).map(f => ({ label: f.label, value: f.value })),
|
|
6584
|
+
actionUrl: args.buttonUrl, actionLabel: args.buttonLabel,
|
|
6585
|
+
});
|
|
6586
|
+
return r?.sent ? `Direct message sent to ${args.user} via ${r.path}.` : `Send failed: ${r?.error || 'unknown error'} ${(r?.warnings || []).join('; ')}`;
|
|
6587
|
+
}
|
|
6588
|
+
|
|
6495
6589
|
case 'teams_notify_card': {
|
|
6590
|
+
if ((args.mentions && args.mentions.length) || args.destination) {
|
|
6591
|
+
const r = await api('POST', '/TeamsMessaging/Card', {
|
|
6592
|
+
title: args.title,
|
|
6593
|
+
facts: (args.fields || []).map(f => ({ label: f.label, value: f.value })),
|
|
6594
|
+
actionUrl: args.buttonUrl, actionLabel: args.buttonLabel,
|
|
6595
|
+
destination: args.destination,
|
|
6596
|
+
mentions: (args.mentions || []).map(m => ({ user: m.user, name: m.name })),
|
|
6597
|
+
});
|
|
6598
|
+
return r?.sent ? `Card sent via ${r.path}${r.warnings?.length ? ' (' + r.warnings.join('; ') + ')' : ''}.` : `Send failed: ${r?.error || 'unknown error'}`;
|
|
6599
|
+
}
|
|
6496
6600
|
const webhooks = await api('GET', '/TeamsNotification');
|
|
6497
6601
|
if (!Array.isArray(webhooks) || !webhooks.length)
|
|
6498
6602
|
return 'No Teams webhooks configured. Go to Integrations → Microsoft Teams to add one, or call velaro teams create <name> <webhookUrl> via CLI.';
|
|
@@ -8485,12 +8589,18 @@ async function handleTool(name, args) {
|
|
|
8485
8589
|
program_breakdown: 'program-breakdown', agent_scorecard: 'agent-scorecard', qa_coverage: 'qa-coverage',
|
|
8486
8590
|
coaching_queue: 'coaching-queue', sentiment_breakdown: 'sentiment-breakdown', topic_radar: 'topic-radar',
|
|
8487
8591
|
weekly_brief: 'weekly-brief', weekly_brief_send_test: 'weekly-brief/send-test',
|
|
8592
|
+
repeat_contact: 'repeat-contact', demand_coverage: 'demand-coverage', bot_containment: 'bot-containment',
|
|
8593
|
+
effort_index: 'effort-index', promise_ledger: 'promise-ledger',
|
|
8488
8594
|
};
|
|
8595
|
+
if (args.report === 'promise_dismiss') {
|
|
8596
|
+
if (!args.promiseId) throw new Error('promiseId is required for promise_dismiss');
|
|
8597
|
+
return JSON.stringify(await messagingPost('/api/enterprise-reports/promise-ledger/' + encodeURIComponent(String(args.promiseId)) + '/dismiss', {}), null, 2);
|
|
8598
|
+
}
|
|
8489
8599
|
const seg = ER_PATHS[args.report];
|
|
8490
8600
|
if (!seg) throw new Error('report must be one of: ' + Object.keys(ER_PATHS).join(', '));
|
|
8491
8601
|
if (args.report === 'weekly_brief_send_test') return JSON.stringify(await messagingPost('/api/enterprise-reports/' + seg, {}), null, 2);
|
|
8492
8602
|
const qs = new URLSearchParams();
|
|
8493
|
-
for (const k of ['from', 'to', 'groupBy', 'deploymentId', 'teamId', 'threshold', 'perAgent', 'limit', 'days']) {
|
|
8603
|
+
for (const k of ['from', 'to', 'groupBy', 'deploymentId', 'teamId', 'threshold', 'perAgent', 'limit', 'days', 'windowDays', 'weeks', 'handleMinutes', 'maxConcurrent', 'timeZone', 'lowScore', 'includeDemo']) {
|
|
8494
8604
|
if (args[k] != null && args[k] !== '') qs.set(k, String(args[k]));
|
|
8495
8605
|
}
|
|
8496
8606
|
const q = qs.toString();
|
|
@@ -8908,6 +9018,13 @@ async function handleTool(name, args) {
|
|
|
8908
9018
|
return JSON.stringify(data, null, 2);
|
|
8909
9019
|
}
|
|
8910
9020
|
|
|
9021
|
+
case 'ai_federation': {
|
|
9022
|
+
const action = args.action || 'status';
|
|
9023
|
+
if (action === 'test') return JSON.stringify(await api('POST', '/AiFederation/test', {}), null, 2);
|
|
9024
|
+
if (action === 'reset_breaker') return JSON.stringify(await api('POST', '/AiFederation/reset-breaker', {}), null, 2);
|
|
9025
|
+
return JSON.stringify(await api('GET', '/AiFederation/status'), null, 2);
|
|
9026
|
+
}
|
|
9027
|
+
|
|
8911
9028
|
case 'status_incident_list': {
|
|
8912
9029
|
const rows = await messagingRequest('GET', `/superadmin/status-incidents?filter=${encodeURIComponent(args.filter || 'active')}`);
|
|
8913
9030
|
return JSON.stringify(rows, null, 2);
|
|
@@ -10330,7 +10447,12 @@ async function handleTool(name, args) {
|
|
|
10330
10447
|
if (!Number.isInteger(n) || n < 0) throw new Error('autoCreateCaseTypeId must be an integer >= 0 (0 clears).');
|
|
10331
10448
|
body.autoCreateCaseTypeId = n;
|
|
10332
10449
|
}
|
|
10333
|
-
if (
|
|
10450
|
+
if (args.defaultListingDays !== undefined) {
|
|
10451
|
+
const d = Number(args.defaultListingDays);
|
|
10452
|
+
if (!Number.isInteger(d) || d < 1 || d > 365) throw new Error('defaultListingDays must be an integer from 1 to 365.');
|
|
10453
|
+
body.defaultListingDays = d;
|
|
10454
|
+
}
|
|
10455
|
+
if (!Object.keys(body).length) throw new Error('Specify publicApplyEnabled, autoCreateCaseTypeId and/or defaultListingDays.');
|
|
10334
10456
|
const r = await messagingPut('/Recruiting/ApplySettings', body);
|
|
10335
10457
|
return JSON.stringify(r, null, 2);
|
|
10336
10458
|
}
|
|
@@ -10367,6 +10489,29 @@ async function handleTool(name, args) {
|
|
|
10367
10489
|
}, null, 2);
|
|
10368
10490
|
}
|
|
10369
10491
|
|
|
10492
|
+
case 'jobboard_lifecycle_status': {
|
|
10493
|
+
const r = await messagingGet('/Recruiting/Lifecycle');
|
|
10494
|
+
return JSON.stringify(r, null, 2);
|
|
10495
|
+
}
|
|
10496
|
+
case 'jobboard_close_listing': {
|
|
10497
|
+
const id = Number(args.listingId);
|
|
10498
|
+
if (!Number.isInteger(id) || id <= 0) throw new Error('listingId must be a positive integer.');
|
|
10499
|
+
const r = await messagingPost(`/Recruiting/Jobs/${id}/close`, {});
|
|
10500
|
+
return JSON.stringify(r, null, 2);
|
|
10501
|
+
}
|
|
10502
|
+
case 'jobboard_renew_listing': {
|
|
10503
|
+
const id = Number(args.listingId);
|
|
10504
|
+
if (!Number.isInteger(id) || id <= 0) throw new Error('listingId must be a positive integer.');
|
|
10505
|
+
const body = {};
|
|
10506
|
+
if (args.days !== undefined) {
|
|
10507
|
+
const d = Number(args.days);
|
|
10508
|
+
if (!Number.isInteger(d) || d < 1 || d > 365) throw new Error('days must be an integer from 1 to 365.');
|
|
10509
|
+
body.days = d;
|
|
10510
|
+
}
|
|
10511
|
+
const r = await messagingPost(`/Recruiting/Jobs/${id}/renew`, body);
|
|
10512
|
+
return JSON.stringify(r, null, 2);
|
|
10513
|
+
}
|
|
10514
|
+
|
|
10370
10515
|
case 'jobboard_move_application_stage': {
|
|
10371
10516
|
const app = await messagingPut(`/Recruiting/Applications/${args.applicationId}/Stage`, { stage: args.stage });
|
|
10372
10517
|
return JSON.stringify(app, null, 2);
|