@agifyai/leadify-mcp 9.11.0 → 9.12.0
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
|
@@ -258,11 +258,11 @@ Leadify et ne doit jamais être envoyée par un agent MCP.
|
|
|
258
258
|
|------|-------------|
|
|
259
259
|
| `test_api_key` | Vérifier que la clé API configurée est valide (health check). |
|
|
260
260
|
| `list_lead_groups` | Lister les groupes accessibles d'une organisation explicitement sélectionnée, en vue compacte, avec le sous-menu de chacun (`folderId`, `folder`). `folder_id` garde exactement les groupes d'un sous-menu, `none` ceux qui n'en ont aucun. |
|
|
261
|
-
| `get_lead_group` | Consulter les métadonnées compactes d'un groupe accessible par son ID, avec son sous-menu. |
|
|
261
|
+
| `get_lead_group` | Consulter les métadonnées compactes d'un groupe accessible par son ID, avec son sous-menu et `relations` : les groupes auxquels il est relié (`field`, `leadGroupId`, `canonicalType`, `canonicalEndpointRole`, `inverseField` s'il existe). |
|
|
262
262
|
| `list_lead_group_folders` | Lister les sous-menus partagés de la barre latérale d'une organisation (nom, emoji, description, groupes). Toute l'équipe voit les mêmes. |
|
|
263
263
|
| `create_lead_group_folder` / `update_lead_group_folder` / `delete_lead_group_folder` | Créer, renommer, changer l'emoji (caractère ou code) ou la description, ajouter ou retirer des groupes, supprimer un sous-menu. La suppression garde les groupes. Droit d'écriture requis. |
|
|
264
264
|
| `move_lead_groups_to_folder` | Ranger des groupes dans un sous-menu, ou les en sortir avec `folder_id: null` ; tous bougent ou aucun. Un groupe est dans un seul sous-menu. |
|
|
265
|
-
| `create_lead_group` | Créer un groupe, choisir son type canonique optionnel et rattacher atomiquement `persona_id` avec l’`offer_id` ACTIVE du même tenant. |
|
|
265
|
+
| `create_lead_group` | Créer un groupe, choisir son type canonique optionnel et rattacher atomiquement `persona_id` avec l’`offer_id` ACTIVE du même tenant. Pour un groupe PERSON, `employer_lead_group_id` le relie dès la création au groupe d'entreprises (COMPANY, même organisation). |
|
|
266
266
|
| `update_lead_group` | Modifier un groupe avec réconciliation du schéma ; lorsque le serveur exige un contexte complet, transmettre ensemble `persona_id` et `offer_id` sans inférer l’offre. |
|
|
267
267
|
| `add_leads` | Import plat générique vers un groupe : ne crée aucune relation d’emploi, aucun rattachement parent ni identité canonique. Ne jamais l’utiliser pour rattacher une Personne à une Company (voir `upsert_person_leads_with_employment`). |
|
|
268
268
|
| `upsert_person_leads_with_employment` | Créer ou réconcilier atomiquement des Person Leads, PERSON, EMPLOYED_BY, projections et historique, sans effet commercial. |
|
|
@@ -352,7 +352,7 @@ Leadify et ne doit jamais être envoyée par un agent MCP.
|
|
|
352
352
|
| `preview_canonical_relationship_migration` | Prévisualiser une migration de champs historiques, divergences et quarantaines comprises, sans mutation. |
|
|
353
353
|
| `apply_canonical_relationship_migration` | Appliquer exactement un plan prévisualisé et borné grâce à son digest. |
|
|
354
354
|
| `rollback_canonical_relationship_migration` | Tombstoner les liens créés par un plan de migration précis. |
|
|
355
|
-
| `configure_lead_group_relations` |
|
|
355
|
+
| `configure_lead_group_relations` | Relier un groupe de personnes au groupe de leurs entreprises (ou deux groupes entre eux) dans une organisation vérifiée. Appelé sur le groupe de personnes ; l'inverse est écrit seul sur le groupe d'entreprises. `relations` remplace toute la configuration du groupe : renvoyer les relations lues avec `get_lead_group`. |
|
|
356
356
|
| `preview_canonical_identity_backfill` | Prévisualiser le backfill d'identité tenant-scoped d'un groupe et de ses parents Company configurés. |
|
|
357
357
|
| `apply_canonical_identity_backfill` | Appliquer exactement un backfill d'identité relu par digest, sans outreach ni activation. |
|
|
358
358
|
| `update_company_brain_sections` | Modifier uniquement les sections globales encore actives (`identity`, `positioning`, `allowedVocabulary`, `prohibitedVocabulary`, `legalConstraints`). Les anciennes sections Offre/Verticale sont filtrées et refusées. |
|
|
@@ -386,6 +386,9 @@ Chaque entrée est enregistrée entièrement ou annulée. Aucun numéro légal n
|
|
|
386
386
|
préparation juridique de l’entreprise n’est obligatoire.
|
|
387
387
|
|
|
388
388
|
1. Choisir l’organisation, les groupes et la fiche entreprise exacts.
|
|
389
|
+
Vérifier avec `get_lead_group` que le groupe de personnes est relié au
|
|
390
|
+
groupe d’entreprises (voir « Relier un groupe de personnes à ses
|
|
391
|
+
entreprises » ci-dessous) ; sinon, le relier avant toute écriture.
|
|
389
392
|
2. Créer la preuve avec `create_person_employment_evidence`, en conservant
|
|
390
393
|
ses dates originales. Transmettre son identifiant dans `evidence_ids`.
|
|
391
394
|
3. Appeler `upsert_person_leads_with_employment` avec les champs admis par
|
|
@@ -401,6 +404,25 @@ Tous les emplois restent accessibles, avec leurs dates et leur confiance.
|
|
|
401
404
|
Une confiance inconnue ne signifie pas une absence de lien. L’entreprise
|
|
402
405
|
utilisée pour une qualification doit être choisie explicitement.
|
|
403
406
|
|
|
407
|
+
#### Relier un groupe de personnes à ses entreprises (PRD-2811)
|
|
408
|
+
|
|
409
|
+
Un groupe de personnes (par exemple « Dirigeants ») doit être relié au
|
|
410
|
+
groupe de leurs entreprises. Sans cette liaison, la qualification refuse
|
|
411
|
+
les entreprises (`QUALIFICATION_EMPLOYEE_REQUIRED`) et les tableaux
|
|
412
|
+
n’affichent ni l’employeur d’une personne ni les employés d’une entreprise.
|
|
413
|
+
|
|
414
|
+
- À la création : `create_lead_group` avec `entity_kind: "PERSON"` et
|
|
415
|
+
`employer_lead_group_id: <groupe d’entreprises>` (groupe COMPANY de la
|
|
416
|
+
même organisation).
|
|
417
|
+
- Pour un groupe existant : `configure_lead_group_relations` sur le groupe
|
|
418
|
+
de personnes, avec `{ field: "parent_lead", lead_group_id: <groupe
|
|
419
|
+
d’entreprises>, canonical_type: "EMPLOYED_BY", canonical_endpoint_role:
|
|
420
|
+
"SOURCE", inverse_field: "child_leads" }`. L’inverse est écrit seul sur le
|
|
421
|
+
groupe d’entreprises. `relations` remplace toute la configuration : lire
|
|
422
|
+
d’abord les relations existantes avec `get_lead_group` et les renvoyer
|
|
423
|
+
avec la nouvelle.
|
|
424
|
+
- Vérifier ensuite avec `get_lead_group` sur les deux groupes.
|
|
425
|
+
|
|
404
426
|
Pour modifier un emploi existant, utiliser `manage_person_employment` :
|
|
405
427
|
`attach` ajoute sans fermer les autres emplois ; `end` termine une période ;
|
|
406
428
|
`invalidate` conserve la trace d’un lien erroné ; `replace` remplace seulement
|
|
@@ -518,7 +540,9 @@ de 1 à 20 entreprises et un `request_id` UUID. Commencer avec `dry_run: true`
|
|
|
518
540
|
(valeur par défaut), puis transmettre le `expectedSchemaHash` retourné dans
|
|
519
541
|
`expected_schema_hash` avec `dry_run: false`. La clé doit avoir les droits
|
|
520
542
|
`write` et `start_qualification`, et son propriétaire doit administrer
|
|
521
|
-
l’organisation.
|
|
543
|
+
l’organisation. Le groupe d’entreprises doit être relié à un groupe de
|
|
544
|
+
personnes (`configure_lead_group_relations`), et chaque entreprise doit avoir
|
|
545
|
+
un employé vérifié et relié.
|
|
522
546
|
Avant l’accord du pilote dans les réglages du groupe, deux entreprises distinctes
|
|
523
547
|
au plus sont admises, même avec plusieurs appels. Une répétition conserve le
|
|
524
548
|
même `request_id` et la même sélection. Aucun groupe entier n’est déduit.
|
|
@@ -34,7 +34,14 @@ const backfillScope = {
|
|
|
34
34
|
lead_ids: z.array(z.string().trim().min(1)).min(1).max(100),
|
|
35
35
|
};
|
|
36
36
|
export function registerCanonicalBackfillTools(server, client = getClient()) {
|
|
37
|
-
server.tool("configure_lead_group_relations", "
|
|
37
|
+
server.tool("configure_lead_group_relations", "Link (connect, pair) a person group to the company group of their employers, or set any other relation between two lead groups of the same organization. " +
|
|
38
|
+
"Common use: link a person group (for example \"Dirigeants\") to its company group. Call it on the person group with " +
|
|
39
|
+
"relations: [{ field: \"parent_lead\", lead_group_id: <company group id>, canonical_type: \"EMPLOYED_BY\", canonical_endpoint_role: \"SOURCE\", inverse_field: \"child_leads\" }]. " +
|
|
40
|
+
"Leadify writes the inverse relation on the company group by itself: do not call it again on the company group. " +
|
|
41
|
+
"Without this link, qualification refuses the companies (QUALIFICATION_EMPLOYEE_REQUIRED) and the tables show neither the employer of a person nor the employees of a company. " +
|
|
42
|
+
"relations replaces the whole relation configuration of the group: first read the existing relations with get_lead_group, then send them back together with the new one; a relation left out is removed. " +
|
|
43
|
+
"The organization is mandatory and verified against both groups; canonical_type and canonical_endpoint_role must be specified together. " +
|
|
44
|
+
"The same configuration is read by canonical relationship migrations. It changes no lead, identity, canonical relationship, campaign, or outreach.", { organization_id: z.string().trim().min(1), lead_group_id: z.string().trim().min(1), relations: z.array(relation).max(100) }, async ({ organization_id, lead_group_id, relations }) => {
|
|
38
45
|
try {
|
|
39
46
|
return toolResult(await client.put(`/api/lead-group/${encodeURIComponent(lead_group_id)}/relations`, {
|
|
40
47
|
organizationId: organization_id,
|
|
@@ -15,7 +15,9 @@ export function registerLeadGroupTools(server, writeClient) {
|
|
|
15
15
|
server.tool("create_lead_group", "Create a new lead group in the specified organization. A lead group holds leads, a " +
|
|
16
16
|
"schema, and an optional persona assignment. Use list_organizations first to find the " +
|
|
17
17
|
"organization_id if you don't have it. Assigning a persona at creation time scopes " +
|
|
18
|
-
"scoring/messaging immediately.
|
|
18
|
+
"scoring/messaging immediately. For a PERSON group, pass employer_lead_group_id to link it at " +
|
|
19
|
+
"creation to the company group of their employers (otherwise link it afterwards with " +
|
|
20
|
+
"configure_lead_group_relations).", {
|
|
19
21
|
name: z.string().describe("Group name."),
|
|
20
22
|
organization_id: z
|
|
21
23
|
.string()
|
|
@@ -53,6 +55,14 @@ export function registerLeadGroupTools(server, writeClient) {
|
|
|
53
55
|
.nullable()
|
|
54
56
|
.optional()
|
|
55
57
|
.describe("Active offer ID to assign with persona_id. Must belong to the same organization."),
|
|
58
|
+
employer_lead_group_id: z
|
|
59
|
+
.string()
|
|
60
|
+
.trim()
|
|
61
|
+
.min(1)
|
|
62
|
+
.optional()
|
|
63
|
+
.describe("For a PERSON group: ID of the COMPANY group of the same organization that holds their employers. " +
|
|
64
|
+
"Links the new person group to that company group at creation, the same link as " +
|
|
65
|
+
"configure_lead_group_relations (parent_lead / child_leads, EMPLOYED_BY). Check it with get_lead_group."),
|
|
56
66
|
}, async (params) => {
|
|
57
67
|
try {
|
|
58
68
|
const body = {
|
|
@@ -73,6 +83,8 @@ export function registerLeadGroupTools(server, writeClient) {
|
|
|
73
83
|
body.personaId = params.persona_id;
|
|
74
84
|
if (params.offer_id !== undefined)
|
|
75
85
|
body.offerId = params.offer_id;
|
|
86
|
+
if (params.employer_lead_group_id !== undefined)
|
|
87
|
+
body.employerLeadGroupId = params.employer_lead_group_id;
|
|
76
88
|
const data = await (writeClient ?? getClient()).post("/api/lead-group", body);
|
|
77
89
|
return toolResult(data);
|
|
78
90
|
}
|
|
@@ -10,6 +10,12 @@ export declare function leadGroupFolder(group: Record<string, unknown>): {
|
|
|
10
10
|
emoji: unknown;
|
|
11
11
|
} | null;
|
|
12
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* Compact view of the groups this group is linked to (for example a person
|
|
15
|
+
* group linked to the company group of its employers). Display mapping
|
|
16
|
+
* details (targetField, displayField, canonicalLabel) stay out of the read.
|
|
17
|
+
*/
|
|
18
|
+
export declare function compactLeadGroupRelations(relations: unknown): Record<string, unknown>[];
|
|
13
19
|
/** Keep group reads navigable: never return schema, profiles, or lead data. */
|
|
14
20
|
export declare function compactLeadGroup(group: unknown): Record<string, unknown>;
|
|
15
21
|
export declare function registerOrganizationTools(server: McpServer, client?: Pick<LeadifyClient, "get" | "post" | "put">): void;
|
|
@@ -42,6 +42,24 @@ function listedLeadGroup(group) {
|
|
|
42
42
|
...leadGroupFolder(group),
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Compact view of the groups this group is linked to (for example a person
|
|
47
|
+
* group linked to the company group of its employers). Display mapping
|
|
48
|
+
* details (targetField, displayField, canonicalLabel) stay out of the read.
|
|
49
|
+
*/
|
|
50
|
+
export function compactLeadGroupRelations(relations) {
|
|
51
|
+
if (!Array.isArray(relations))
|
|
52
|
+
return [];
|
|
53
|
+
return relations
|
|
54
|
+
.filter((relation) => Boolean(relation) && typeof relation === "object")
|
|
55
|
+
.map((relation) => ({
|
|
56
|
+
field: relation.field,
|
|
57
|
+
leadGroupId: relation.leadGroupId,
|
|
58
|
+
canonicalType: relation.canonicalType ?? null,
|
|
59
|
+
canonicalEndpointRole: relation.canonicalEndpointRole ?? null,
|
|
60
|
+
...(typeof relation.inverseField === "string" && relation.inverseField ? { inverseField: relation.inverseField } : {}),
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
45
63
|
/** Keep group reads navigable: never return schema, profiles, or lead data. */
|
|
46
64
|
export function compactLeadGroup(group) {
|
|
47
65
|
const source = group && typeof group === "object" ? group : {};
|
|
@@ -62,6 +80,7 @@ export function compactLeadGroup(group) {
|
|
|
62
80
|
refreshEnabled: source.refreshEnabled ?? false,
|
|
63
81
|
refreshFrequencyDays: source.refreshFrequencyDays ?? null,
|
|
64
82
|
createdAt: source.createdAt ?? null,
|
|
83
|
+
relations: compactLeadGroupRelations(source.relations),
|
|
65
84
|
...leadGroupFolder(source),
|
|
66
85
|
};
|
|
67
86
|
}
|
|
@@ -132,10 +151,14 @@ export function registerOrganizationTools(server, client = getClient()) {
|
|
|
132
151
|
}
|
|
133
152
|
});
|
|
134
153
|
server.tool("get_lead_group", "Read the compact metadata of one accessible lead group by ID. Use this after list_lead_groups " +
|
|
135
|
-
"or discover_leadify_context to confirm its type and operational state
|
|
136
|
-
"
|
|
137
|
-
"
|
|
138
|
-
"
|
|
154
|
+
"or discover_leadify_context to confirm its type and operational state, and to see which other groups " +
|
|
155
|
+
"this group is linked to: relations lists each link as { field, leadGroupId, canonicalType, " +
|
|
156
|
+
"canonicalEndpointRole, inverseField when present } (for example a person group linked to the company " +
|
|
157
|
+
"group of their employers with field parent_lead and canonicalType EMPLOYED_BY). An empty relations " +
|
|
158
|
+
"array means the group is linked to no other group; link it with configure_lead_group_relations, after " +
|
|
159
|
+
"reading these relations, since that tool replaces the whole list. Returns no lead records, schema, " +
|
|
160
|
+
"company profile, or persona payload; includes its shared sidebar folder (folderId, folder), and reports " +
|
|
161
|
+
"inaccessible groups as not found, without revealing their organization.", {
|
|
139
162
|
lead_group_id: z.string().describe("Lead group ID returned by Leadify discovery or another authorized Leadify response."),
|
|
140
163
|
}, async ({ lead_group_id }) => {
|
|
141
164
|
try {
|
|
@@ -5,6 +5,8 @@ export function registerQualificationRunTools(server, client = getClient()) {
|
|
|
5
5
|
server.tool("start_qualification_run", "Validate or start qualification of an explicit list of 1 to 20 companies in one organization and group, " +
|
|
6
6
|
"then their linked people. dry_run defaults to true: read preflight.snapshot.expectedSchemaHash, then " +
|
|
7
7
|
"send it as expected_schema_hash with dry_run=false and the same request_id to launch. " +
|
|
8
|
+
"The company group must be linked to a person group (configure_lead_group_relations on the person group, " +
|
|
9
|
+
"checked with get_lead_group): without that link the server refuses with QUALIFICATION_EMPLOYEE_REQUIRED. " +
|
|
8
10
|
"The server refuses companies without a verified employee and more than two distinct pilot companies " +
|
|
9
11
|
"until a human approves the pilot for this group in Leadify. No outreach or campaign activation. " +
|
|
10
12
|
"Keep request_id unchanged when retrying the same selection. Read the returned runId with get_qualification_run.", { organization_id: z.string().trim().min(1), lead_group_id: z.string().trim().min(1),
|