@velaro/mcp-server 2.0.12 → 2.0.13

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 (3) hide show
  1. package/README.md +3 -1
  2. package/package.json +1 -1
  3. package/server.js +55 -0
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.12",
3
+ "version": "2.0.13",
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.',
@@ -5009,7 +5025,35 @@ async function handleTool(name, args) {
5009
5025
  corporateSignature: cur.corporateSignature || null,
5010
5026
  disclaimerEnabled: cur.disclaimerEnabled ?? null,
5011
5027
  disclaimerText: cur.disclaimerText || null,
5028
+ // PUT replaces the row: carry the flow-down fields or a mode change would wipe them.
5029
+ nameSource: cur.nameSource ?? null,
5030
+ nameFormat: cur.nameFormat ?? null,
5031
+ teamLabel: cur.teamLabel || null,
5032
+ allowTeamOverrides: cur.allowTeamOverrides ?? null,
5033
+ allowAgentOverrides: cur.allowAgentOverrides ?? null,
5034
+ };
5035
+ const nameEnum = (v, allowed, label) => {
5036
+ if (v === undefined) return undefined;
5037
+ if (v === null || v === 'default') return null;
5038
+ if (!allowed.includes(v)) throw new Error(`${label} must be one of ${allowed.join(', ')} or default`);
5039
+ return v;
5012
5040
  };
5041
+ const nf = nameEnum(args.nameFormat, ['none', 'name', 'team', 'name_and_team'], 'nameFormat');
5042
+ if (nf !== undefined) body.nameFormat = nf;
5043
+ const ns = nameEnum(args.nameSource, ['real_name', 'display_name'], 'nameSource');
5044
+ if (ns !== undefined) body.nameSource = ns;
5045
+ if (args.teamLabel !== undefined) body.teamLabel = args.teamLabel || null;
5046
+ if (body.teamLabel && body.teamLabel.length > 100) throw new Error('teamLabel is limited to 100 characters');
5047
+ for (const k of ['allowTeamOverrides', 'allowAgentOverrides']) {
5048
+ if (args[k] !== undefined) {
5049
+ if (args[k] !== null && typeof args[k] !== 'boolean') throw new Error(`${k} must be true, false or null`);
5050
+ body[k] = args[k];
5051
+ }
5052
+ }
5053
+ if (args.applyTo !== undefined) {
5054
+ if (!['inheritingGroups', 'allGroups', 'newGroupsOnly'].includes(args.applyTo)) throw new Error('applyTo must be inheritingGroups, allGroups or newGroupsOnly');
5055
+ body.applyTo = args.applyTo;
5056
+ }
5013
5057
  if (args.mode !== undefined) {
5014
5058
  if (args.mode === null || args.mode === 'default') body.mode = null;
5015
5059
  else if (modes[args.mode]) body.mode = modes[args.mode];
@@ -5027,6 +5071,17 @@ async function handleTool(name, args) {
5027
5071
  return JSON.stringify(await messagingGet('/Signatures/policy'), null, 2);
5028
5072
  }
5029
5073
 
5074
+ case 'signature_policy_history': {
5075
+ const tid = args.teamId === undefined || args.teamId === null ? 0 : args.teamId;
5076
+ if (!Number.isInteger(tid) || tid < 0) throw new Error('teamId must be 0 (company-wide) or a team id');
5077
+ return JSON.stringify(await messagingGet(`/Signatures/policy/history?teamId=${tid}`), null, 2);
5078
+ }
5079
+
5080
+ case 'signature_policy_rollback': {
5081
+ if (!Number.isInteger(args.versionId) || args.versionId <= 0) throw new Error('versionId must be a positive integer');
5082
+ return JSON.stringify(await messagingPost(`/Signatures/policy/rollback/${args.versionId}`, {}), null, 2);
5083
+ }
5084
+
5030
5085
  case 'kb_list_topics': {
5031
5086
  const data = await api('GET', '/api/kb/topics');
5032
5087
  const topics = data?.topics ?? [];