@agifyai/leadify-mcp 9.15.0 → 9.16.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
@@ -304,7 +304,7 @@ Leadify et ne doit jamais être envoyée par un agent MCP.
304
304
  | `delete_campaign_log` | Supprimer une entrée de log de campagne. |
305
305
  | `update_campaign_stats` | Mettre à jour les statistiques d'email d'une campagne pour un groupe de leads. |
306
306
  | `create_campaign` | Créer une campagne DRAFT mono-canal rattachée à un Lead Group qui possède déjà sa paire Persona–Offre. Aucun `persona_id` ou contexte indépendant n’est accepté au niveau Campagne. `channel` (`LINKEDIN` ou `EMAIL`) est obligatoire ; `start_at` inclusif, `end_at` exclusif et `timezone` IANA configurent la fenêtre métier. À `end_at`, Leadify met la campagne en pause réversible (`WINDOW_END`) sans la clôturer. |
307
- | `update_campaign` / `update_campaign_configuration` | Modifier le nom, la description et la fenêtre de toute campagne encore `OPEN`; le canal reste modifiable uniquement en DRAFT. Prolonger `end_at` dans le futur ou le supprimer relance automatiquement une pause `WINDOW_END` après validation du fournisseur, mais jamais une pause manuelle. La fenêtre demandée reste enregistrée si cette validation échoue. La Persona est héritée du Lead Group et n’est pas modifiable au niveau Campagne. |
307
+ | `update_campaign` / `update_campaign_configuration` | Modifier le nom, la description, la fenêtre, la limite par jour (`daily_limit`) et les jours d'envoi (`send_days`) de toute campagne encore `OPEN`, y compris en pilote ; l'audience (`audience_view_id`) se change jusqu'au lancement. La réponse rend `settings` et `sequenceWindowWarning` si la fin de campagne coupe la séquence; le canal reste modifiable uniquement en DRAFT. Prolonger `end_at` dans le futur ou le supprimer relance automatiquement une pause `WINDOW_END` après validation du fournisseur, mais jamais une pause manuelle. La fenêtre demandée reste enregistrée si cette validation échoue. La Persona est héritée du Lead Group et n’est pas modifiable au niveau Campagne. |
308
308
  | `delete_campaign` | Supprimer irréversiblement une campagne `DRAFT` ou `PAUSED` encore `OPEN`, avec la confirmation explicite `delete_campaign`. Une campagne active ou clôturée est refusée, et aucun envoi n’est déclenché. |
309
309
  | `list_campaigns` | Lister compactement les campagnes d'une organisation explicitement sélectionnée, avec état effectif, fenêtre, motif de pause et clôture. |
310
310
  | `get_campaign` | Récupérer les détails d'une campagne, son état effectif, sa clôture et son éventuel rapport final figé, ainsi que ses KPIs temps réel. |
@@ -475,7 +475,8 @@ d'écrire à quelqu'un : `get_contact_state`, puis `get_prospect_approach`. Les
475
475
  échanges captés à la main (emails et messages LinkedIn, avec texte, auteur et
476
476
  origine) arrivent dans `organizationContact.exchanges` de
477
477
  `get_outreach_contact_history` et de la première page de
478
- `get_outreach_context_history`. Les vues (`preview_lead_view`,
478
+ `get_outreach_context_history`. Une vue qu'aucune campagne n'utilise se supprime
479
+ avec `delete_lead_view`. Les vues (`preview_lead_view`,
479
480
  `create_lead_view`) acceptent les 12 champs `__contact_*` (dont `__contact_due`,
480
481
  le filtre « À relancer »), `within_last_days`, `older_than_days` et
481
482
  `includeEmpty`. Les listes fermées des entrées sont recopiées octet pour octet du
@@ -142,7 +142,18 @@ export function registerCampaignTools(server, readClient, writeClient, mutationC
142
142
  timezone: z.string().min(1).optional().describe("IANA timezone used for the business window, for example Europe/Paris."),
143
143
  name: z.string().min(1).optional().describe("New campaign name."),
144
144
  description: z.string().nullable().optional().describe("New campaign description, or null to clear it."),
145
- }, async ({ id, channel, start_at, end_at, timezone, name, description }) => {
145
+ daily_limit: z.number().int().min(1).optional().describe("Daily sending limit of the campaign channel, as on the campaign page: at most 500 for EMAIL, at most 30 for LINKEDIN (invitations and messages)."),
146
+ send_days: z.object({
147
+ monday: z.boolean().optional(),
148
+ tuesday: z.boolean().optional(),
149
+ wednesday: z.boolean().optional(),
150
+ thursday: z.boolean().optional(),
151
+ friday: z.boolean().optional(),
152
+ saturday: z.boolean().optional(),
153
+ sunday: z.boolean().optional(),
154
+ }).strict().optional().describe("Sending days to change; omitted days stay as they are. At least one day must stay enabled."),
155
+ audience_view_id: z.string().min(1).nullable().optional().describe("Audience segment: a lead view of the campaign group, or null for the whole group. Refused once the campaign is launched (only DRAFT and PILOT)."),
156
+ }, async ({ id, channel, start_at, end_at, timezone, name, description, daily_limit, send_days, audience_view_id }) => {
146
157
  try {
147
158
  const body = {};
148
159
  if (channel !== undefined)
@@ -157,6 +168,12 @@ export function registerCampaignTools(server, readClient, writeClient, mutationC
157
168
  body.name = name;
158
169
  if (description !== undefined)
159
170
  body.description = description;
171
+ if (daily_limit !== undefined)
172
+ body.dailyLimit = daily_limit;
173
+ if (send_days !== undefined)
174
+ body.sendDays = send_days;
175
+ if (audience_view_id !== undefined)
176
+ body.audienceViewId = audience_view_id;
160
177
  return toolResult(await (mutationClient ?? getClient()).put(`/api/campaign/${encodeURIComponent(id)}/configuration`, body));
161
178
  }
162
179
  catch (error) {
@@ -164,7 +181,8 @@ export function registerCampaignTools(server, readClient, writeClient, mutationC
164
181
  }
165
182
  });
166
183
  };
167
- const updateCampaignDescription = "Edit the name, description, and lifecycle window of any OPEN campaign; changing channel remains limited to DRAFT. " +
184
+ const updateCampaignDescription = "Edit the name, description, lifecycle window, daily limit and sending days of any OPEN campaign, including a campaign in PILOT, as the campaign page does; " +
185
+ "the audience segment changes until launch, and changing channel remains limited to DRAFT. The response returns the saved settings and sequenceWindowWarning when the campaign end cuts the longest sequence. " +
168
186
  "Extending endAt into the future or removing it automatically resumes only a campaign paused " +
169
187
  "because WINDOW_END, after provider validation and immediate replanning. A MANUAL pause never " +
170
188
  "auto-resumes. The requested window remains saved when provider validation fails, and a CLOSED " +
@@ -65,7 +65,7 @@ export function registerLeadViewTools(server) {
65
65
  return handleToolError(error);
66
66
  }
67
67
  });
68
- server.tool("create_lead_view", "Create an organization-shared saved view after previewing it. Idempotency key is required: retry the same request with the same key; changing the payload with that key conflicts. Update and delete are intentionally unavailable. " +
68
+ server.tool("create_lead_view", "Create an organization-shared saved view after previewing it. Idempotency key is required: retry the same request with the same key; changing the payload with that key conflicts. Update is intentionally unavailable; delete_lead_view removes a view no campaign uses. " +
69
69
  "Filters may use the contact fields __contact_*, with within_last_days, older_than_days and includeEmpty (see preview_lead_view).", { ...viewConfigSchema, idempotency_key: z.string().min(8).max(200) }, async ({ organization_id, lead_group_id, name, filters, columns, sort, pagination, idempotency_key }) => {
70
70
  try {
71
71
  const data = await getClient().post(`/api/lead-group/${encodeURIComponent(lead_group_id)}/views`, { organizationId: organization_id, name, filters, columns, sort, pagination, idempotencyKey: idempotency_key });
@@ -75,4 +75,18 @@ export function registerLeadViewTools(server) {
75
75
  return handleToolError(error);
76
76
  }
77
77
  });
78
+ server.tool("delete_lead_view", "Delete one organization-shared saved view that no campaign uses. No lead is deleted. The default view cannot be deleted, and a view chosen by a campaign is refused with the list of those campaigns. Always confirm with the user first.", {
79
+ organization_id: z.string().min(1),
80
+ lead_group_id: z.string().min(1),
81
+ view_id: z.string().min(1),
82
+ confirmation: z.literal("delete_lead_view").describe("Exact acknowledgement required before deleting the view."),
83
+ }, async ({ organization_id, lead_group_id, view_id }) => {
84
+ try {
85
+ const data = await getClient().delete(`/api/lead-group/${encodeURIComponent(lead_group_id)}/views/${encodeURIComponent(view_id)}?organizationId=${encodeURIComponent(organization_id)}`);
86
+ return toolResult(data);
87
+ }
88
+ catch (error) {
89
+ return handleToolError(error);
90
+ }
91
+ });
78
92
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agifyai/leadify-mcp",
3
- "version": "9.15.0",
3
+ "version": "9.16.0",
4
4
  "description": "MCP server for Leadify lead management API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",