@velaro/mcp-server 0.6.80 → 0.6.81

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 +1 -0
  2. package/package.json +1 -1
  3. package/server.js +122 -1
package/README.md CHANGED
@@ -118,6 +118,7 @@ This works with any MCP client that supports HTTP/SSE transport — including Cl
118
118
  | `bot_list` | List all bot/AI configurations for this site |
119
119
  | `bot_get` | Get full bot config including system prompt |
120
120
  | `bot_update_prompt` | Update a bot's system prompt |
121
+ | `ai_config_set_reply_format` | Set reply format: global (plain text), plain, or markdown |
121
122
 
122
123
  ### CRM Mobile Fields
123
124
  | Tool | What It Does |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velaro/mcp-server",
3
- "version": "0.6.80",
3
+ "version": "0.6.81",
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
@@ -299,7 +299,7 @@ async function gatewayInit() {
299
299
  const MESSAGING_ADMIN_TOOLS = new Set([
300
300
  'workflow_create', 'workflow_list', 'workflow_get', 'workflow_toggle',
301
301
  'bot_create', 'bot_list', 'bot_get', 'bot_update_prompt', 'bot_set_knowledge',
302
- 'ai_config_attach_index', 'call_pop_settings_get', 'call_pop_settings_set',
302
+ 'ai_config_attach_index', 'ai_config_set_reply_format', 'call_pop_settings_get', 'call_pop_settings_set',
303
303
  'crm_mobile_fields_get', 'crm_mobile_fields_set',
304
304
  'agent_list', 'team_list', 'conversation_list', 'conversation_get', 'conversation_search',
305
305
  'contact_search', 'contact_get', 'routing_list', 'routing_get', 'site_info',
@@ -1165,6 +1165,18 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
1165
1165
  required: ['id', 'prompt'],
1166
1166
  },
1167
1167
  },
1168
+ {
1169
+ name: 'ai_config_set_reply_format',
1170
+ description: 'Set how a bot formats replies. mode: global (follow global default, plain text, no markdown, no em/en dashes), plain (force plain text), markdown (allow markdown; explicit bullet/table requests are honored). Applies to every channel. Admin UI: Bots > AI Settings > General > Reply format.',
1171
+ inputSchema: {
1172
+ type: 'object',
1173
+ properties: {
1174
+ aiConfigId: { type: 'number', description: 'AI configuration ID (from bot_list)' },
1175
+ mode: { type: 'string', enum: ['global', 'plain', 'markdown'], description: 'Reply format mode' },
1176
+ },
1177
+ required: ['aiConfigId', 'mode'],
1178
+ },
1179
+ },
1168
1180
  {
1169
1181
  name: 'site_identity_secret_status',
1170
1182
  description: 'Check whether a visitor identity signing secret is configured for this site. The secret lets pre-authenticated visitors (already logged in to the customer website) skip the OTP challenge when the bot looks up their CRM data. Returns whether configured and the masked secret. To generate or rotate the secret, the customer goes to Admin → Account Settings → Security → "Visitor Identity Signing Secret".',
@@ -1904,6 +1916,33 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
1904
1916
  required: ['indexName'],
1905
1917
  },
1906
1918
  },
1919
+ {
1920
+ name: 'kb_advise_knowledge_strategy',
1921
+ description: 'Recommend, per data source (manual_pdf, spec_sheet, policy_document, faq_or_help_pages, product_catalog, price_list, cross_reference_sheet, images_or_drawings, cad_files, other_documents), whether to embed all, embed some, use exact lookup or query live, exactly what to upload, and a rough size estimate. Pure computation: nothing is read or written. Estimates only. Wraps POST KnowledgeAdvisor/advise.',
1922
+ inputSchema: {
1923
+ type: 'object',
1924
+ properties: {
1925
+ sources: {
1926
+ type: 'array',
1927
+ items: {
1928
+ type: 'object',
1929
+ properties: {
1930
+ kind: { type: 'string' },
1931
+ name: { type: 'string' },
1932
+ pages: { type: 'integer' },
1933
+ rows: { type: 'integer' },
1934
+ changeFrequency: { type: 'string', description: 'static | monthly | weekly | daily | realtime' },
1935
+ hasExactIdentifiers: { type: 'boolean' },
1936
+ scanned: { type: 'boolean' },
1937
+ hasLiveSystem: { type: 'boolean' },
1938
+ },
1939
+ required: ['kind'],
1940
+ },
1941
+ },
1942
+ },
1943
+ required: ['sources'],
1944
+ },
1945
+ },
1907
1946
  {
1908
1947
  name: 'index_integrity_check',
1909
1948
  description: 'Read-only integrity report for a knowledge index: orphan chunks, records without chunks, count mismatches, duplicate records. Wraps GET IndexMove/Integrity.',
@@ -3651,6 +3690,51 @@ For multiSelect dynamic options: the variable named in dynamicOptionsVariable mu
3651
3690
  },
3652
3691
  },
3653
3692
 
3693
+ // ── Business actions + SAP (one definition, many surfaces) ─────────────────────
3694
+ {
3695
+ name: 'sap_diagnose',
3696
+ description: 'Run the SAP live diagnostic for a site: configuration completeness, authentication (real HTTP status) and, when deep, a per-capability read-only probe compared with what the capability matrix documents (S/4HANA on-prem/private/public, Business One, ECC via gateway). Never writes; a write capability is never reported as verified; secrets are never returned. Calls messaging GET diagnostics/test-sap?siteId=<id>&deep=<bool>. Velaro staff only.',
3697
+ inputSchema: {
3698
+ type: 'object',
3699
+ properties: {
3700
+ siteId: { type: 'number', description: 'Site to diagnose (e.g. 1032)' },
3701
+ deep: { type: 'boolean', description: 'Probe every capability (default true). false = configuration + authentication only.' },
3702
+ },
3703
+ required: ['siteId'],
3704
+ },
3705
+ },
3706
+ {
3707
+ name: 'business_action_list',
3708
+ 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.',
3709
+ inputSchema: { type: 'object', properties: {} },
3710
+ },
3711
+ {
3712
+ name: 'business_action_route',
3713
+ description: 'Deterministically route free text to the business action(s) it means (no model call, no side effects, grants nothing - authorization stays in the executor). Returns ranked matches with score, matched terms and AI skill tool names. Calls POST /BusinessActions/Route.',
3714
+ inputSchema: {
3715
+ type: 'object',
3716
+ properties: {
3717
+ text: { type: 'string', description: 'What the customer or agent asked for, e.g. "what is my contract price for BRG-6204"' },
3718
+ max: { type: 'number', description: 'Max matches (default 3)' },
3719
+ },
3720
+ required: ['text'],
3721
+ },
3722
+ },
3723
+ {
3724
+ name: 'business_action_execute',
3725
+ description: 'Execute a business action as the authenticated caller (agent actor; site from auth context, never from arguments). Read actions return data with source system and freshness; write actions are idempotent: repeating the same idempotencyKey (or the same body in the same conversation) returns the stored result and never creates a duplicate, a timed-out write reports OUTCOMEUNKNOWN and must be verified in the system of record before retrying. Prices are never accepted from the caller for ERP-priced actions. Calls POST /BusinessActions/{name}/Execute.',
3726
+ inputSchema: {
3727
+ type: 'object',
3728
+ properties: {
3729
+ name: { type: 'string', description: 'Action name from business_action_list, e.g. get_customer_pricing or create_quote' },
3730
+ request: { type: 'object', description: 'The action request body (see requestSchema from business_action_list)' },
3731
+ idempotencyKey: { type: 'string', description: 'For writes: reuse the same key to replay the same result instead of creating another document' },
3732
+ conversationId: { type: 'string', description: 'Optional conversation to attach the result to' },
3733
+ },
3734
+ required: ['name', 'request'],
3735
+ },
3736
+ },
3737
+
3654
3738
  // ── CallRail Attribution ──────────────────────────────────────────────────────
3655
3739
  {
3656
3740
  name: 'callrail_get_attributions',
@@ -5750,6 +5834,9 @@ async function handleTool(name, args) {
5750
5834
  case 'bot_update_prompt':
5751
5835
  return await rpc('bot_update_prompt', args);
5752
5836
 
5837
+ case 'ai_config_set_reply_format':
5838
+ return await rpc('ai_config_set_reply_format', args);
5839
+
5753
5840
  case 'site_identity_secret_status': {
5754
5841
  const settings = await api('GET', '/SiteSettings');
5755
5842
  const configured = settings?.identitySigningSecretConfigured ?? false;
@@ -6827,6 +6914,11 @@ async function handleTool(name, args) {
6827
6914
  const r = await messagingGet(`/IndexMove/MixedContent?index=${encodeURIComponent(args.indexName)}`);
6828
6915
  return JSON.stringify(r, null, 2);
6829
6916
  }
6917
+ case 'kb_advise_knowledge_strategy': {
6918
+ if (!Array.isArray(args.sources) || args.sources.length === 0) throw new Error('sources must be a non-empty array of { kind, ... }');
6919
+ const r = await messagingPost('/KnowledgeAdvisor/advise', { sources: args.sources });
6920
+ return JSON.stringify(r, null, 2);
6921
+ }
6830
6922
  case 'index_integrity_check': {
6831
6923
  const r = await messagingGet(`/IndexMove/Integrity?index=${encodeURIComponent(args.indexName)}`);
6832
6924
  return JSON.stringify(r, null, 2);
@@ -8709,6 +8801,35 @@ async function handleTool(name, args) {
8709
8801
  return JSON.stringify(r, null, 2);
8710
8802
  }
8711
8803
 
8804
+ // ── Business actions + SAP ────────────────────────────────────────────────
8805
+ case 'sap_diagnose': {
8806
+ if (!args.siteId) return 'siteId is required.';
8807
+ const deep = args.deep === false ? 'false' : 'true';
8808
+ const r = await api('GET', `/diagnostics/test-sap?siteId=${encodeURIComponent(args.siteId)}&deep=${deep}`);
8809
+ return JSON.stringify(r, null, 2);
8810
+ }
8811
+
8812
+ case 'business_action_list': {
8813
+ const r = await api('GET', '/BusinessActions');
8814
+ return JSON.stringify(r, null, 2);
8815
+ }
8816
+
8817
+ case 'business_action_route': {
8818
+ if (!args.text) return 'text is required.';
8819
+ const r = await api('POST', '/BusinessActions/Route', { text: args.text, max: args.max });
8820
+ return JSON.stringify(r, null, 2);
8821
+ }
8822
+
8823
+ case 'business_action_execute': {
8824
+ if (!args.name) return 'name is required.';
8825
+ if (!args.request || typeof args.request !== 'object') return 'request (object) is required.';
8826
+ const qs = [];
8827
+ if (args.idempotencyKey) qs.push(`idempotencyKey=${encodeURIComponent(args.idempotencyKey)}`);
8828
+ if (args.conversationId) qs.push(`conversationId=${encodeURIComponent(args.conversationId)}`);
8829
+ const r = await api('POST', `/BusinessActions/${encodeURIComponent(args.name)}/Execute${qs.length ? '?' + qs.join('&') : ''}`, args.request);
8830
+ return JSON.stringify(r, null, 2);
8831
+ }
8832
+
8712
8833
  // ── CallRail Attribution ──────────────────────────────────────────────────
8713
8834
  case 'callrail_get_attributions': {
8714
8835
  const limit = Math.min(100, args.limit ?? 25);