@velaro/mcp-server 2.0.12 → 2.0.14
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/README.md +3 -1
- package/package.json +1 -1
- package/server.js +64 -2
package/README.md
CHANGED
|
@@ -158,7 +158,9 @@ This works with any MCP client that supports HTTP/SSE transport — including Cl
|
|
|
158
158
|
| Tool | What It Does |
|
|
159
159
|
|------|-------------|
|
|
160
160
|
| `signature_policy_get` | Read the company email signature policy: mode, company signature, legal disclaimer, per-team overrides (admin only) |
|
|
161
|
-
| `signature_policy_set` | Change the signature policy (locked, company-default or personal-only), the company signature, the optional legal disclaimer, company-wide or for one team (admin only) |
|
|
161
|
+
| `signature_policy_set` | Change the signature policy (locked, company-default or personal-only), the company signature, the optional legal disclaimer, the name line (real or display name, agent and/or team name), the team and agent override switches, company-wide or for one team (admin only) |
|
|
162
|
+
| `signature_policy_history` | List saved versions of the signature policy, newest first (admin only) |
|
|
163
|
+
| `signature_policy_rollback` | Restore a saved version of the signature policy as a new version (site administrators only) |
|
|
162
164
|
|
|
163
165
|
### Live Operations
|
|
164
166
|
| Tool | What It Does |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velaro/mcp-server",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.14",
|
|
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
|
@@ -439,9 +439,25 @@ const TOOLS = [
|
|
|
439
439
|
corporateSignature: { type: ['string', 'null'], description: 'Company signature HTML, max 4000 characters. Empty or null clears it.' },
|
|
440
440
|
disclaimerEnabled: { type: ['boolean', 'null'], description: 'Turn the legal disclaimer on or off. null follows the company-wide choice. Off by default.' },
|
|
441
441
|
disclaimerText: { type: ['string', 'null'], description: 'Legal disclaimer text, max 2000 characters. Empty or null clears it.' },
|
|
442
|
+
nameFormat: { type: ['string', 'null'], enum: ['none', 'name', 'team', 'name_and_team', 'default', null], description: 'Name line added above the signature: none | name | team | name_and_team. default/null inherits. Platform default is none.' },
|
|
443
|
+
nameSource: { type: ['string', 'null'], enum: ['real_name', 'display_name', 'default', null], description: 'Which name the name line uses. The display name falls back to the real name when the agent has none. Platform default is real_name.' },
|
|
444
|
+
teamLabel: { type: ['string', 'null'], description: 'Team name shown by the team formats, max 100 characters (for example Customer Support). Empty or null uses the routing group name.' },
|
|
445
|
+
allowTeamOverrides: { type: ['boolean', 'null'], description: 'Company-wide row only: may team admins change group signature settings. null = allowed.' },
|
|
446
|
+
allowAgentOverrides:{ type: ['boolean', 'null'], description: 'Company-wide row only: may agents choose their own name line (never while locked). null = allowed.' },
|
|
447
|
+
applyTo: { type: 'string', enum: ['inheritingGroups', 'allGroups', 'newGroupsOnly'], description: 'Company-wide row only: how a name line change reaches existing groups.' },
|
|
442
448
|
},
|
|
443
449
|
},
|
|
444
450
|
},
|
|
451
|
+
{
|
|
452
|
+
name: 'signature_policy_history',
|
|
453
|
+
description: 'List saved versions of the signature policy for the company-wide row (teamId 0) or one team, newest first, with who changed it and when. Admin only.',
|
|
454
|
+
inputSchema: { type: 'object', properties: { teamId: { type: 'integer', description: '0 = company-wide (default)' } } },
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
name: 'signature_policy_rollback',
|
|
458
|
+
description: 'Restore a saved version of the signature policy (site administrators only). The restored settings are saved as a NEW version. Use signature_policy_history to find the versionId.',
|
|
459
|
+
inputSchema: { type: 'object', properties: { versionId: { type: 'integer' } }, required: ['versionId'] },
|
|
460
|
+
},
|
|
445
461
|
{
|
|
446
462
|
name: 'kb_list_topics',
|
|
447
463
|
description: 'List all KB topics. Call this first to find the topicId needed for creating articles.',
|
|
@@ -3450,6 +3466,7 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
3450
3466
|
applicationInstanceObjectId: { type: 'string', description: 'Teams resource account (application instance) object ID. Pass "" to clear.' },
|
|
3451
3467
|
assignedPhoneNumber: { type: 'string', description: 'Phone number assigned to the resource account. Pass "" to clear.' },
|
|
3452
3468
|
webhookSecret: { type: 'string', description: 'Webhook secret. Omit to auto-generate on create or leave unchanged on update.' },
|
|
3469
|
+
queueMaxWaitSeconds: { type: 'number', description: 'Site default for how long a caller waits for a free agent, 30 to 600 seconds. Omit to leave unchanged; pass 0 to reset to the platform default (120). Valid values are 0 or 30 to 600.' },
|
|
3453
3470
|
},
|
|
3454
3471
|
required: [],
|
|
3455
3472
|
},
|
|
@@ -3461,7 +3478,7 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
|
|
|
3461
3478
|
},
|
|
3462
3479
|
{
|
|
3463
3480
|
name: 'teams_phone_test_config',
|
|
3464
|
-
description: 'Run the Teams Phone readiness checks and return each check (name, ok, message) plus callingReady
|
|
3481
|
+
description: 'Run the Teams Phone calling readiness checks on the ACS path and return each check (name, ok, message) plus callingReady: tenant ID saved, resource account saved, admin consent and inbound call routing. A response with no checks is never a pass. Surfaces what is missing rather than only being discovered when a call is missed. Lives in velaro-messaging — requires VELARO_MESSAGING_API.',
|
|
3465
3482
|
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
3466
3483
|
},
|
|
3467
3484
|
|
|
@@ -5009,7 +5026,35 @@ async function handleTool(name, args) {
|
|
|
5009
5026
|
corporateSignature: cur.corporateSignature || null,
|
|
5010
5027
|
disclaimerEnabled: cur.disclaimerEnabled ?? null,
|
|
5011
5028
|
disclaimerText: cur.disclaimerText || null,
|
|
5029
|
+
// PUT replaces the row: carry the flow-down fields or a mode change would wipe them.
|
|
5030
|
+
nameSource: cur.nameSource ?? null,
|
|
5031
|
+
nameFormat: cur.nameFormat ?? null,
|
|
5032
|
+
teamLabel: cur.teamLabel || null,
|
|
5033
|
+
allowTeamOverrides: cur.allowTeamOverrides ?? null,
|
|
5034
|
+
allowAgentOverrides: cur.allowAgentOverrides ?? null,
|
|
5012
5035
|
};
|
|
5036
|
+
const nameEnum = (v, allowed, label) => {
|
|
5037
|
+
if (v === undefined) return undefined;
|
|
5038
|
+
if (v === null || v === 'default') return null;
|
|
5039
|
+
if (!allowed.includes(v)) throw new Error(`${label} must be one of ${allowed.join(', ')} or default`);
|
|
5040
|
+
return v;
|
|
5041
|
+
};
|
|
5042
|
+
const nf = nameEnum(args.nameFormat, ['none', 'name', 'team', 'name_and_team'], 'nameFormat');
|
|
5043
|
+
if (nf !== undefined) body.nameFormat = nf;
|
|
5044
|
+
const ns = nameEnum(args.nameSource, ['real_name', 'display_name'], 'nameSource');
|
|
5045
|
+
if (ns !== undefined) body.nameSource = ns;
|
|
5046
|
+
if (args.teamLabel !== undefined) body.teamLabel = args.teamLabel || null;
|
|
5047
|
+
if (body.teamLabel && body.teamLabel.length > 100) throw new Error('teamLabel is limited to 100 characters');
|
|
5048
|
+
for (const k of ['allowTeamOverrides', 'allowAgentOverrides']) {
|
|
5049
|
+
if (args[k] !== undefined) {
|
|
5050
|
+
if (args[k] !== null && typeof args[k] !== 'boolean') throw new Error(`${k} must be true, false or null`);
|
|
5051
|
+
body[k] = args[k];
|
|
5052
|
+
}
|
|
5053
|
+
}
|
|
5054
|
+
if (args.applyTo !== undefined) {
|
|
5055
|
+
if (!['inheritingGroups', 'allGroups', 'newGroupsOnly'].includes(args.applyTo)) throw new Error('applyTo must be inheritingGroups, allGroups or newGroupsOnly');
|
|
5056
|
+
body.applyTo = args.applyTo;
|
|
5057
|
+
}
|
|
5013
5058
|
if (args.mode !== undefined) {
|
|
5014
5059
|
if (args.mode === null || args.mode === 'default') body.mode = null;
|
|
5015
5060
|
else if (modes[args.mode]) body.mode = modes[args.mode];
|
|
@@ -5027,6 +5072,17 @@ async function handleTool(name, args) {
|
|
|
5027
5072
|
return JSON.stringify(await messagingGet('/Signatures/policy'), null, 2);
|
|
5028
5073
|
}
|
|
5029
5074
|
|
|
5075
|
+
case 'signature_policy_history': {
|
|
5076
|
+
const tid = args.teamId === undefined || args.teamId === null ? 0 : args.teamId;
|
|
5077
|
+
if (!Number.isInteger(tid) || tid < 0) throw new Error('teamId must be 0 (company-wide) or a team id');
|
|
5078
|
+
return JSON.stringify(await messagingGet(`/Signatures/policy/history?teamId=${tid}`), null, 2);
|
|
5079
|
+
}
|
|
5080
|
+
|
|
5081
|
+
case 'signature_policy_rollback': {
|
|
5082
|
+
if (!Number.isInteger(args.versionId) || args.versionId <= 0) throw new Error('versionId must be a positive integer');
|
|
5083
|
+
return JSON.stringify(await messagingPost(`/Signatures/policy/rollback/${args.versionId}`, {}), null, 2);
|
|
5084
|
+
}
|
|
5085
|
+
|
|
5030
5086
|
case 'kb_list_topics': {
|
|
5031
5087
|
const data = await api('GET', '/api/kb/topics');
|
|
5032
5088
|
const topics = data?.topics ?? [];
|
|
@@ -7777,7 +7833,11 @@ reply: ${r?.reply}`;
|
|
|
7777
7833
|
applicationInstanceObjectId: args.applicationInstanceObjectId,
|
|
7778
7834
|
assignedPhoneNumber: args.assignedPhoneNumber,
|
|
7779
7835
|
webhookSecret: args.webhookSecret,
|
|
7836
|
+
queueMaxWaitSeconds: args.queueMaxWaitSeconds,
|
|
7780
7837
|
};
|
|
7838
|
+
if (args.queueMaxWaitSeconds != null && (!Number.isInteger(args.queueMaxWaitSeconds) || (args.queueMaxWaitSeconds !== 0 && (args.queueMaxWaitSeconds < 30 || args.queueMaxWaitSeconds > 600)))) {
|
|
7839
|
+
throw new Error('queueMaxWaitSeconds must be 0 (reset to default) or a whole number from 30 to 600.');
|
|
7840
|
+
}
|
|
7781
7841
|
const result = existing?.configured
|
|
7782
7842
|
? await messagingPut('/TeamsPhone/Config', body)
|
|
7783
7843
|
: await messagingPost('/TeamsPhone/Config', body);
|
|
@@ -7789,7 +7849,9 @@ reply: ${r?.reply}`;
|
|
|
7789
7849
|
}
|
|
7790
7850
|
case 'teams_phone_test_config': {
|
|
7791
7851
|
const result = await messagingPost('/TeamsPhone/Config/Test', {});
|
|
7792
|
-
const
|
|
7852
|
+
const noChecks = !Array.isArray(result.checks) || result.checks.length === 0;
|
|
7853
|
+
const passed = result.success === true && !noChecks;
|
|
7854
|
+
const lines = [`${passed ? 'Success' : 'Failed'}: ${result.message ?? (noChecks ? 'The test returned no checks, so nothing was verified.' : '(no message)')}`];
|
|
7793
7855
|
if (typeof result.callingReady === 'boolean') lines.push(`Inbound calling ready: ${result.callingReady}`);
|
|
7794
7856
|
if (Array.isArray(result.checks)) {
|
|
7795
7857
|
for (const ck of result.checks) lines.push(`${ck?.ok ? 'PASS' : 'FAIL'} ${ck?.name ?? ''}${ck?.message ? ': ' + ck.message : ''}`);
|