@connect-xlab/mcp-server 0.1.2 → 0.2.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.
Files changed (67) hide show
  1. package/dist/index.js +128 -0
  2. package/dist/tools/addCalendarQuestion.js +41 -0
  3. package/dist/tools/addSmartJoinQuestion.js +38 -0
  4. package/dist/tools/addSubscriptionPrice.js +33 -0
  5. package/dist/tools/clearSmartJoinResponses.js +26 -0
  6. package/dist/tools/createCompany.js +48 -0
  7. package/dist/tools/createCompanyCategory.js +29 -0
  8. package/dist/tools/createFunnel.js +40 -0
  9. package/dist/tools/createPost.js +4 -1
  10. package/dist/tools/createShopProduct.js +5 -3
  11. package/dist/tools/deleteCalendarQuestion.js +29 -0
  12. package/dist/tools/deleteCompany.js +29 -0
  13. package/dist/tools/deleteCompanyCategory.js +29 -0
  14. package/dist/tools/deleteFunnel.js +29 -0
  15. package/dist/tools/deleteFunnelItem.js +34 -0
  16. package/dist/tools/deleteNewsletterEdition.js +29 -0
  17. package/dist/tools/deleteNewsletterSubscriber.js +29 -0
  18. package/dist/tools/deleteSmartJoinQuestion.js +29 -0
  19. package/dist/tools/deleteSubscriptionPrice.js +29 -0
  20. package/dist/tools/duplicateSmartJoinQuestion.js +29 -0
  21. package/dist/tools/getCalendar.js +26 -0
  22. package/dist/tools/getCalendarPipeline.js +26 -0
  23. package/dist/tools/getFunnel.js +35 -0
  24. package/dist/tools/getFunnelStats.js +35 -0
  25. package/dist/tools/getLabAffiliationConfig.js +29 -0
  26. package/dist/tools/getNewsletterEdition.js +29 -0
  27. package/dist/tools/getNewsletterRevenue.js +28 -0
  28. package/dist/tools/getNewsletterSettings.js +28 -0
  29. package/dist/tools/getProductAffiliationConfig.js +36 -0
  30. package/dist/tools/getSmartJoin.js +26 -0
  31. package/dist/tools/getSubscriptionSettings.js +29 -0
  32. package/dist/tools/listCompanies.js +34 -0
  33. package/dist/tools/listCompanyCategories.js +28 -0
  34. package/dist/tools/listFunnelOffers.js +29 -0
  35. package/dist/tools/listLabAffiliates.js +40 -0
  36. package/dist/tools/listPixelRequests.js +45 -0
  37. package/dist/tools/listProductAffiliates.js +49 -0
  38. package/dist/tools/listSmartJoinResponses.js +40 -0
  39. package/dist/tools/manageLabAffiliate.js +41 -0
  40. package/dist/tools/managePixelRequest.js +35 -0
  41. package/dist/tools/manageProductAffiliate.js +45 -0
  42. package/dist/tools/reactivateNewsletter.js +28 -0
  43. package/dist/tools/reorderClass.js +34 -0
  44. package/dist/tools/reorderSmartJoinQuestions.js +32 -0
  45. package/dist/tools/scheduleNewsletterEdition.js +34 -0
  46. package/dist/tools/setCurrentSubscriptionPrice.js +34 -0
  47. package/dist/tools/setFunnelItem.js +94 -0
  48. package/dist/tools/stopNewsletter.js +28 -0
  49. package/dist/tools/updateCalendar.js +70 -0
  50. package/dist/tools/updateCalendarAvailability.js +51 -0
  51. package/dist/tools/updateCalendarDisqualifRules.js +48 -0
  52. package/dist/tools/updateCalendarFollowupConfig.js +51 -0
  53. package/dist/tools/updateCalendarQuestion.js +43 -0
  54. package/dist/tools/updateCompany.js +49 -0
  55. package/dist/tools/updateCompanyCategory.js +34 -0
  56. package/dist/tools/updateFunnel.js +37 -0
  57. package/dist/tools/updateLabAffiliationConfig.js +44 -0
  58. package/dist/tools/updateLinkInBio.js +13 -13
  59. package/dist/tools/updateNewsletterEdition.js +43 -0
  60. package/dist/tools/updateNewsletterSettings.js +63 -0
  61. package/dist/tools/updatePost.js +3 -1
  62. package/dist/tools/updateProductAffiliationConfig.js +43 -0
  63. package/dist/tools/updateShopProduct.js +5 -1
  64. package/dist/tools/updateSmartJoinQuestion.js +40 -0
  65. package/dist/tools/updateSmartJoinSettings.js +29 -0
  66. package/dist/tools/updateTrialSettings.js +34 -0
  67. package/package.json +1 -1
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Tool `update_calendar_disqualif_rules` — règles de disqualification des leads.
3
+ */
4
+ import { z } from 'zod';
5
+ import { http, formatApiError } from '../http.js';
6
+ export const updateCalendarDisqualifRulesTool = {
7
+ name: 'update_calendar_disqualif_rules',
8
+ description: "Remplace les regles de disqualification automatique des leads du Calendrier IA. rules est le jeu complet de regles : condition_type = phone_country (indicatif telephonique) ou question_answer (reponse a une question, question_id requis), disqualifying_values = valeurs qui disqualifient. Envoyer un tableau vide efface toutes les regles.",
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ lab: { type: 'string' },
13
+ rules: {
14
+ type: 'array',
15
+ items: {
16
+ type: 'object',
17
+ properties: {
18
+ condition_type: { type: 'string', enum: ['phone_country', 'question_answer'] },
19
+ question_id: { type: ['number', 'null'], description: 'Requis si condition_type=question_answer' },
20
+ disqualifying_values: { type: 'array', items: { type: 'string' } },
21
+ },
22
+ required: ['condition_type'],
23
+ additionalProperties: false,
24
+ },
25
+ },
26
+ },
27
+ required: ['lab', 'rules'],
28
+ additionalProperties: false,
29
+ },
30
+ zodSchema: z.object({
31
+ lab: z.string(),
32
+ rules: z.array(z.object({
33
+ condition_type: z.enum(['phone_country', 'question_answer']),
34
+ question_id: z.number().int().positive().nullable().optional(),
35
+ disqualifying_values: z.array(z.string()).optional(),
36
+ })),
37
+ }),
38
+ async handler(args) {
39
+ const p = this.zodSchema.parse(args);
40
+ try {
41
+ const { data } = await http.put(`/mcp/labs/${encodeURIComponent(p.lab)}/calendar/disqualif-rules`, { rules: p.rules });
42
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
43
+ }
44
+ catch (err) {
45
+ return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
46
+ }
47
+ },
48
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Tool `update_calendar_followup_config` — relances automatiques des prospects.
3
+ */
4
+ import { z } from 'zod';
5
+ import { http, formatApiError } from '../http.js';
6
+ export const updateCalendarFollowupConfigTool = {
7
+ name: 'update_calendar_followup_config',
8
+ description: "Configure les relances automatiques des prospects du Calendrier IA (max 2). trigger_type = abandon_step1 (a quitte au formulaire) ou no_booking (n'a pas reserve). Pour chaque : enabled, delay_hours (1..720), message_template optionnel.",
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ lab: { type: 'string' },
13
+ configs: {
14
+ type: 'array',
15
+ maxItems: 2,
16
+ items: {
17
+ type: 'object',
18
+ properties: {
19
+ trigger_type: { type: 'string', enum: ['abandon_step1', 'no_booking'] },
20
+ enabled: { type: 'boolean' },
21
+ delay_hours: { type: 'number', minimum: 1, maximum: 720 },
22
+ message_template: { type: 'string' },
23
+ },
24
+ required: ['trigger_type', 'enabled', 'delay_hours'],
25
+ additionalProperties: false,
26
+ },
27
+ },
28
+ },
29
+ required: ['lab', 'configs'],
30
+ additionalProperties: false,
31
+ },
32
+ zodSchema: z.object({
33
+ lab: z.string(),
34
+ configs: z.array(z.object({
35
+ trigger_type: z.enum(['abandon_step1', 'no_booking']),
36
+ enabled: z.boolean(),
37
+ delay_hours: z.number().int().min(1).max(720),
38
+ message_template: z.string().nullable().optional(),
39
+ })).max(2),
40
+ }),
41
+ async handler(args) {
42
+ const p = this.zodSchema.parse(args);
43
+ try {
44
+ const { data } = await http.put(`/mcp/labs/${encodeURIComponent(p.lab)}/calendar/followup-config`, { configs: p.configs });
45
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
46
+ }
47
+ catch (err) {
48
+ return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
49
+ }
50
+ },
51
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Tool `update_calendar_question` — modifie une question du calendrier.
3
+ */
4
+ import { z } from 'zod';
5
+ import { http, formatApiError } from '../http.js';
6
+ export const updateCalendarQuestionTool = {
7
+ name: 'update_calendar_question',
8
+ description: "Modifie une question de qualification du Calendrier IA. question_id vient de get_calendar. question_type = text ou qcm (options requises si qcm).",
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ lab: { type: 'string' },
13
+ question_id: { type: 'number' },
14
+ label: { type: 'string', maxLength: 500 },
15
+ question_type: { type: 'string', enum: ['text', 'qcm'] },
16
+ icon: { type: 'string', maxLength: 40 },
17
+ required: { type: 'boolean' },
18
+ options: { type: 'array', items: { type: 'string', maxLength: 200 } },
19
+ },
20
+ required: ['lab', 'question_id', 'label', 'question_type'],
21
+ additionalProperties: false,
22
+ },
23
+ zodSchema: z.object({
24
+ lab: z.string(),
25
+ question_id: z.number().int().positive(),
26
+ label: z.string().min(1).max(500),
27
+ question_type: z.enum(['text', 'qcm']),
28
+ icon: z.string().max(40).nullable().optional(),
29
+ required: z.boolean().optional(),
30
+ options: z.array(z.string().max(200)).optional(),
31
+ }),
32
+ async handler(args) {
33
+ const p = this.zodSchema.parse(args);
34
+ const { lab, question_id, ...body } = p;
35
+ try {
36
+ const { data } = await http.put(`/mcp/labs/${encodeURIComponent(lab)}/calendar/questions/${question_id}`, body);
37
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
38
+ }
39
+ catch (err) {
40
+ return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
41
+ }
42
+ },
43
+ };
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Tool `update_company` — modifie une societe du Marketplace (par uuid).
3
+ */
4
+ import { z } from 'zod';
5
+ import { http, formatApiError } from '../http.js';
6
+ export const updateCompanyTool = {
7
+ name: 'update_company',
8
+ description: "Modifie une societe du Marketplace (identifiee par son uuid, cf list_companies). Champs optionnels : n'envoie que ce qui change. IMPORTANT : action ecriture, demander confirmation.",
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ lab: { type: 'string' },
13
+ uuid: { type: 'string', description: 'uuid de la societe (list_companies)' },
14
+ name: { type: 'string', maxLength: 255 },
15
+ website: { type: 'string' },
16
+ description: { type: 'string' },
17
+ short_description: { type: 'string' },
18
+ cta_link: { type: 'string' },
19
+ text_cta: { type: 'string', maxLength: 255 },
20
+ color: { type: 'string' },
21
+ company_category_id: { type: 'number', description: 'Nouvelle categorie (list_company_categories)' },
22
+ },
23
+ required: ['lab', 'uuid'],
24
+ additionalProperties: false,
25
+ },
26
+ zodSchema: z.object({
27
+ lab: z.string(),
28
+ uuid: z.string(),
29
+ name: z.string().max(255).optional(),
30
+ website: z.string().url().optional(),
31
+ description: z.string().optional(),
32
+ short_description: z.string().optional(),
33
+ cta_link: z.string().url().optional(),
34
+ text_cta: z.string().max(255).nullable().optional(),
35
+ color: z.string().max(20).optional(),
36
+ company_category_id: z.number().int().positive().optional(),
37
+ }),
38
+ async handler(args) {
39
+ const parsed = this.zodSchema.parse(args);
40
+ const { lab, uuid, ...body } = parsed;
41
+ try {
42
+ const { data } = await http.put(`/mcp/labs/${encodeURIComponent(lab)}/companies/${encodeURIComponent(uuid)}`, body);
43
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
44
+ }
45
+ catch (err) {
46
+ return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
47
+ }
48
+ },
49
+ };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Tool `update_company_category` — renomme une categorie Marketplace.
3
+ */
4
+ import { z } from 'zod';
5
+ import { http, formatApiError } from '../http.js';
6
+ export const updateCompanyCategoryTool = {
7
+ name: 'update_company_category',
8
+ description: "Renomme une categorie du Marketplace (identifiee par son id, cf list_company_categories).",
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ lab: { type: 'string' },
13
+ category_id: { type: 'number', description: 'Id de la categorie (list_company_categories)' },
14
+ name: { type: 'string', maxLength: 255 },
15
+ },
16
+ required: ['lab', 'category_id', 'name'],
17
+ additionalProperties: false,
18
+ },
19
+ zodSchema: z.object({
20
+ lab: z.string(),
21
+ category_id: z.number().int().positive(),
22
+ name: z.string().min(1).max(255),
23
+ }),
24
+ async handler(args) {
25
+ const parsed = this.zodSchema.parse(args);
26
+ try {
27
+ const { data } = await http.put(`/mcp/labs/${encodeURIComponent(parsed.lab)}/company-categories/${parsed.category_id}`, { name: parsed.name });
28
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
29
+ }
30
+ catch (err) {
31
+ return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
32
+ }
33
+ },
34
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Tool `update_funnel` — modifie le nom / l'activation d'un tunnel de vente.
3
+ */
4
+ import { z } from 'zod';
5
+ import { http, formatApiError } from '../http.js';
6
+ export const updateFunnelTool = {
7
+ name: 'update_funnel',
8
+ description: "Modifie un tunnel de vente (nom, activation). funnel_id vient de get_funnel / create_funnel. Passe is_active=false pour desactiver le tunnel sans le supprimer.",
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ lab: { type: 'string' },
13
+ funnel_id: { type: 'number' },
14
+ name: { type: 'string', maxLength: 120 },
15
+ is_active: { type: 'boolean' },
16
+ },
17
+ required: ['lab', 'funnel_id'],
18
+ additionalProperties: false,
19
+ },
20
+ zodSchema: z.object({
21
+ lab: z.string(),
22
+ funnel_id: z.number().int().positive(),
23
+ name: z.string().max(120).nullable().optional(),
24
+ is_active: z.boolean().optional(),
25
+ }),
26
+ async handler(args) {
27
+ const p = this.zodSchema.parse(args);
28
+ const { lab, funnel_id, ...body } = p;
29
+ try {
30
+ const { data } = await http.put(`/mcp/labs/${encodeURIComponent(lab)}/funnels/${funnel_id}`, body);
31
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
32
+ }
33
+ catch (err) {
34
+ return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
35
+ }
36
+ },
37
+ };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Tool `update_lab_affiliation_config` — configure le programme d'affiliation
3
+ * au niveau du Lab entier.
4
+ */
5
+ import { z } from 'zod';
6
+ import { http, formatApiError } from '../http.js';
7
+ export const updateLabAffiliationConfigTool = {
8
+ name: 'update_lab_affiliation_config',
9
+ description: "Configure le programme d'affiliation du Lab entier. affiliation_status = '1' actif / '0' inactif. affiliation_percent = commission %. Les 3 scopes activent l'affiliation sur : paiements one-shot, abonnement au Lab, abonnements internes. affiliation_badge_status = affiche le badge affilie.",
10
+ inputSchema: {
11
+ type: 'object',
12
+ properties: {
13
+ lab: { type: 'string' },
14
+ affiliation_status: { type: 'string', enum: ['0', '1'] },
15
+ affiliation_percent: { type: 'number', minimum: 0, maximum: 100 },
16
+ affiliation_scope_paid_one_shot: { type: 'boolean' },
17
+ affiliation_scope_lab_subscription: { type: 'boolean' },
18
+ affiliation_scope_internal_subscription: { type: 'boolean' },
19
+ affiliation_badge_status: { type: 'string', enum: ['0', '1'] },
20
+ },
21
+ required: ['lab'],
22
+ additionalProperties: false,
23
+ },
24
+ zodSchema: z.object({
25
+ lab: z.string(),
26
+ affiliation_status: z.enum(['0', '1']).optional(),
27
+ affiliation_percent: z.number().min(0).max(100).optional(),
28
+ affiliation_scope_paid_one_shot: z.boolean().optional(),
29
+ affiliation_scope_lab_subscription: z.boolean().optional(),
30
+ affiliation_scope_internal_subscription: z.boolean().optional(),
31
+ affiliation_badge_status: z.enum(['0', '1']).optional(),
32
+ }),
33
+ async handler(args) {
34
+ const p = this.zodSchema.parse(args);
35
+ const { lab, ...body } = p;
36
+ try {
37
+ const { data } = await http.put(`/mcp/labs/${encodeURIComponent(lab)}/affiliation/lab/config`, body);
38
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
39
+ }
40
+ catch (err) {
41
+ return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
42
+ }
43
+ },
44
+ };
@@ -9,15 +9,15 @@ import { http, formatApiError } from '../http.js';
9
9
  const SOCIAL_KEYS = ['instagram', 'tiktok', 'youtube', 'x', 'linkedin', 'facebook', 'whatsapp', 'telegram'];
10
10
  export const updateLinkInBioTool = {
11
11
  name: 'update_link_in_bio',
12
- description: "Upsert de la page Link in Bio (meta). Cree la page si absente. Champs optionnels : slug, display_name, bio, theme (violet/blue/black/pastel), accent_color (#RRGGBB), photo_layout (avatar/banner/portrait), desktop_layout (split/centered), avatar_url, banner_url, portrait_url, socials{instagram, tiktok, youtube, x, linkedin, facebook, whatsapp, telegram}. Attention : changer le slug a un cooldown de 30 jours.",
12
+ description: "Upsert (remplacement) de la page Link in Bio. Cree la page si absente. C'est un upsert COMPLET : tu dois TOUJOURS fournir slug, display_name, photo_layout et theme (fais get_link_in_bio d'abord pour recuperer les valeurs actuelles, puis renvoie-les avec tes modifs). Autres champs : bio, accent_color (#RRGGBB), desktop_layout (split/centered), avatar_url, banner_url, portrait_url, socials{instagram, tiktok, youtube, x, linkedin, facebook, whatsapp, telegram}. theme = light | dark | violet | yellow. photo_layout = avatar | banner | portrait. Les uploads d'images (avatar/banniere) se font via le front — ici on passe des URLs. Attention : changer le slug a un cooldown de 30 jours.",
13
13
  inputSchema: {
14
14
  type: 'object',
15
15
  properties: {
16
16
  lab: { type: 'string' },
17
- slug: { type: 'string', maxLength: 40 },
18
- display_name: { type: 'string', maxLength: 60 },
19
- bio: { type: 'string', maxLength: 300 },
20
- theme: { type: 'string', enum: ['violet', 'blue', 'black', 'pastel'] },
17
+ slug: { type: 'string', minLength: 3, maxLength: 60, description: 'minuscule, ^[a-z][a-z0-9_-]{2,59}$' },
18
+ display_name: { type: 'string', maxLength: 100 },
19
+ bio: { type: 'string', maxLength: 500 },
20
+ theme: { type: 'string', enum: ['light', 'dark', 'violet', 'yellow'] },
21
21
  accent_color: { type: 'string', pattern: '^#[0-9A-Fa-f]{6}$' },
22
22
  photo_layout: { type: 'string', enum: ['avatar', 'banner', 'portrait'] },
23
23
  desktop_layout: { type: 'string', enum: ['split', 'centered'] },
@@ -26,26 +26,26 @@ export const updateLinkInBioTool = {
26
26
  portrait_url: { type: 'string' },
27
27
  socials: {
28
28
  type: 'object',
29
- properties: Object.fromEntries(SOCIAL_KEYS.map((k) => [k, { type: 'string' }])),
29
+ properties: Object.fromEntries(SOCIAL_KEYS.map((k) => [k, { type: 'string', maxLength: 200 }])),
30
30
  additionalProperties: false,
31
31
  },
32
32
  },
33
- required: ['lab'],
33
+ required: ['lab', 'slug', 'display_name', 'photo_layout', 'theme'],
34
34
  additionalProperties: false,
35
35
  },
36
36
  zodSchema: z.object({
37
37
  lab: z.string(),
38
- slug: z.string().max(40).optional(),
39
- display_name: z.string().max(60).optional(),
40
- bio: z.string().max(300).optional(),
41
- theme: z.enum(['violet', 'blue', 'black', 'pastel']).optional(),
38
+ slug: z.string().min(3).max(60),
39
+ display_name: z.string().max(100),
40
+ bio: z.string().max(500).optional(),
41
+ theme: z.enum(['light', 'dark', 'violet', 'yellow']),
42
42
  accent_color: z.string().regex(/^#[0-9A-Fa-f]{6}$/).optional(),
43
- photo_layout: z.enum(['avatar', 'banner', 'portrait']).optional(),
43
+ photo_layout: z.enum(['avatar', 'banner', 'portrait']),
44
44
  desktop_layout: z.enum(['split', 'centered']).optional(),
45
45
  avatar_url: z.string().optional(),
46
46
  banner_url: z.string().optional(),
47
47
  portrait_url: z.string().optional(),
48
- socials: z.record(z.string()).optional(),
48
+ socials: z.record(z.string().max(200)).optional(),
49
49
  }),
50
50
  async handler(args) {
51
51
  const parsed = this.zodSchema.parse(args);
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Tool `update_newsletter_edition` — édite un draft de newsletter.
3
+ */
4
+ import { z } from 'zod';
5
+ import { http, formatApiError } from '../http.js';
6
+ export const updateNewsletterEditionTool = {
7
+ name: 'update_newsletter_edition',
8
+ description: "Modifie une edition de newsletter (title, subject, body_html, access, audience). Une edition deja envoyee ne peut plus etre modifiee. edition_id vient de list_newsletter_editions. IMPORTANT : action ecriture.",
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ lab: { type: 'string' },
13
+ edition_id: { type: 'number' },
14
+ title: { type: 'string', maxLength: 255 },
15
+ subject: { type: 'string', maxLength: 255 },
16
+ body_html: { type: 'string', description: 'Contenu HTML de l\'edition' },
17
+ access: { type: 'string', enum: ['free', 'premium'] },
18
+ audience: { type: 'string', enum: ['all', 'premium', 'free', 'lab_members'] },
19
+ },
20
+ required: ['lab', 'edition_id'],
21
+ additionalProperties: false,
22
+ },
23
+ zodSchema: z.object({
24
+ lab: z.string(),
25
+ edition_id: z.number().int().positive(),
26
+ title: z.string().max(255).optional(),
27
+ subject: z.string().max(255).optional(),
28
+ body_html: z.string().nullable().optional(),
29
+ access: z.enum(['free', 'premium']).optional(),
30
+ audience: z.enum(['all', 'premium', 'free', 'lab_members']).optional(),
31
+ }),
32
+ async handler(args) {
33
+ const p = this.zodSchema.parse(args);
34
+ const { lab, edition_id, ...body } = p;
35
+ try {
36
+ const { data } = await http.put(`/mcp/labs/${encodeURIComponent(lab)}/newsletter/editions/${edition_id}`, body);
37
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
38
+ }
39
+ catch (err) {
40
+ return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
41
+ }
42
+ },
43
+ };
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Tool `update_newsletter_settings` — met à jour les réglages clés de la
3
+ * newsletter (sous-ensemble curé ; l'éditeur de landing page complet reste
4
+ * sur le front).
5
+ */
6
+ import { z } from 'zod';
7
+ import { http, formatApiError } from '../http.js';
8
+ export const updateNewsletterSettingsTool = {
9
+ name: 'update_newsletter_settings',
10
+ description: "Met a jour les reglages cles de la newsletter (titre, tagline, auteur, apparence, CTA, email de bienvenue, mode d'envoi). N'envoie que ce que tu veux changer. L'editeur de landing page complet (perks / temoignages / FAQ / sections) reste sur le front.",
11
+ inputSchema: {
12
+ type: 'object',
13
+ properties: {
14
+ lab: { type: 'string' },
15
+ title: { type: 'string', maxLength: 191 },
16
+ tagline: { type: 'string', maxLength: 2000 },
17
+ author_name: { type: 'string', maxLength: 191 },
18
+ author_bio: { type: 'string', maxLength: 2000 },
19
+ accent_color: { type: 'string', maxLength: 16 },
20
+ background: { type: 'string', enum: ['white', 'cream', 'dark'] },
21
+ cta_primary_text: { type: 'string', maxLength: 191 },
22
+ cta_secondary_text: { type: 'string', maxLength: 191 },
23
+ show_secondary_cta: { type: 'boolean' },
24
+ footer_text: { type: 'string', maxLength: 2000 },
25
+ unsubscribe_label: { type: 'string', maxLength: 100 },
26
+ welcome_email_subject: { type: 'string', maxLength: 255 },
27
+ welcome_email_html: { type: 'string', maxLength: 50000 },
28
+ welcome_email_enabled: { type: 'boolean' },
29
+ send_mode: { type: 'string', enum: ['standard', 'custom_domain'] },
30
+ },
31
+ required: ['lab'],
32
+ additionalProperties: false,
33
+ },
34
+ zodSchema: z.object({
35
+ lab: z.string(),
36
+ title: z.string().max(191).optional(),
37
+ tagline: z.string().max(2000).nullable().optional(),
38
+ author_name: z.string().max(191).nullable().optional(),
39
+ author_bio: z.string().max(2000).nullable().optional(),
40
+ accent_color: z.string().max(16).optional(),
41
+ background: z.enum(['white', 'cream', 'dark']).optional(),
42
+ cta_primary_text: z.string().max(191).optional(),
43
+ cta_secondary_text: z.string().max(191).optional(),
44
+ show_secondary_cta: z.boolean().optional(),
45
+ footer_text: z.string().max(2000).nullable().optional(),
46
+ unsubscribe_label: z.string().max(100).nullable().optional(),
47
+ welcome_email_subject: z.string().max(255).nullable().optional(),
48
+ welcome_email_html: z.string().max(50000).nullable().optional(),
49
+ welcome_email_enabled: z.boolean().optional(),
50
+ send_mode: z.enum(['standard', 'custom_domain']).optional(),
51
+ }),
52
+ async handler(args) {
53
+ const p = this.zodSchema.parse(args);
54
+ const { lab, ...body } = p;
55
+ try {
56
+ const { data } = await http.put(`/mcp/labs/${encodeURIComponent(lab)}/newsletter/settings`, body);
57
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
58
+ }
59
+ catch (err) {
60
+ return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
61
+ }
62
+ },
63
+ };
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import { http, formatApiError } from '../http.js';
3
3
  export const updatePostTool = {
4
4
  name: 'update_post',
5
- description: "Modifie un post existant (titre / corps / categorie). Champs optionnels : n'envoie que ce que tu veux changer. IMPORTANT : action ecriture, demander confirmation.",
5
+ description: "Modifie un post existant (titre / corps / categorie / produit Boutique). Champs optionnels : n'envoie que ce que tu veux changer. shop_id : passe l'id d'un produit (list_shops) pour l'attacher, ou null pour retirer le produit du post. IMPORTANT : action ecriture, demander confirmation.",
6
6
  inputSchema: {
7
7
  type: 'object',
8
8
  properties: {
@@ -11,6 +11,7 @@ export const updatePostTool = {
11
11
  title: { type: 'string', maxLength: 255 },
12
12
  body: { type: 'string' },
13
13
  category_id: { type: 'number' },
14
+ shop_id: { type: ['number', 'null'], description: "Id d'un produit Boutique a mettre en avant (list_shops), ou null pour le retirer." },
14
15
  },
15
16
  required: ['lab', 'post_id'],
16
17
  additionalProperties: false,
@@ -21,6 +22,7 @@ export const updatePostTool = {
21
22
  title: z.string().max(255).optional(),
22
23
  body: z.string().optional(),
23
24
  category_id: z.number().int().positive().optional(),
25
+ shop_id: z.number().int().positive().nullable().optional(),
24
26
  }),
25
27
  async handler(args) {
26
28
  const parsed = this.zodSchema.parse(args);
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Tool `update_product_affiliation_config` — active/configure l'affiliation
3
+ * d'un produit (boutique ou agent IA).
4
+ */
5
+ import { z } from 'zod';
6
+ import { http, formatApiError } from '../http.js';
7
+ const PRODUCT_TYPES = ['shop_product', 'agent_ai'];
8
+ export const updateProductAffiliationConfigTool = {
9
+ name: 'update_product_affiliation_config',
10
+ description: "Active / configure l'affiliation d'un produit (boutique ou agent IA custom). enabled = activer, percent = commission % reversee a l'affilie, visibility = qui peut devenir affilie (members_only = membres approuves, open = tout utilisateur connecte, approval_required = sur validation manuelle).",
11
+ inputSchema: {
12
+ type: 'object',
13
+ properties: {
14
+ lab: { type: 'string' },
15
+ product_type: { type: 'string', enum: [...PRODUCT_TYPES] },
16
+ product_id: { type: 'number' },
17
+ affiliation_enabled: { type: 'boolean' },
18
+ affiliation_percent: { type: 'number', minimum: 0, maximum: 100 },
19
+ affiliation_visibility: { type: 'string', enum: ['members_only', 'open', 'approval_required'] },
20
+ },
21
+ required: ['lab', 'product_type', 'product_id'],
22
+ additionalProperties: false,
23
+ },
24
+ zodSchema: z.object({
25
+ lab: z.string(),
26
+ product_type: z.enum(PRODUCT_TYPES),
27
+ product_id: z.number().int().positive(),
28
+ affiliation_enabled: z.boolean().optional(),
29
+ affiliation_percent: z.number().min(0).max(100).optional(),
30
+ affiliation_visibility: z.enum(['members_only', 'open', 'approval_required']).optional(),
31
+ }),
32
+ async handler(args) {
33
+ const p = this.zodSchema.parse(args);
34
+ const { lab, product_type, product_id, ...body } = p;
35
+ try {
36
+ const { data } = await http.put(`/mcp/labs/${encodeURIComponent(lab)}/affiliation/products/${product_type}/${product_id}/config`, body);
37
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
38
+ }
39
+ catch (err) {
40
+ return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
41
+ }
42
+ },
43
+ };
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import { http, formatApiError } from '../http.js';
3
3
  export const updateShopProductTool = {
4
4
  name: 'update_shop_product',
5
- description: "Modifie un produit boutique (titre, prix, description, publication). Champs optionnels. Prix en centimes.",
5
+ description: "Modifie un produit boutique (titre, prix, description, publication, type d'offre). Champs optionnels. Prix en centimes. Passe offer_type=formation + course_id (list_classes) pour que l'achat debloque un cours ; tout autre offer_type detache le cours lie.",
6
6
  inputSchema: {
7
7
  type: 'object',
8
8
  properties: {
@@ -12,6 +12,8 @@ export const updateShopProductTool = {
12
12
  short_description: { type: 'string' },
13
13
  description: { type: 'string' },
14
14
  price_cents: { type: 'number', minimum: 0 },
15
+ offer_type: { type: 'string', enum: ['digital', 'calendar', 'formation'] },
16
+ course_id: { type: 'number', description: "Id d'un cours du Lab (list_classes) — requis/utilise quand offer_type=formation." },
15
17
  payment_mode: { type: 'string', enum: ['external', 'stripe'] },
16
18
  payment_link_text: { type: 'string', maxLength: 255 },
17
19
  support_email: { type: 'string', format: 'email' },
@@ -27,6 +29,8 @@ export const updateShopProductTool = {
27
29
  short_description: z.string().optional(),
28
30
  description: z.string().optional(),
29
31
  price_cents: z.number().int().min(0).nullable().optional(),
32
+ offer_type: z.enum(['digital', 'calendar', 'formation']).optional(),
33
+ course_id: z.number().int().positive().nullable().optional(),
30
34
  payment_mode: z.enum(['external', 'stripe']).optional(),
31
35
  payment_link_text: z.string().max(255).nullable().optional(),
32
36
  support_email: z.string().email().nullable().optional(),
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Tool `update_smart_join_question` — modifie une question Smart Join.
3
+ */
4
+ import { z } from 'zod';
5
+ import { http, formatApiError } from '../http.js';
6
+ const TYPES = ['email', 'short_text', 'long_text', 'phone', 'number', 'single_choice', 'multiple_choice'];
7
+ export const updateSmartJoinQuestionTool = {
8
+ name: 'update_smart_join_question',
9
+ description: "Modifie une question de qualification Smart Join. question_id vient de get_smart_join. Pour single_choice / multiple_choice, fournis options.",
10
+ inputSchema: {
11
+ type: 'object',
12
+ properties: {
13
+ lab: { type: 'string' },
14
+ question_id: { type: 'number' },
15
+ label: { type: 'string', maxLength: 500 },
16
+ type: { type: 'string', enum: [...TYPES] },
17
+ options: { type: 'array', items: { type: 'string' } },
18
+ },
19
+ required: ['lab', 'question_id'],
20
+ additionalProperties: false,
21
+ },
22
+ zodSchema: z.object({
23
+ lab: z.string(),
24
+ question_id: z.number().int().positive(),
25
+ label: z.string().max(500).optional(),
26
+ type: z.enum(TYPES).optional(),
27
+ options: z.array(z.string()).optional(),
28
+ }),
29
+ async handler(args) {
30
+ const p = this.zodSchema.parse(args);
31
+ const { lab, question_id, ...body } = p;
32
+ try {
33
+ const { data } = await http.put(`/mcp/labs/${encodeURIComponent(lab)}/smart-join/questions/${question_id}`, body);
34
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
35
+ }
36
+ catch (err) {
37
+ return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
38
+ }
39
+ },
40
+ };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Tool `update_smart_join_settings` — active / désactive le plug-in Smart Join.
3
+ */
4
+ import { z } from 'zod';
5
+ import { http, formatApiError } from '../http.js';
6
+ export const updateSmartJoinSettingsTool = {
7
+ name: 'update_smart_join_settings',
8
+ description: "Active ou desactive le plug-in Smart Join (pop-up de questions a l'inscription). is_active = true active le questionnaire de qualification.",
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ lab: { type: 'string' },
13
+ is_active: { type: 'boolean' },
14
+ },
15
+ required: ['lab', 'is_active'],
16
+ additionalProperties: false,
17
+ },
18
+ zodSchema: z.object({ lab: z.string(), is_active: z.boolean() }),
19
+ async handler(args) {
20
+ const p = this.zodSchema.parse(args);
21
+ try {
22
+ const { data } = await http.put(`/mcp/labs/${encodeURIComponent(p.lab)}/smart-join`, { is_active: p.is_active });
23
+ return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
24
+ }
25
+ catch (err) {
26
+ return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
27
+ }
28
+ },
29
+ };