@velaro/mcp-server 2.0.9 → 2.0.11
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velaro/mcp-server",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.11",
|
|
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": {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// velaro callpresence: call-presence policy (chat and call routing while an agent is on a phone call).
|
|
2
|
+
// Site comes from the credential only. Parity module (CLI group -> MCP tools).
|
|
3
|
+
|
|
4
|
+
const enc = encodeURIComponent;
|
|
5
|
+
const pid = (v, n = 'id') => { const x = Number(v); if (!Number.isInteger(x) || x <= 0) throw new Error(n + ' must be a positive integer'); return x; };
|
|
6
|
+
const need = (a, ...ks) => { for (const k of ks) if (a[k] === undefined || a[k] === null || a[k] === '') throw new Error(k + ' is required'); };
|
|
7
|
+
|
|
8
|
+
const SCOPE = { type: 'string', enum: ['site', 'group', 'agent'], description: 'Level: site default, a routing group (id = team id) or an agent (id = agent id)' };
|
|
9
|
+
|
|
10
|
+
export const tools = [
|
|
11
|
+
{
|
|
12
|
+
name: 'callpresence_get',
|
|
13
|
+
description: 'Get the call-presence policy: site default, routing-group and agent overrides, whether agents may override, and the allowed values. Controls chat/call routing while an agent is on a phone call and what happens when the call ends.',
|
|
14
|
+
inputSchema: { type: 'object', properties: {} },
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: 'callpresence_get_effective',
|
|
18
|
+
description: 'Get the resolved call-presence policy for one agent, with where each setting comes from (Agent override, Group override, Inherited from site, Platform default).',
|
|
19
|
+
inputSchema: { type: 'object', properties: { agentId: { type: 'integer', description: 'Agent (workspace user) id' }, teamId: { type: 'integer', description: 'Routing group to resolve against, for agents in several groups' } }, required: ['agentId'] },
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'callpresence_status',
|
|
23
|
+
description: 'List agents who are on a live phone call right now (Ringing, Active or OnHold call records), with call counts and whether a second call is live.',
|
|
24
|
+
inputSchema: { type: 'object', properties: {} },
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'callpresence_set',
|
|
28
|
+
description: 'Set the call-presence policy at one level. Omit a setting to inherit it. whileOnCall: NoChats | TakeChats | FinishThenOffline. afterCall: ReturnAutomatically | AskAgent | StayOffline. callsWhileBusy: NoCallsWhileBusy | RingEvenWhenBusy. allowAgentOverrides applies to the site level only.',
|
|
29
|
+
inputSchema: {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
scope: SCOPE,
|
|
33
|
+
id: { type: 'integer', description: 'Team id (group) or agent id (agent). Omit for site.' },
|
|
34
|
+
whileOnCall: { type: 'string', enum: ['NoChats', 'TakeChats', 'FinishThenOffline'] },
|
|
35
|
+
afterCall: { type: 'string', enum: ['ReturnAutomatically', 'AskAgent', 'StayOffline'] },
|
|
36
|
+
callsWhileBusy: { type: 'string', enum: ['NoCallsWhileBusy', 'RingEvenWhenBusy'] },
|
|
37
|
+
allowAgentOverrides: { type: 'boolean', description: 'Site level only: may agents set their own override' },
|
|
38
|
+
},
|
|
39
|
+
required: ['scope'],
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'callpresence_clear',
|
|
44
|
+
description: 'Remove the call-presence policy at one level so it inherits from the level above again.',
|
|
45
|
+
inputSchema: { type: 'object', properties: { scope: SCOPE, id: { type: 'integer', description: 'Team id (group) or agent id (agent). Omit for site.' } }, required: ['scope'] },
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const target = (a) => {
|
|
50
|
+
need(a, 'scope');
|
|
51
|
+
if (!['site', 'group', 'agent'].includes(a.scope)) throw new Error('scope must be site, group or agent');
|
|
52
|
+
return a.scope === 'site' ? 'site/0' : `${a.scope}/${pid(a.id, 'id')}`;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const handlers = {
|
|
56
|
+
callpresence_get: async (a, ctx) => ctx.messagingGet('/CallPresencePolicy'),
|
|
57
|
+
callpresence_get_effective: async (a, ctx) => {
|
|
58
|
+
need(a, 'agentId');
|
|
59
|
+
const q = a.teamId ? `?teamId=${pid(a.teamId, 'teamId')}` : '';
|
|
60
|
+
return ctx.messagingGet(`/CallPresencePolicy/effective/${pid(a.agentId, 'agentId')}${q}`);
|
|
61
|
+
},
|
|
62
|
+
callpresence_status: async (a, ctx) => ctx.messagingGet('/CallPresencePolicy/presence'),
|
|
63
|
+
callpresence_set: async (a, ctx) => {
|
|
64
|
+
const body = { whileOnCall: a.whileOnCall ?? null, afterCall: a.afterCall ?? null, callsWhileBusy: a.callsWhileBusy ?? null };
|
|
65
|
+
if (a.scope === 'site' && a.allowAgentOverrides !== undefined) body.allowAgentOverrides = a.allowAgentOverrides;
|
|
66
|
+
return ctx.messagingRequest('PUT', '/CallPresencePolicy/' + target(a), body);
|
|
67
|
+
},
|
|
68
|
+
callpresence_clear: async (a, ctx) => ctx.messagingRequest('DELETE', '/CallPresencePolicy/' + target(a)),
|
|
69
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// velaro product-match: the per-site Product Match matrix. Site scope comes from the credential only, never from arguments.
|
|
2
|
+
// Parity module (CLI group `product-match` -> MCP tools). Needs the Product Match package (EnableProductMatch).
|
|
3
|
+
|
|
4
|
+
const enc = encodeURIComponent;
|
|
5
|
+
const need = (a, ...ks) => { for (const k of ks) if (a[k] === undefined || a[k] === null || a[k] === '') throw new Error(k + ' is required'); };
|
|
6
|
+
const pid = (v, n = 'id') => { const x = Number(v); if (!Number.isInteger(x) || x <= 0) throw new Error(n + ' must be a positive integer'); return x; };
|
|
7
|
+
|
|
8
|
+
export const tools = [
|
|
9
|
+
{
|
|
10
|
+
name: 'product_match_lookup',
|
|
11
|
+
description: 'Look up which of the site\'s OWN catalog products matches a part number, SKU, competitor model or discontinued part. Deterministic (no model decides it): only approved matrix rows, only SKUs that exist in the site catalog, never a deny-listed brand. Returns status (matched, own_product, no_match, unapproved, loop, not_in_catalog), the recommendations and whether to hand off to a person. Calls POST /BusinessActions/match_product/Execute.',
|
|
12
|
+
inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'The part number, SKU or model as the customer wrote it' } }, required: ['query'] },
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'product_match_list',
|
|
16
|
+
description: 'List the site\'s Product Match matrix rows (source, target SKU, match type, approved). Calls GET /ProductMatch/Entries.',
|
|
17
|
+
inputSchema: { type: 'object', properties: { q: { type: 'string' }, page: { type: 'number' } } },
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'product_match_import',
|
|
21
|
+
description: 'Import a cross-reference matrix from CSV text (header row with a source column such as "Competitor SKU" and a target column such as "Our SKU"; optional "Match Type" exact|equivalent|supersedes, "Approved" yes/no, "Notes"). Rows are NOT approved unless the Approved column says yes. Upserts by source and target. Calls POST /ProductMatch/ImportFile.',
|
|
22
|
+
inputSchema: { type: 'object', properties: { csv: { type: 'string', description: 'The CSV file content' } }, required: ['csv'] },
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'product_match_approve',
|
|
26
|
+
description: 'Approve or revoke one matrix row. Only approved rows are ever recommended. Calls PUT /ProductMatch/Entries/{id}/Approve.',
|
|
27
|
+
inputSchema: { type: 'object', properties: { id: { type: 'number' }, approved: { type: 'boolean', description: 'default true' } }, required: ['id'] },
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'product_match_remove',
|
|
31
|
+
description: 'Delete one matrix row. Calls DELETE /ProductMatch/Entries/{id}.',
|
|
32
|
+
inputSchema: { type: 'object', properties: { id: { type: 'number' } }, required: ['id'] },
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'product_match_deny_terms',
|
|
36
|
+
description: 'Read, or replace (when terms is given), the brands and competitors the bot must never name in a Product Match reply. Calls GET or PUT /ProductMatch/DenyTerms.',
|
|
37
|
+
inputSchema: { type: 'object', properties: { terms: { type: 'array', items: { type: 'string' } } } },
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
export const handlers = {
|
|
42
|
+
product_match_lookup: async (a, ctx) => {
|
|
43
|
+
need(a, 'query');
|
|
44
|
+
return ctx.messagingPost('/BusinessActions/match_product/Execute', { query: String(a.query) });
|
|
45
|
+
},
|
|
46
|
+
product_match_list: async (a, ctx) => {
|
|
47
|
+
const p = new URLSearchParams();
|
|
48
|
+
if (a.q) p.set('q', String(a.q));
|
|
49
|
+
p.set('page', String(a.page ?? 1));
|
|
50
|
+
return ctx.messagingGet('/ProductMatch/Entries?' + p.toString());
|
|
51
|
+
},
|
|
52
|
+
product_match_import: async (a, ctx) => {
|
|
53
|
+
need(a, 'csv');
|
|
54
|
+
return ctx.messagingPost('/ProductMatch/ImportFile', { fileName: 'matrix.csv', contentBase64: Buffer.from(String(a.csv), 'utf8').toString('base64') });
|
|
55
|
+
},
|
|
56
|
+
product_match_approve: async (a, ctx) => {
|
|
57
|
+
return ctx.messagingPut('/ProductMatch/Entries/' + pid(a.id) + '/Approve', { approved: a.approved !== false });
|
|
58
|
+
},
|
|
59
|
+
product_match_remove: async (a, ctx) => {
|
|
60
|
+
return ctx.messagingDel('/ProductMatch/Entries/' + pid(a.id));
|
|
61
|
+
},
|
|
62
|
+
product_match_deny_terms: async (a, ctx) => {
|
|
63
|
+
if (Array.isArray(a.terms)) return ctx.messagingPut('/ProductMatch/DenyTerms', { terms: a.terms.map(String) });
|
|
64
|
+
return ctx.messagingGet('/ProductMatch/DenyTerms');
|
|
65
|
+
},
|
|
66
|
+
};
|
package/tool-annotations.js
CHANGED
|
@@ -24,7 +24,7 @@ const MUTATING = new Set([
|
|
|
24
24
|
'monday_set_field_mapping', 'teams_push_settings_update', 'teams_channel_config_update',
|
|
25
25
|
'routing_team_update_config', 'pickup_update_config', 'payment_recovery_update_config',
|
|
26
26
|
'recruiting_sync_jobs', 'ai_config_set_reply_format', 'magento_set_sidebar_fields',
|
|
27
|
-
'zoom_phone_set_config',
|
|
27
|
+
'zoom_phone_set_config', 'callpresence_set', 'callpresence_clear',
|
|
28
28
|
'billing_insights_set_preferences', 'billing_insights_dismiss_recommendation',
|
|
29
29
|
'site_sale_create', 'site_sale_update', 'site_sale_end',
|
|
30
30
|
]);
|