@agifyai/leadify-mcp 8.3.8 → 8.3.9

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 CHANGED
@@ -198,6 +198,7 @@ Conséquences pratiques :
198
198
  | `update_schema` | Ajouter ou modifier les définitions de champs d'un groupe. |
199
199
  | `delete_columns` | Supprimer des colonnes du schéma et des données d'un groupe. |
200
200
  | `update_hidden_columns` | Afficher ou masquer des colonnes dans la vue tableau (réversible). |
201
+ | `list_crm_schema_packs` | Lister le catalogue canonique des CRM Schema Packs, leurs domaines et contraintes de compatibilité. |
201
202
  | `add_campaign_log` | Enregistrer une entrée de log de campagne pour un lead. |
202
203
  | `get_campaign_logs` | Récupérer les logs de campagne avec filtres et pagination. |
203
204
  | `delete_campaign_log` | Supprimer une entrée de log de campagne. |
@@ -225,7 +226,8 @@ Conséquences pratiques :
225
226
  | `update_company_info_economics` | Patch du bloc economics (pricingModel, ticketRange, salesCycleMonths, triggers, defaultBaseline). |
226
227
  | `update_company_info_product_icp` | Add / replace / remove un seul ICP dans productICPs[]. Lookup par productId (must match a products[].name). Cap 5. |
227
228
  | `update_company_info_proof_wording` | Patch du bloc proofWording (keyMetrics, miniStories, forbiddenWords). |
228
- | `upsert_persona` | Créer ou mettre à jour un persona (ciblage, messaging, outils actifs). |
229
+ | `upsert_persona` | Créer ou mettre à jour atomiquement un Persona, avec `schema_packs` obligatoire à la création. |
230
+ | `update_persona_schema_packs` | Remplacer uniquement les CRM Schema Packs d’un Persona et relire les preuves de readiness des groupes liés. |
229
231
  | `get_persona` | Récupérer un persona par son ID. |
230
232
  | `get_lead_group_persona` | Récupérer le persona assigné à un groupe de leads. |
231
233
  | `list_data_sources` | Lister toutes les sources de données configurées (par pays puis nom). |
package/dist/server.js CHANGED
@@ -17,7 +17,7 @@ import { registerLeadViewTools } from "./tools/views.js";
17
17
  export function createServer() {
18
18
  const server = new McpServer({
19
19
  name: "leadify",
20
- version: "8.3.6",
20
+ version: "8.3.8",
21
21
  });
22
22
  registerAuthTools(server);
23
23
  registerOrganizationTools(server);
@@ -1,2 +1,7 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- export declare function registerPersonaTools(server: McpServer): void;
2
+ import { type LeadifyClient } from "../client.js";
3
+ export declare const CRM_SCHEMA_PACKS: readonly ["base_person", "base_company", "healthcare", "medtech", "recruitment_hr", "community_creator"];
4
+ type PersonaClient = Pick<LeadifyClient, "get" | "post" | "delete">;
5
+ export declare function crmSchemaPackSelectionError(packs: readonly string[], workflowMode?: "person_first" | "company_first" | null): string | null;
6
+ export declare function registerPersonaTools(server: McpServer, client?: PersonaClient): void;
7
+ export {};
@@ -55,6 +55,41 @@ const icpStrategyShape = {
55
55
  keyObjections: z.array(z.string()).optional(),
56
56
  decisionDrivers: z.array(z.string()).optional(),
57
57
  };
58
+ export const CRM_SCHEMA_PACKS = [
59
+ "base_person",
60
+ "base_company",
61
+ "healthcare",
62
+ "medtech",
63
+ "recruitment_hr",
64
+ "community_creator",
65
+ ];
66
+ const SECTOR_BASE_COMPATIBILITY = {
67
+ healthcare: ["base_person", "base_company"],
68
+ medtech: ["base_person", "base_company"],
69
+ recruitment_hr: ["base_person", "base_company"],
70
+ community_creator: ["base_person", "base_company"],
71
+ };
72
+ export function crmSchemaPackSelectionError(packs, workflowMode) {
73
+ const unknown = [...new Set(packs.filter(pack => !CRM_SCHEMA_PACKS.includes(pack)))];
74
+ if (unknown.length > 0)
75
+ return `Unknown CRM Schema Pack: ${unknown.sort().join(", ")}. Call list_crm_schema_packs first.`;
76
+ const selected = [...new Set(packs)];
77
+ const bases = selected.filter(pack => pack === "base_person" || pack === "base_company");
78
+ const sectors = selected.filter(pack => pack !== "base_person" && pack !== "base_company");
79
+ if (bases.length !== 1 || sectors.length > 1 || selected.length !== packs.length) {
80
+ return "Select exactly one base CRM Schema Pack and at most one sector pack; duplicates are not allowed.";
81
+ }
82
+ const base = bases[0];
83
+ if (workflowMode !== undefined && workflowMode !== null) {
84
+ const expectedBase = workflowMode === "company_first" ? "base_company" : "base_person";
85
+ if (base !== expectedBase)
86
+ return `${base} is incompatible with workflow_mode=${workflowMode}; use ${expectedBase}.`;
87
+ }
88
+ const incompatibleSector = sectors.find(sector => !SECTOR_BASE_COMPATIBILITY[sector].includes(base));
89
+ return incompatibleSector
90
+ ? `${incompatibleSector} is incompatible with ${base}. Call list_crm_schema_packs for compatible combinations.`
91
+ : null;
92
+ }
58
93
  // camelCase mapping for nested objects that the backend expects as-is.
59
94
  function mapLookalikeClient(c) {
60
95
  const out = { name: c.name };
@@ -139,10 +174,10 @@ class PersonaPatchError extends Error {
139
174
  * Strategy: fast-path the direct GET; on 404, fall back to the permissive
140
175
  * list endpoint and find by id. Other errors propagate immediately.
141
176
  */
142
- async function fetchPersona(id) {
177
+ async function fetchPersona(id, client = getClient()) {
143
178
  const directPath = `/api/persona/${encodeURIComponent(id)}`;
144
179
  try {
145
- const data = await getClient().get(directPath);
180
+ const data = await client.get(directPath);
146
181
  if (!data || typeof data !== "object") {
147
182
  throw new PersonaPatchError("read", directPath, null, data, "Unexpected response shape (expected an object).");
148
183
  }
@@ -162,7 +197,7 @@ async function fetchPersona(id) {
162
197
  const listPath = "/api/persona";
163
198
  let listed;
164
199
  try {
165
- listed = await getClient().get(listPath);
200
+ listed = await client.get(listPath);
166
201
  }
167
202
  catch (err) {
168
203
  if (err instanceof LeadifyApiError) {
@@ -183,10 +218,10 @@ async function fetchPersona(id) {
183
218
  }
184
219
  return found;
185
220
  }
186
- async function postPersonaUpdate(id, name, fieldsToWrite) {
221
+ async function postPersonaUpdate(id, name, fieldsToWrite, client = getClient()) {
187
222
  const path = "/api/persona";
188
223
  try {
189
- return await getClient().post(path, {
224
+ return await client.post(path, {
190
225
  id,
191
226
  name,
192
227
  ...fieldsToWrite,
@@ -227,7 +262,7 @@ function handlePersonaToolError(error) {
227
262
  return handleToolError(error);
228
263
  }
229
264
  // ─── Tool registrations ────────────────────────────────────────────────────
230
- export function registerPersonaTools(server) {
265
+ export function registerPersonaTools(server, client) {
231
266
  // ════════════════════════════════════════════════════════════════════════
232
267
  // ESCAPE HATCH — wholesale upsert
233
268
  // ════════════════════════════════════════════════════════════════════════
@@ -297,6 +332,12 @@ export function registerPersonaTools(server) {
297
332
  .nullable()
298
333
  .optional()
299
334
  .describe("Qualification mode."),
335
+ schema_packs: z
336
+ .array(z.enum(CRM_SCHEMA_PACKS))
337
+ .optional()
338
+ .describe("Canonical CRM Schema Packs. REQUIRED on create: exactly one base pack " +
339
+ "(base_person for person_first or base_company for company_first) and at most one " +
340
+ "compatible sector pack. Call list_crm_schema_packs before selecting values."),
300
341
  output_language: z
301
342
  .string()
302
343
  .nullable()
@@ -345,6 +386,14 @@ export function registerPersonaTools(server) {
345
386
  .describe("Snippets inserted at named points. scope: 'qualify' | 'outreach'; insertion_point: 'prefix' | 'phase_1_5' | 'phase_2_extra' | 'suffix'."),
346
387
  }, async (params) => {
347
388
  try {
389
+ if (params.id === undefined && params.schema_packs === undefined) {
390
+ throw new Error("schema_packs is required when creating a Persona. Call list_crm_schema_packs, then select exactly one base pack and at most one compatible sector pack.");
391
+ }
392
+ if (params.schema_packs !== undefined) {
393
+ const selectionError = crmSchemaPackSelectionError(params.schema_packs, params.workflow_mode ?? (params.id === undefined ? "person_first" : undefined));
394
+ if (selectionError)
395
+ throw new Error(selectionError);
396
+ }
348
397
  const body = { name: params.name };
349
398
  if (params.id !== undefined)
350
399
  body.id = params.id;
@@ -376,6 +425,8 @@ export function registerPersonaTools(server) {
376
425
  body.strictMatch = params.strict_match;
377
426
  if (params.workflow_mode !== undefined)
378
427
  body.workflowMode = params.workflow_mode;
428
+ if (params.schema_packs !== undefined)
429
+ body.schemaPacks = params.schema_packs;
379
430
  if (params.output_language !== undefined)
380
431
  body.outputLanguage = params.output_language;
381
432
  if (params.enable_signals !== undefined)
@@ -404,7 +455,32 @@ export function registerPersonaTools(server) {
404
455
  if (params.extra_prompt_phases !== undefined)
405
456
  body.extraPromptPhases =
406
457
  params.extra_prompt_phases.map(mapExtraPromptPhase);
407
- const data = await getClient().post("/api/persona", body);
458
+ const data = await (client ?? getClient()).post("/api/persona", body);
459
+ return toolResult(data);
460
+ }
461
+ catch (error) {
462
+ return handlePersonaToolError(error);
463
+ }
464
+ });
465
+ // ── update_persona_schema_packs ───────────────────────────────────────
466
+ server.tool("update_persona_schema_packs", "Safely replace one Persona's CRM Schema Packs without rewriting unrelated Persona sections. " +
467
+ "Reads the current Persona, validates exactly one workflow-compatible base and at most one " +
468
+ "compatible sector pack, then writes schemaPacks through the canonical Persona endpoint. " +
469
+ "The response includes the persisted Persona and readiness proofs for every linked group.", {
470
+ id: z.string().describe("Persona ID to update."),
471
+ schema_packs: z
472
+ .array(z.enum(CRM_SCHEMA_PACKS))
473
+ .min(1)
474
+ .describe("Complete replacement selection. Call list_crm_schema_packs first."),
475
+ }, async ({ id, schema_packs }) => {
476
+ try {
477
+ const api = client ?? getClient();
478
+ const persona = await fetchPersona(id, api);
479
+ const workflowMode = persona.workflowMode === "company_first" ? "company_first" : "person_first";
480
+ const selectionError = crmSchemaPackSelectionError(schema_packs, workflowMode);
481
+ if (selectionError)
482
+ throw new Error(selectionError);
483
+ const data = await postPersonaUpdate(id, persona.name, { schemaPacks: schema_packs }, api);
408
484
  return toolResult(data);
409
485
  }
410
486
  catch (error) {
@@ -428,7 +504,7 @@ export function registerPersonaTools(server) {
428
504
  "in its own tool)."),
429
505
  }, async ({ id, include_outreach }) => {
430
506
  try {
431
- const data = await getClient().get(`/api/persona/${encodeURIComponent(id)}`);
507
+ const data = await (client ?? getClient()).get(`/api/persona/${encodeURIComponent(id)}`);
432
508
  // SILO defense in depth: strip the outreach trio locally unless the
433
509
  // caller explicitly opted in. Outreach data belongs to the dedicated
434
510
  // outreach tools — never mix it with the persona read by default.
@@ -470,14 +546,14 @@ export function registerPersonaTools(server) {
470
546
  // Step 1: resolve the persona assigned to this lead group (slim view).
471
547
  // We only need the persona's id from here — we re-fetch the full
472
548
  // persona below to grab the outreach trio.
473
- const groupPersona = (await getClient().get(`/api/lead-group/${encodeURIComponent(lead_group_id)}/persona`));
549
+ const groupPersona = (await (client ?? getClient()).get(`/api/lead-group/${encodeURIComponent(lead_group_id)}/persona`));
474
550
  const personaId = groupPersona?.persona?.id;
475
551
  if (!personaId) {
476
552
  return toolError(`No persona is assigned to lead group "${lead_group_id}". ` +
477
553
  `Assign one via update_lead_group({ persona_id }) before reading outreach templates.`);
478
554
  }
479
555
  // Step 2: fetch the full persona so we can project the trio.
480
- const full = (await getClient().get(`/api/persona/${encodeURIComponent(personaId)}`));
556
+ const full = (await (client ?? getClient()).get(`/api/persona/${encodeURIComponent(personaId)}`));
481
557
  // The API may return either a bare persona or {persona: {...}}.
482
558
  const persona = full.persona ?? full;
483
559
  const trio = {
@@ -523,7 +599,7 @@ export function registerPersonaTools(server) {
523
599
  params.set("organizationId", organization_id);
524
600
  if (include_globals !== undefined)
525
601
  params.set("includeGlobals", String(include_globals));
526
- const data = await getClient().get("/api/persona", params);
602
+ const data = await (client ?? getClient()).get("/api/persona", params);
527
603
  if (verbose)
528
604
  return toolResult(data);
529
605
  // Project to compact view: id, name, organizationId, truncated description.
@@ -562,7 +638,7 @@ export function registerPersonaTools(server) {
562
638
  id: z.string().describe("Persona ID to delete."),
563
639
  }, async ({ id }) => {
564
640
  try {
565
- const data = await getClient().delete(`/api/persona/${encodeURIComponent(id)}`);
641
+ const data = await (client ?? getClient()).delete(`/api/persona/${encodeURIComponent(id)}`);
566
642
  return toolResult(data);
567
643
  }
568
644
  catch (error) {
@@ -580,7 +656,7 @@ export function registerPersonaTools(server) {
580
656
  .describe("Target organization ID (Clerk org ID). Pass null to make the persona global."),
581
657
  }, async ({ id, organization_id }) => {
582
658
  try {
583
- const data = await getClient().post(`/api/persona/${encodeURIComponent(id)}/move`, { organizationId: organization_id });
659
+ const data = await (client ?? getClient()).post(`/api/persona/${encodeURIComponent(id)}/move`, { organizationId: organization_id });
584
660
  return toolResult(data);
585
661
  }
586
662
  catch (error) {
@@ -625,7 +701,7 @@ export function registerPersonaTools(server) {
625
701
  enable_signals === undefined) {
626
702
  return toolError("Provide at least one field to update.");
627
703
  }
628
- const current = await fetchPersona(id);
704
+ const current = await fetchPersona(id, client ?? getClient());
629
705
  const body = {};
630
706
  if (description !== undefined)
631
707
  body.description = description;
@@ -637,7 +713,7 @@ export function registerPersonaTools(server) {
637
713
  body.strictMatch = strict_match;
638
714
  if (enable_signals !== undefined)
639
715
  body.enableSignals = enable_signals;
640
- const data = await postPersonaUpdate(id, name ?? current.name, body);
716
+ const data = await postPersonaUpdate(id, name ?? current.name, body, client ?? getClient());
641
717
  return toolResult(data);
642
718
  }
643
719
  catch (error) {
@@ -665,11 +741,11 @@ export function registerPersonaTools(server) {
665
741
  (remove_keys === undefined || remove_keys.length === 0)) {
666
742
  return toolError("Provide at least one of: patch (non-empty), remove_keys (non-empty).");
667
743
  }
668
- const current = await fetchPersona(id);
744
+ const current = await fetchPersona(id, client ?? getClient());
669
745
  const next = { ...asObject(current.targetProfile), ...(patch ?? {}) };
670
746
  for (const k of remove_keys ?? [])
671
747
  delete next[k];
672
- const data = await postPersonaUpdate(id, current.name, { targetProfile: next });
748
+ const data = await postPersonaUpdate(id, current.name, { targetProfile: next }, client ?? getClient());
673
749
  return toolResult(data);
674
750
  }
675
751
  catch (error) {
@@ -694,11 +770,11 @@ export function registerPersonaTools(server) {
694
770
  (remove_keys === undefined || remove_keys.length === 0)) {
695
771
  return toolError("Provide at least one of: patch (non-empty), remove_keys (non-empty).");
696
772
  }
697
- const current = await fetchPersona(id);
773
+ const current = await fetchPersona(id, client ?? getClient());
698
774
  const next = { ...asObject(current.disqualificationCriteria), ...(patch ?? {}) };
699
775
  for (const k of remove_keys ?? [])
700
776
  delete next[k];
701
- const data = await postPersonaUpdate(id, current.name, { disqualificationCriteria: next });
777
+ const data = await postPersonaUpdate(id, current.name, { disqualificationCriteria: next }, client ?? getClient());
702
778
  return toolResult(data);
703
779
  }
704
780
  catch (error) {
@@ -730,7 +806,7 @@ export function registerPersonaTools(server) {
730
806
  if (tools !== undefined && (add !== undefined || remove !== undefined)) {
731
807
  return toolError("'tools' is mutually exclusive with 'add' / 'remove'.");
732
808
  }
733
- const current = await fetchPersona(id);
809
+ const current = await fetchPersona(id, client ?? getClient());
734
810
  let next;
735
811
  if (tools !== undefined) {
736
812
  next = tools;
@@ -743,7 +819,7 @@ export function registerPersonaTools(server) {
743
819
  set.delete(t);
744
820
  next = Array.from(set);
745
821
  }
746
- const data = await postPersonaUpdate(id, current.name, { activeTools: next });
822
+ const data = await postPersonaUpdate(id, current.name, { activeTools: next }, client ?? getClient());
747
823
  return toolResult(data);
748
824
  }
749
825
  catch (error) {
@@ -781,7 +857,7 @@ export function registerPersonaTools(server) {
781
857
  disqualified: "disqualifiedCriteria",
782
858
  };
783
859
  const field = fieldMap[tier];
784
- const current = await fetchPersona(id);
860
+ const current = await fetchPersona(id, client ?? getClient());
785
861
  let nextValue;
786
862
  if (typeof criteria === "string") {
787
863
  nextValue = criteria;
@@ -793,7 +869,7 @@ export function registerPersonaTools(server) {
793
869
  : {};
794
870
  nextValue = { ...base, ...criteria };
795
871
  }
796
- const data = await postPersonaUpdate(id, current.name, { [field]: nextValue });
872
+ const data = await postPersonaUpdate(id, current.name, { [field]: nextValue }, client ?? getClient());
797
873
  return toolResult(data);
798
874
  }
799
875
  catch (error) {
@@ -816,29 +892,29 @@ export function registerPersonaTools(server) {
816
892
  client: lookalikeClient
817
893
  .optional()
818
894
  .describe("Client payload. Required for 'add' and 'replace'. Schema: {name, sector?, size?, segment?, comparison_criteria?}."),
819
- }, async ({ id, action, name, client }) => {
895
+ }, async ({ id, action, name, client: lookalikeClientInput }) => {
820
896
  try {
821
- if ((action === "add" || action === "replace") && !client) {
897
+ if ((action === "add" || action === "replace") && !lookalikeClientInput) {
822
898
  return toolError(`client is required for action '${action}'.`);
823
899
  }
824
900
  if ((action === "replace" || action === "remove") && !name) {
825
901
  return toolError(`name is required for action '${action}'.`);
826
902
  }
827
- const current = await fetchPersona(id);
903
+ const current = await fetchPersona(id, client ?? getClient());
828
904
  const list = asArray(current.lookalikeClients).map((c) => ({ ...c }));
829
905
  if (action === "add") {
830
- const newName = client.name;
906
+ const newName = lookalikeClientInput.name;
831
907
  if (list.some((c) => c.name === newName)) {
832
908
  return toolError(`A lookalike client with name "${newName}" already exists. Use action 'replace' instead.`);
833
909
  }
834
- list.push(mapLookalikeClient(client));
910
+ list.push(mapLookalikeClient(lookalikeClientInput));
835
911
  }
836
912
  else if (action === "replace") {
837
913
  const idx = list.findIndex((c) => c.name === name);
838
914
  if (idx === -1) {
839
915
  return toolError(`No lookalike client found with name "${name}".`);
840
916
  }
841
- list[idx] = mapLookalikeClient(client);
917
+ list[idx] = mapLookalikeClient(lookalikeClientInput);
842
918
  }
843
919
  else {
844
920
  const before = list.length;
@@ -851,7 +927,7 @@ export function registerPersonaTools(server) {
851
927
  }
852
928
  const data = await postPersonaUpdate(id, current.name, {
853
929
  lookalikeClients: list,
854
- });
930
+ }, client ?? getClient());
855
931
  return toolResult(data);
856
932
  }
857
933
  catch (error) {
@@ -883,7 +959,7 @@ export function registerPersonaTools(server) {
883
959
  if ((action === "replace" || action === "remove") && index === undefined) {
884
960
  return toolError(`index is required for action '${action}'.`);
885
961
  }
886
- const current = await fetchPersona(id);
962
+ const current = await fetchPersona(id, client ?? getClient());
887
963
  const list = asArray(current.painPoints).map((p) => ({ ...p }));
888
964
  if (action === "add") {
889
965
  list.push(pain);
@@ -900,7 +976,7 @@ export function registerPersonaTools(server) {
900
976
  }
901
977
  list.splice(index, 1);
902
978
  }
903
- const data = await postPersonaUpdate(id, current.name, { painPoints: list });
979
+ const data = await postPersonaUpdate(id, current.name, { painPoints: list }, client ?? getClient());
904
980
  return toolResult(data);
905
981
  }
906
982
  catch (error) {
@@ -941,7 +1017,7 @@ export function registerPersonaTools(server) {
941
1017
  context === undefined) {
942
1018
  return toolError("Provide at least one field to update.");
943
1019
  }
944
- const current = await fetchPersona(id);
1020
+ const current = await fetchPersona(id, client ?? getClient());
945
1021
  const body = {};
946
1022
  if (normalization_rules !== undefined)
947
1023
  body.normalizationRules = normalization_rules;
@@ -951,7 +1027,7 @@ export function registerPersonaTools(server) {
951
1027
  body.toneInstructions = tone_instructions;
952
1028
  if (context !== undefined)
953
1029
  body.context = context;
954
- const data = await postPersonaUpdate(id, current.name, body);
1030
+ const data = await postPersonaUpdate(id, current.name, body, client ?? getClient());
955
1031
  return toolResult(data);
956
1032
  }
957
1033
  catch (error) {
@@ -1004,7 +1080,7 @@ export function registerPersonaTools(server) {
1004
1080
  (remove_keys === undefined || remove_keys.length === 0)) {
1005
1081
  return toolError("Provide at least one field to update.");
1006
1082
  }
1007
- const current = await fetchPersona(id);
1083
+ const current = await fetchPersona(id, client ?? getClient());
1008
1084
  const next = { ...asObject(current.icpStrategy) };
1009
1085
  if (dealType !== undefined)
1010
1086
  next.dealType = dealType;
@@ -1020,7 +1096,7 @@ export function registerPersonaTools(server) {
1020
1096
  Object.assign(next, patch);
1021
1097
  for (const k of remove_keys ?? [])
1022
1098
  delete next[k];
1023
- const data = await postPersonaUpdate(id, current.name, { icpStrategy: next });
1099
+ const data = await postPersonaUpdate(id, current.name, { icpStrategy: next }, client ?? getClient());
1024
1100
  return toolResult(data);
1025
1101
  }
1026
1102
  catch (error) {
@@ -1,2 +1,5 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- export declare function registerSchemaTools(server: McpServer): void;
2
+ import { type LeadifyClient } from "../client.js";
3
+ type SchemaClient = Pick<LeadifyClient, "get" | "post">;
4
+ export declare function registerSchemaTools(server: McpServer, client?: SchemaClient): void;
5
+ export {};
@@ -1,7 +1,20 @@
1
1
  import { z } from "zod";
2
2
  import { getClient } from "../client.js";
3
3
  import { toolResult, handleToolError } from "../types.js";
4
- export function registerSchemaTools(server) {
4
+ export function registerSchemaTools(server, client) {
5
+ // ── list_crm_schema_packs ──────────────────────────────────────────────
6
+ server.tool("list_crm_schema_packs", "List the canonical CRM Schema Pack catalogue before creating or updating a Persona. " +
7
+ "Returns every pack id, label, domain, base/sector kind, compatible base packs and " +
8
+ "workflow modes, field count, registry version and composition constraints. The catalogue " +
9
+ "is global code configuration, not organization-owned data.", {}, async () => {
10
+ try {
11
+ const data = await (client ?? getClient()).get("/api/persona-types");
12
+ return toolResult(data);
13
+ }
14
+ catch (error) {
15
+ return handleToolError(error);
16
+ }
17
+ });
5
18
  // ── update_schema ──────────────────────────────────────────────────────
6
19
  server.tool("update_schema", "Add or modify field definitions in a lead group's schema. Each field update " +
7
20
  "specifies the internal field name, display label, data type, whether it's required, " +
@@ -58,7 +71,7 @@ export function registerSchemaTools(server) {
58
71
  ...(u.options ? { options: u.options } : {}),
59
72
  })),
60
73
  };
61
- const data = await getClient().post("/update-schema", body);
74
+ const data = await (client ?? getClient()).post("/update-schema", body);
62
75
  return toolResult(data);
63
76
  }
64
77
  catch (error) {
@@ -88,7 +101,7 @@ export function registerSchemaTools(server) {
88
101
  else {
89
102
  body.columnNames = column_names;
90
103
  }
91
- const data = await getClient().post("/delete-column", body);
104
+ const data = await (client ?? getClient()).post("/delete-column", body);
92
105
  return toolResult(data);
93
106
  }
94
107
  catch (error) {
@@ -120,7 +133,7 @@ export function registerSchemaTools(server) {
120
133
  body.addHiddenColumns = add_hidden;
121
134
  if (remove_hidden)
122
135
  body.removeHiddenColumns = remove_hidden;
123
- const data = await getClient().post("/update-hidden-columns", body);
136
+ const data = await (client ?? getClient()).post("/update-hidden-columns", body);
124
137
  return toolResult(data);
125
138
  }
126
139
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agifyai/leadify-mcp",
3
- "version": "8.3.8",
3
+ "version": "8.3.9",
4
4
  "description": "MCP server for Leadify lead management API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",