@agifyai/leadify-mcp 8.3.7 → 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 +3 -1
- package/dist/server.js +1 -1
- package/dist/tools/personas.d.ts +6 -1
- package/dist/tools/personas.js +112 -36
- package/dist/tools/schema.d.ts +4 -1
- package/dist/tools/schema.js +17 -4
- package/package.json +1 -1
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
|
|
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.
|
|
20
|
+
version: "8.3.8",
|
|
21
21
|
});
|
|
22
22
|
registerAuthTools(server);
|
|
23
23
|
registerOrganizationTools(server);
|
package/dist/tools/personas.d.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
|
|
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 {};
|
package/dist/tools/personas.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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") && !
|
|
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 =
|
|
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(
|
|
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(
|
|
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) {
|
package/dist/tools/schema.d.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
|
|
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 {};
|
package/dist/tools/schema.js
CHANGED
|
@@ -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) {
|