@connect-xlab/mcp-server 0.2.1 → 0.3.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/dist/index.js +95 -0
- package/dist/tools/approveAssistantAction.js +40 -0
- package/dist/tools/correctAssistantAction.js +36 -0
- package/dist/tools/createDmSequence.js +36 -0
- package/dist/tools/createLinkInBioBlock.js +27 -18
- package/dist/tools/createQuiz.js +38 -0
- package/dist/tools/createQuizAnswer.js +42 -0
- package/dist/tools/createQuizItem.js +46 -0
- package/dist/tools/createQuizProfile.js +50 -0
- package/dist/tools/createShopProduct.js +7 -5
- package/dist/tools/deleteQuiz.js +33 -0
- package/dist/tools/deleteQuizAnswer.js +37 -0
- package/dist/tools/deleteQuizItem.js +35 -0
- package/dist/tools/deleteQuizProfile.js +35 -0
- package/dist/tools/getAssistantAction.js +33 -0
- package/dist/tools/getAssistantProducts.js +31 -0
- package/dist/tools/getAssistantSettings.js +31 -0
- package/dist/tools/getAssistantSummary.js +36 -0
- package/dist/tools/getDmSequence.js +33 -0
- package/dist/tools/getDmSequenceSettings.js +31 -0
- package/dist/tools/getDmSequenceStats.js +38 -0
- package/dist/tools/getLinkInBioCatalog.js +31 -0
- package/dist/tools/getQuiz.js +33 -0
- package/dist/tools/getQuizLead.js +35 -0
- package/dist/tools/getQuizSettings.js +31 -0
- package/dist/tools/getQuizStats.js +33 -0
- package/dist/tools/listAssistantActions.js +40 -0
- package/dist/tools/listDmEnrollments.js +40 -0
- package/dist/tools/listDmSequenceTargetPosts.js +31 -0
- package/dist/tools/listDmSequences.js +31 -0
- package/dist/tools/listQuizLeads.js +48 -0
- package/dist/tools/listQuizTemplates.js +31 -0
- package/dist/tools/listQuizzes.js +31 -0
- package/dist/tools/manageDmEnrollment.js +36 -0
- package/dist/tools/previewDmSequence.js +40 -0
- package/dist/tools/rejectAssistantAction.js +33 -0
- package/dist/tools/reorderQuizItems.js +36 -0
- package/dist/tools/requestAssistantPostDraft.js +38 -0
- package/dist/tools/setDmSequenceStatus.js +36 -0
- package/dist/tools/setQuizPublished.js +35 -0
- package/dist/tools/updateAssistantProducts.js +34 -0
- package/dist/tools/updateAssistantSettings.js +90 -0
- package/dist/tools/updateDmSequence.js +44 -0
- package/dist/tools/updateDmSequenceSettings.js +44 -0
- package/dist/tools/updateLinkInBioBlock.js +13 -8
- package/dist/tools/updateQuiz.js +56 -0
- package/dist/tools/updateQuizAnswer.js +44 -0
- package/dist/tools/updateQuizItem.js +46 -0
- package/dist/tools/updateQuizProfile.js +52 -0
- package/dist/tools/updateQuizSettings.js +34 -0
- package/dist/tools/updateShopProduct.js +7 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -152,6 +152,52 @@ import { deleteSmartJoinQuestionTool } from './tools/deleteSmartJoinQuestion.js'
|
|
|
152
152
|
import { duplicateSmartJoinQuestionTool } from './tools/duplicateSmartJoinQuestion.js';
|
|
153
153
|
import { listSmartJoinResponsesTool } from './tools/listSmartJoinResponses.js';
|
|
154
154
|
import { clearSmartJoinResponsesTool } from './tools/clearSmartJoinResponses.js';
|
|
155
|
+
import { getLinkInBioCatalogTool } from './tools/getLinkInBioCatalog.js';
|
|
156
|
+
import { getQuizSettingsTool } from './tools/getQuizSettings.js';
|
|
157
|
+
import { updateQuizSettingsTool } from './tools/updateQuizSettings.js';
|
|
158
|
+
import { listQuizTemplatesTool } from './tools/listQuizTemplates.js';
|
|
159
|
+
import { listQuizzesTool } from './tools/listQuizzes.js';
|
|
160
|
+
import { createQuizTool } from './tools/createQuiz.js';
|
|
161
|
+
import { getQuizTool } from './tools/getQuiz.js';
|
|
162
|
+
import { updateQuizTool } from './tools/updateQuiz.js';
|
|
163
|
+
import { deleteQuizTool } from './tools/deleteQuiz.js';
|
|
164
|
+
import { setQuizPublishedTool } from './tools/setQuizPublished.js';
|
|
165
|
+
import { createQuizItemTool } from './tools/createQuizItem.js';
|
|
166
|
+
import { updateQuizItemTool } from './tools/updateQuizItem.js';
|
|
167
|
+
import { deleteQuizItemTool } from './tools/deleteQuizItem.js';
|
|
168
|
+
import { reorderQuizItemsTool } from './tools/reorderQuizItems.js';
|
|
169
|
+
import { createQuizAnswerTool } from './tools/createQuizAnswer.js';
|
|
170
|
+
import { updateQuizAnswerTool } from './tools/updateQuizAnswer.js';
|
|
171
|
+
import { deleteQuizAnswerTool } from './tools/deleteQuizAnswer.js';
|
|
172
|
+
import { createQuizProfileTool } from './tools/createQuizProfile.js';
|
|
173
|
+
import { updateQuizProfileTool } from './tools/updateQuizProfile.js';
|
|
174
|
+
import { deleteQuizProfileTool } from './tools/deleteQuizProfile.js';
|
|
175
|
+
import { listQuizLeadsTool } from './tools/listQuizLeads.js';
|
|
176
|
+
import { getQuizLeadTool } from './tools/getQuizLead.js';
|
|
177
|
+
import { getQuizStatsTool } from './tools/getQuizStats.js';
|
|
178
|
+
import { getDmSequenceSettingsTool } from './tools/getDmSequenceSettings.js';
|
|
179
|
+
import { updateDmSequenceSettingsTool } from './tools/updateDmSequenceSettings.js';
|
|
180
|
+
import { listDmSequenceTargetPostsTool } from './tools/listDmSequenceTargetPosts.js';
|
|
181
|
+
import { listDmSequencesTool } from './tools/listDmSequences.js';
|
|
182
|
+
import { createDmSequenceTool } from './tools/createDmSequence.js';
|
|
183
|
+
import { getDmSequenceTool } from './tools/getDmSequence.js';
|
|
184
|
+
import { updateDmSequenceTool } from './tools/updateDmSequence.js';
|
|
185
|
+
import { setDmSequenceStatusTool } from './tools/setDmSequenceStatus.js';
|
|
186
|
+
import { previewDmSequenceTool } from './tools/previewDmSequence.js';
|
|
187
|
+
import { getDmSequenceStatsTool } from './tools/getDmSequenceStats.js';
|
|
188
|
+
import { listDmEnrollmentsTool } from './tools/listDmEnrollments.js';
|
|
189
|
+
import { manageDmEnrollmentTool } from './tools/manageDmEnrollment.js';
|
|
190
|
+
import { getAssistantSettingsTool } from './tools/getAssistantSettings.js';
|
|
191
|
+
import { updateAssistantSettingsTool } from './tools/updateAssistantSettings.js';
|
|
192
|
+
import { getAssistantProductsTool } from './tools/getAssistantProducts.js';
|
|
193
|
+
import { updateAssistantProductsTool } from './tools/updateAssistantProducts.js';
|
|
194
|
+
import { listAssistantActionsTool } from './tools/listAssistantActions.js';
|
|
195
|
+
import { getAssistantActionTool } from './tools/getAssistantAction.js';
|
|
196
|
+
import { approveAssistantActionTool } from './tools/approveAssistantAction.js';
|
|
197
|
+
import { rejectAssistantActionTool } from './tools/rejectAssistantAction.js';
|
|
198
|
+
import { correctAssistantActionTool } from './tools/correctAssistantAction.js';
|
|
199
|
+
import { requestAssistantPostDraftTool } from './tools/requestAssistantPostDraft.js';
|
|
200
|
+
import { getAssistantSummaryTool } from './tools/getAssistantSummary.js';
|
|
155
201
|
const tools = [
|
|
156
202
|
listLabsTool,
|
|
157
203
|
listMembersTool,
|
|
@@ -231,6 +277,7 @@ const tools = [
|
|
|
231
277
|
updateLinkInBioBlockTool,
|
|
232
278
|
deleteLinkInBioBlockTool,
|
|
233
279
|
reorderLinkInBioBlocksTool,
|
|
280
|
+
getLinkInBioCatalogTool,
|
|
234
281
|
// Marketplace (societes + categories)
|
|
235
282
|
listCompaniesTool,
|
|
236
283
|
createCompanyTool,
|
|
@@ -300,6 +347,54 @@ const tools = [
|
|
|
300
347
|
duplicateSmartJoinQuestionTool,
|
|
301
348
|
listSmartJoinResponsesTool,
|
|
302
349
|
clearSmartJoinResponsesTool,
|
|
350
|
+
// Quiz (capture + qualification de prospects)
|
|
351
|
+
getQuizSettingsTool,
|
|
352
|
+
updateQuizSettingsTool,
|
|
353
|
+
listQuizTemplatesTool,
|
|
354
|
+
listQuizzesTool,
|
|
355
|
+
createQuizTool,
|
|
356
|
+
getQuizTool,
|
|
357
|
+
updateQuizTool,
|
|
358
|
+
deleteQuizTool,
|
|
359
|
+
setQuizPublishedTool,
|
|
360
|
+
createQuizItemTool,
|
|
361
|
+
updateQuizItemTool,
|
|
362
|
+
deleteQuizItemTool,
|
|
363
|
+
reorderQuizItemsTool,
|
|
364
|
+
createQuizAnswerTool,
|
|
365
|
+
updateQuizAnswerTool,
|
|
366
|
+
deleteQuizAnswerTool,
|
|
367
|
+
createQuizProfileTool,
|
|
368
|
+
updateQuizProfileTool,
|
|
369
|
+
deleteQuizProfileTool,
|
|
370
|
+
listQuizLeadsTool,
|
|
371
|
+
getQuizLeadTool,
|
|
372
|
+
getQuizStatsTool,
|
|
373
|
+
// Sequences DM (DM programmes aux membres)
|
|
374
|
+
getDmSequenceSettingsTool,
|
|
375
|
+
updateDmSequenceSettingsTool,
|
|
376
|
+
listDmSequenceTargetPostsTool,
|
|
377
|
+
listDmSequencesTool,
|
|
378
|
+
createDmSequenceTool,
|
|
379
|
+
getDmSequenceTool,
|
|
380
|
+
updateDmSequenceTool,
|
|
381
|
+
setDmSequenceStatusTool,
|
|
382
|
+
previewDmSequenceTool,
|
|
383
|
+
getDmSequenceStatsTool,
|
|
384
|
+
listDmEnrollmentsTool,
|
|
385
|
+
manageDmEnrollmentTool,
|
|
386
|
+
// Lou (assistant IA de l'owner)
|
|
387
|
+
getAssistantSettingsTool,
|
|
388
|
+
updateAssistantSettingsTool,
|
|
389
|
+
getAssistantProductsTool,
|
|
390
|
+
updateAssistantProductsTool,
|
|
391
|
+
listAssistantActionsTool,
|
|
392
|
+
getAssistantActionTool,
|
|
393
|
+
approveAssistantActionTool,
|
|
394
|
+
rejectAssistantActionTool,
|
|
395
|
+
correctAssistantActionTool,
|
|
396
|
+
requestAssistantPostDraftTool,
|
|
397
|
+
getAssistantSummaryTool,
|
|
303
398
|
];
|
|
304
399
|
const server = new Server({ name: 'connectxlab', version: '0.1.0' }, { capabilities: { tools: {} } });
|
|
305
400
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool `approve_assistant_action` — valide et execute une proposition de Lou.
|
|
3
|
+
* Scope : assistant.write.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { http, formatApiError } from '../http.js';
|
|
7
|
+
export const approveAssistantActionTool = {
|
|
8
|
+
name: 'approve_assistant_action',
|
|
9
|
+
description: "Valide ET execute une proposition de Lou (envoie le DM / la reponse, publie le post). body / title / category_id optionnels pour retoucher avant envoi. Action visible par les membres : la faire confirmer par l'owner.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
lab: { type: 'string', description: 'group_url ou id du Lab' },
|
|
14
|
+
uuid: { type: 'string', description: 'uuid de la proposition (list_assistant_actions)' },
|
|
15
|
+
body: { type: 'string', maxLength: 5000 },
|
|
16
|
+
title: { type: 'string', maxLength: 255 },
|
|
17
|
+
category_id: { type: 'number', minimum: 1 },
|
|
18
|
+
},
|
|
19
|
+
required: ['lab', 'uuid'],
|
|
20
|
+
additionalProperties: false,
|
|
21
|
+
},
|
|
22
|
+
zodSchema: z.object({
|
|
23
|
+
lab: z.string(),
|
|
24
|
+
uuid: z.string(),
|
|
25
|
+
body: z.string().max(5000).nullable().optional(),
|
|
26
|
+
title: z.string().max(255).nullable().optional(),
|
|
27
|
+
category_id: z.number().int().min(1).optional(),
|
|
28
|
+
}),
|
|
29
|
+
async handler(args) {
|
|
30
|
+
const { lab, uuid, ...body } = this.zodSchema.parse(args);
|
|
31
|
+
const p = { lab, uuid };
|
|
32
|
+
try {
|
|
33
|
+
const { data } = await http.post(`/mcp/labs/${encodeURIComponent(p.lab)}/assistant/actions/${encodeURIComponent(p.uuid)}/approve`, 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,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool `correct_assistant_action` — corrige une reponse deja envoyee par Lou.
|
|
3
|
+
* Scope : assistant.write.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { http, formatApiError } from '../http.js';
|
|
7
|
+
export const correctAssistantActionTool = {
|
|
8
|
+
name: 'correct_assistant_action',
|
|
9
|
+
description: "Corrige une reponse que Lou a deja envoyee seule (modes assisted / autopilot) : remplace le contenu publie et enregistre la correction pour que Lou apprenne.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
lab: { type: 'string', description: 'group_url ou id du Lab' },
|
|
14
|
+
uuid: { type: 'string', description: 'uuid de la proposition (list_assistant_actions)' },
|
|
15
|
+
body: { type: 'string', maxLength: 5000 },
|
|
16
|
+
},
|
|
17
|
+
required: ['lab', 'uuid', 'body'],
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
},
|
|
20
|
+
zodSchema: z.object({
|
|
21
|
+
lab: z.string(),
|
|
22
|
+
uuid: z.string(),
|
|
23
|
+
body: z.string().max(5000),
|
|
24
|
+
}),
|
|
25
|
+
async handler(args) {
|
|
26
|
+
const { lab, uuid, ...body } = this.zodSchema.parse(args);
|
|
27
|
+
const p = { lab, uuid };
|
|
28
|
+
try {
|
|
29
|
+
const { data } = await http.put(`/mcp/labs/${encodeURIComponent(p.lab)}/assistant/actions/${encodeURIComponent(p.uuid)}/correct`, body);
|
|
30
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool `create_dm_sequence` — cree une sequence DM (brouillon).
|
|
3
|
+
* Scope : dm_sequences.write.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { http, formatApiError } from '../http.js';
|
|
7
|
+
export const createDmSequenceTool = {
|
|
8
|
+
name: 'create_dm_sequence',
|
|
9
|
+
description: "Cree une sequence DM en brouillon. template = welcome (declenchee a l'arrivee d'un nouveau membre) ou keyword (declenchee quand un membre commente un mot-cle sous une publication). Configurer ensuite avec update_dm_sequence puis publier avec set_dm_sequence_status.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
lab: { type: 'string', description: 'group_url ou id du Lab' },
|
|
14
|
+
name: { type: 'string', maxLength: 120 },
|
|
15
|
+
template: { type: 'string', enum: ['welcome', 'keyword'] },
|
|
16
|
+
},
|
|
17
|
+
required: ['lab', 'name', 'template'],
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
},
|
|
20
|
+
zodSchema: z.object({
|
|
21
|
+
lab: z.string(),
|
|
22
|
+
name: z.string().max(120),
|
|
23
|
+
template: z.enum(['welcome', 'keyword']),
|
|
24
|
+
}),
|
|
25
|
+
async handler(args) {
|
|
26
|
+
const { lab, ...body } = this.zodSchema.parse(args);
|
|
27
|
+
const p = { lab };
|
|
28
|
+
try {
|
|
29
|
+
const { data } = await http.post(`/mcp/labs/${encodeURIComponent(p.lab)}/dm-sequences/sequences`, body);
|
|
30
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
};
|
|
@@ -1,45 +1,54 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tool `create_link_in_bio_block` — ajoute un bloc a la page :
|
|
3
|
-
* - kind=external : lien URL libre (
|
|
4
|
-
* - kind=product :
|
|
5
|
-
* - kind=lab :
|
|
3
|
+
* - kind=external : lien URL libre (url)
|
|
4
|
+
* - kind=product : offre du Lab (sellable_type + sellable_id)
|
|
5
|
+
* - kind=lab : autre Lab de l'owner (lab_group_id)
|
|
6
|
+
* - kind=quiz : quiz du Lab (quiz_id) — l'URL publique /quiz/{public_key}
|
|
7
|
+
* est resolue cote API, jamais par le client.
|
|
6
8
|
*
|
|
7
|
-
*
|
|
9
|
+
* Les ids se trouvent via get_link_in_bio_catalog. Position ajoutee
|
|
10
|
+
* automatiquement en fin de liste.
|
|
8
11
|
*/
|
|
9
12
|
import { z } from 'zod';
|
|
10
13
|
import { http, formatApiError } from '../http.js';
|
|
11
14
|
const SELLABLE_TYPES = ['agent_ai', 'group_shop', 'newsletter', 'podcast_show', 'lab_channel'];
|
|
15
|
+
const KINDS = ['external', 'product', 'lab', 'quiz'];
|
|
12
16
|
export const createLinkInBioBlockTool = {
|
|
13
17
|
name: 'create_link_in_bio_block',
|
|
14
|
-
description: "Ajoute un bloc a la page Link in Bio.
|
|
15
|
-
"- kind=external : lien URL libre (
|
|
16
|
-
"- kind=product :
|
|
17
|
-
"- kind=lab :
|
|
18
|
-
"
|
|
18
|
+
description: "Ajoute un bloc a la page Link in Bio (title requis). Quatre types :\n" +
|
|
19
|
+
"- kind=external : lien URL libre (url requis)\n" +
|
|
20
|
+
"- kind=product : offre du Lab (sellable_type + sellable_id requis, sellable_type dans agent_ai/group_shop/newsletter/podcast_show/lab_channel)\n" +
|
|
21
|
+
"- kind=lab : autre Lab de l'owner (lab_group_id requis)\n" +
|
|
22
|
+
"- kind=quiz : quiz du Lab (quiz_id requis). Le bloc reste masque sur la page publique tant que le quiz n'est pas publie et le plug-in Quiz active.\n" +
|
|
23
|
+
"Les ids se trouvent via get_link_in_bio_catalog. Champs optionnels : subtitle, image_url. Position en fin de liste (utiliser reorder pour changer).",
|
|
19
24
|
inputSchema: {
|
|
20
25
|
type: 'object',
|
|
21
26
|
properties: {
|
|
22
27
|
lab: { type: 'string' },
|
|
23
|
-
kind: { type: 'string', enum: [
|
|
24
|
-
title: { type: 'string', maxLength:
|
|
25
|
-
subtitle: { type: 'string', maxLength:
|
|
26
|
-
|
|
28
|
+
kind: { type: 'string', enum: [...KINDS] },
|
|
29
|
+
title: { type: 'string', maxLength: 200 },
|
|
30
|
+
subtitle: { type: 'string', maxLength: 300 },
|
|
31
|
+
url: { type: 'string', description: 'kind=external : URL du lien' },
|
|
27
32
|
image_url: { type: 'string' },
|
|
28
33
|
sellable_type: { type: 'string', enum: [...SELLABLE_TYPES] },
|
|
29
34
|
sellable_id: { type: 'number', minimum: 1 },
|
|
35
|
+
lab_group_id: { type: 'number', minimum: 1, description: "kind=lab : id d'un autre Lab de l'owner" },
|
|
36
|
+
quiz_id: { type: 'number', minimum: 1, description: 'kind=quiz : id du quiz' },
|
|
30
37
|
},
|
|
31
|
-
required: ['lab', 'kind'],
|
|
38
|
+
required: ['lab', 'kind', 'title'],
|
|
32
39
|
additionalProperties: false,
|
|
33
40
|
},
|
|
34
41
|
zodSchema: z.object({
|
|
35
42
|
lab: z.string(),
|
|
36
|
-
kind: z.enum(
|
|
37
|
-
title: z.string().max(
|
|
38
|
-
subtitle: z.string().max(
|
|
39
|
-
|
|
43
|
+
kind: z.enum(KINDS),
|
|
44
|
+
title: z.string().max(200),
|
|
45
|
+
subtitle: z.string().max(300).optional(),
|
|
46
|
+
url: z.string().optional(),
|
|
40
47
|
image_url: z.string().optional(),
|
|
41
48
|
sellable_type: z.enum(SELLABLE_TYPES).optional(),
|
|
42
49
|
sellable_id: z.number().int().positive().optional(),
|
|
50
|
+
lab_group_id: z.number().int().positive().optional(),
|
|
51
|
+
quiz_id: z.number().int().positive().optional(),
|
|
43
52
|
}),
|
|
44
53
|
async handler(args) {
|
|
45
54
|
const parsed = this.zodSchema.parse(args);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool `create_quiz` — cree un quiz (brouillon).
|
|
3
|
+
* Scope : quiz.write.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { http, formatApiError } from '../http.js';
|
|
7
|
+
export const createQuizTool = {
|
|
8
|
+
name: 'create_quiz',
|
|
9
|
+
description: "Cree un quiz en brouillon. slug unique dans le Lab (lettres, chiffres, - et _). template optionnel (key d'un modele available de list_quiz_templates) : pre-remplit questions, reponses et profils. Ensuite : create_quiz_item / create_quiz_answer / create_quiz_profile puis set_quiz_published.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
lab: { type: 'string', description: 'group_url ou id du Lab' },
|
|
14
|
+
slug: { type: 'string', maxLength: 80, description: 'identifiant URL (alpha_dash)' },
|
|
15
|
+
title: { type: 'string', maxLength: 255 },
|
|
16
|
+
template: { type: 'string', description: 'key d\'un modele (list_quiz_templates)' },
|
|
17
|
+
},
|
|
18
|
+
required: ['lab', 'slug', 'title'],
|
|
19
|
+
additionalProperties: false,
|
|
20
|
+
},
|
|
21
|
+
zodSchema: z.object({
|
|
22
|
+
lab: z.string(),
|
|
23
|
+
slug: z.string().max(80),
|
|
24
|
+
title: z.string().max(255),
|
|
25
|
+
template: z.string().nullable().optional(),
|
|
26
|
+
}),
|
|
27
|
+
async handler(args) {
|
|
28
|
+
const { lab, ...body } = this.zodSchema.parse(args);
|
|
29
|
+
const p = { lab };
|
|
30
|
+
try {
|
|
31
|
+
const { data } = await http.post(`/mcp/labs/${encodeURIComponent(p.lab)}/quiz/quizzes`, body);
|
|
32
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool `create_quiz_answer` — ajoute une reponse a une question.
|
|
3
|
+
* Scope : quiz.write.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { http, formatApiError } from '../http.js';
|
|
7
|
+
export const createQuizAnswerTool = {
|
|
8
|
+
name: 'create_quiz_answer',
|
|
9
|
+
description: "Ajoute une reponse a une question (max 8). points (0 a 4) sont credites au profil profile_id : le profil qui cumule le plus de points devient le resultat du prospect. Un profil doit etre atteignable par au moins une reponse notee pour pouvoir publier.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
lab: { type: 'string', description: 'group_url ou id du Lab' },
|
|
14
|
+
quiz_id: { type: 'number', minimum: 1, description: 'id du quiz (list_quizzes)' },
|
|
15
|
+
item_id: { type: 'number', minimum: 1, description: 'id de la question / page (get_quiz)' },
|
|
16
|
+
label: { type: 'string', maxLength: 300 },
|
|
17
|
+
points: { type: 'number', minimum: 0, maximum: 4 },
|
|
18
|
+
profile_id: { type: 'number', minimum: 1, description: 'profil credite par cette reponse' },
|
|
19
|
+
},
|
|
20
|
+
required: ['lab', 'quiz_id', 'item_id', 'label'],
|
|
21
|
+
additionalProperties: false,
|
|
22
|
+
},
|
|
23
|
+
zodSchema: z.object({
|
|
24
|
+
lab: z.string(),
|
|
25
|
+
quiz_id: z.number().int().positive(),
|
|
26
|
+
item_id: z.number().int().positive(),
|
|
27
|
+
label: z.string().max(300),
|
|
28
|
+
points: z.number().int().min(0).max(4).optional(),
|
|
29
|
+
profile_id: z.number().int().min(1).nullable().optional(),
|
|
30
|
+
}),
|
|
31
|
+
async handler(args) {
|
|
32
|
+
const { lab, quiz_id, item_id, ...body } = this.zodSchema.parse(args);
|
|
33
|
+
const p = { lab, quiz_id, item_id };
|
|
34
|
+
try {
|
|
35
|
+
const { data } = await http.post(`/mcp/labs/${encodeURIComponent(p.lab)}/quiz/quizzes/${p.quiz_id}/items/${p.item_id}/answers`, body);
|
|
36
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool `create_quiz_item` — ajoute une question ou une page intermediaire.
|
|
3
|
+
* Scope : quiz.write.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { http, formatApiError } from '../http.js';
|
|
7
|
+
export const createQuizItemTool = {
|
|
8
|
+
name: 'create_quiz_item',
|
|
9
|
+
description: "Ajoute en fin de quiz une question (kind=question, QCM : ajouter ensuite ses reponses avec create_quiz_answer, max 8) ou une page intermediaire (kind=interstitial : texte + bouton, sans reponse).",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
lab: { type: 'string', description: 'group_url ou id du Lab' },
|
|
14
|
+
quiz_id: { type: 'number', minimum: 1, description: 'id du quiz (list_quizzes)' },
|
|
15
|
+
kind: { type: 'string', enum: ['question', 'interstitial'] },
|
|
16
|
+
title: { type: 'string', maxLength: 500 },
|
|
17
|
+
body: { type: 'string' },
|
|
18
|
+
image_path: { type: 'string', maxLength: 255 },
|
|
19
|
+
button_label: { type: 'string', maxLength: 120, description: 'texte du bouton (page intermediaire)' },
|
|
20
|
+
key: { type: 'string', maxLength: 60, description: 'identifiant technique optionnel (alpha_dash)' },
|
|
21
|
+
},
|
|
22
|
+
required: ['lab', 'quiz_id', 'kind', 'title'],
|
|
23
|
+
additionalProperties: false,
|
|
24
|
+
},
|
|
25
|
+
zodSchema: z.object({
|
|
26
|
+
lab: z.string(),
|
|
27
|
+
quiz_id: z.number().int().positive(),
|
|
28
|
+
kind: z.enum(['question', 'interstitial']),
|
|
29
|
+
title: z.string().max(500),
|
|
30
|
+
body: z.string().nullable().optional(),
|
|
31
|
+
image_path: z.string().max(255).nullable().optional(),
|
|
32
|
+
button_label: z.string().max(120).nullable().optional(),
|
|
33
|
+
key: z.string().max(60).nullable().optional(),
|
|
34
|
+
}),
|
|
35
|
+
async handler(args) {
|
|
36
|
+
const { lab, quiz_id, ...body } = this.zodSchema.parse(args);
|
|
37
|
+
const p = { lab, quiz_id };
|
|
38
|
+
try {
|
|
39
|
+
const { data } = await http.post(`/mcp/labs/${encodeURIComponent(p.lab)}/quiz/quizzes/${p.quiz_id}/items`, body);
|
|
40
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool `create_quiz_profile` — ajoute un profil de resultat.
|
|
3
|
+
* Scope : quiz.write.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { http, formatApiError } from '../http.js';
|
|
7
|
+
export const createQuizProfileTool = {
|
|
8
|
+
name: 'create_quiz_profile',
|
|
9
|
+
description: "Ajoute un profil de resultat (2 a 4 par quiz). diagnosis = texte affiche au prospect ; plan = jusqu'a 5 etapes du plan d'action ({text, locked} : locked=true floute l'etape pour donner envie) ; cta = bouton final vers destination_type : product, join (rejoindre le Lab), calendar ou url, avec destination_ref (URL pour url, reference du produit / calendrier sinon, inutile pour join).",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
lab: { type: 'string', description: 'group_url ou id du Lab' },
|
|
14
|
+
quiz_id: { type: 'number', minimum: 1, description: 'id du quiz (list_quizzes)' },
|
|
15
|
+
name: { type: 'string', maxLength: 120 },
|
|
16
|
+
color: { type: 'string', maxLength: 16 },
|
|
17
|
+
diagnosis: { type: 'string' },
|
|
18
|
+
video_url: { type: 'string', maxLength: 500 },
|
|
19
|
+
plan: { type: 'array', maxItems: 5, items: { type: 'object', properties: { text: { type: 'string' }, locked: { type: 'boolean' } }, required: ['text', 'locked'] } },
|
|
20
|
+
cta_label: { type: 'string', maxLength: 120 },
|
|
21
|
+
destination_type: { type: 'string', enum: ['product', 'join', 'calendar', 'url'] },
|
|
22
|
+
destination_ref: { type: 'string', maxLength: 255 },
|
|
23
|
+
},
|
|
24
|
+
required: ['lab', 'quiz_id', 'name'],
|
|
25
|
+
additionalProperties: false,
|
|
26
|
+
},
|
|
27
|
+
zodSchema: z.object({
|
|
28
|
+
lab: z.string(),
|
|
29
|
+
quiz_id: z.number().int().positive(),
|
|
30
|
+
name: z.string().max(120),
|
|
31
|
+
color: z.string().max(16).nullable().optional(),
|
|
32
|
+
diagnosis: z.string().nullable().optional(),
|
|
33
|
+
video_url: z.string().max(500).nullable().optional(),
|
|
34
|
+
plan: z.array(z.object({ text: z.string(), locked: z.boolean() })).max(5).nullable().optional(),
|
|
35
|
+
cta_label: z.string().max(120).nullable().optional(),
|
|
36
|
+
destination_type: z.enum(['product', 'join', 'calendar', 'url']).optional(),
|
|
37
|
+
destination_ref: z.string().max(255).nullable().optional(),
|
|
38
|
+
}),
|
|
39
|
+
async handler(args) {
|
|
40
|
+
const { lab, quiz_id, ...body } = this.zodSchema.parse(args);
|
|
41
|
+
const p = { lab, quiz_id };
|
|
42
|
+
try {
|
|
43
|
+
const { data } = await http.post(`/mcp/labs/${encodeURIComponent(p.lab)}/quiz/quizzes/${p.quiz_id}/profiles`, body);
|
|
44
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
};
|
|
@@ -2,7 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { http, formatApiError } from '../http.js';
|
|
3
3
|
export const createShopProductTool = {
|
|
4
4
|
name: 'create_shop_product',
|
|
5
|
-
description: "Cree un produit dans la boutique du Lab. Files (bannieres, PDF) non geres par MCP — a uploader ensuite via le front. Prix en centimes (price_cents) — c'est le PRODUIT qui porte le prix de vente. offer_type=formation : l'achat debloque un cours du Lab — fournis alors course_id (via list_classes) ET price_cents (>= 50, obligatoire, le cours lui-meme n'a pas de prix de vente)
|
|
5
|
+
description: "Cree un produit dans la boutique du Lab, vendu via Stripe ConnectXLab (seul mode de paiement). Files (bannieres, PDF) non geres par MCP — a uploader ensuite via le front. Prix en centimes (price_cents) — c'est le PRODUIT qui porte le prix de vente. offer_type=formation : l'achat debloque un cours du Lab — fournis alors course_id (via list_classes) ET price_cents (>= 50, obligatoire, le cours lui-meme n'a pas de prix de vente). offer_type=digital : quiz_id optionnel (list_quizzes) pour embarquer un quiz du Lab — un bouton (quiz_cta_label, quiz_cta_subtext) l'ouvre en plein ecran ; sur un produit gratuit, il remplace le checkout.",
|
|
6
6
|
inputSchema: {
|
|
7
7
|
type: 'object',
|
|
8
8
|
properties: {
|
|
@@ -13,9 +13,10 @@ export const createShopProductTool = {
|
|
|
13
13
|
price_cents: { type: 'number', minimum: 0, description: 'Prix en centimes (ex 2990 = 29.90 EUR)' },
|
|
14
14
|
offer_type: { type: 'string', enum: ['digital', 'calendar', 'formation'], description: "digital = telechargeable ; calendar = Calendrier IA ; formation = debloque un cours a l'achat (course_id requis)." },
|
|
15
15
|
course_id: { type: 'number', description: "Requis si offer_type=formation — id d'un cours du Lab (list_classes). Doit appartenir a ce Lab." },
|
|
16
|
-
payment_mode: { type: 'string', enum: ['external', 'stripe'] },
|
|
17
|
-
payment_link_text: { type: 'string', maxLength: 255 },
|
|
18
16
|
support_email: { type: 'string', format: 'email' },
|
|
17
|
+
quiz_id: { type: 'number', minimum: 1, description: 'offer_type=digital uniquement : id du quiz a embarquer (list_quizzes)' },
|
|
18
|
+
quiz_cta_label: { type: 'string', maxLength: 150, description: 'texte du bouton qui ouvre le quiz' },
|
|
19
|
+
quiz_cta_subtext: { type: 'string', maxLength: 500, description: 'petit texte rassurant sous le bouton' },
|
|
19
20
|
is_published: { type: 'boolean' },
|
|
20
21
|
},
|
|
21
22
|
required: ['lab', 'title', 'short_description', 'description'],
|
|
@@ -29,9 +30,10 @@ export const createShopProductTool = {
|
|
|
29
30
|
price_cents: z.number().int().min(0).nullable().optional(),
|
|
30
31
|
offer_type: z.enum(['digital', 'calendar', 'formation']).optional(),
|
|
31
32
|
course_id: z.number().int().positive().optional(),
|
|
32
|
-
payment_mode: z.enum(['external', 'stripe']).optional(),
|
|
33
|
-
payment_link_text: z.string().max(255).nullable().optional(),
|
|
34
33
|
support_email: z.string().email().nullable().optional(),
|
|
34
|
+
quiz_id: z.number().int().positive().nullable().optional(),
|
|
35
|
+
quiz_cta_label: z.string().max(150).nullable().optional(),
|
|
36
|
+
quiz_cta_subtext: z.string().max(500).nullable().optional(),
|
|
35
37
|
is_published: z.boolean().optional(),
|
|
36
38
|
}),
|
|
37
39
|
async handler(args) {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool `delete_quiz` — supprime un quiz.
|
|
3
|
+
* Scope : quiz.write.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { http, formatApiError } from '../http.js';
|
|
7
|
+
export const deleteQuizTool = {
|
|
8
|
+
name: 'delete_quiz',
|
|
9
|
+
description: "Supprime definitivement un quiz (questions, profils et prospects associes). Demander confirmation a l'owner avant.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
lab: { type: 'string', description: 'group_url ou id du Lab' },
|
|
14
|
+
quiz_id: { type: 'number', minimum: 1, description: 'id du quiz (list_quizzes)' },
|
|
15
|
+
},
|
|
16
|
+
required: ['lab', 'quiz_id'],
|
|
17
|
+
additionalProperties: false,
|
|
18
|
+
},
|
|
19
|
+
zodSchema: z.object({
|
|
20
|
+
lab: z.string(),
|
|
21
|
+
quiz_id: z.number().int().positive(),
|
|
22
|
+
}),
|
|
23
|
+
async handler(args) {
|
|
24
|
+
const p = this.zodSchema.parse(args);
|
|
25
|
+
try {
|
|
26
|
+
const { data } = await http.delete(`/mcp/labs/${encodeURIComponent(p.lab)}/quiz/quizzes/${p.quiz_id}`);
|
|
27
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool `delete_quiz_answer` — supprime une reponse.
|
|
3
|
+
* Scope : quiz.write.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { http, formatApiError } from '../http.js';
|
|
7
|
+
export const deleteQuizAnswerTool = {
|
|
8
|
+
name: 'delete_quiz_answer',
|
|
9
|
+
description: "Supprime une reponse d'une question.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
lab: { type: 'string', description: 'group_url ou id du Lab' },
|
|
14
|
+
quiz_id: { type: 'number', minimum: 1, description: 'id du quiz (list_quizzes)' },
|
|
15
|
+
item_id: { type: 'number', minimum: 1, description: 'id de la question / page (get_quiz)' },
|
|
16
|
+
answer_id: { type: 'number', minimum: 1, description: 'id de la reponse (get_quiz)' },
|
|
17
|
+
},
|
|
18
|
+
required: ['lab', 'quiz_id', 'item_id', 'answer_id'],
|
|
19
|
+
additionalProperties: false,
|
|
20
|
+
},
|
|
21
|
+
zodSchema: z.object({
|
|
22
|
+
lab: z.string(),
|
|
23
|
+
quiz_id: z.number().int().positive(),
|
|
24
|
+
item_id: z.number().int().positive(),
|
|
25
|
+
answer_id: z.number().int().positive(),
|
|
26
|
+
}),
|
|
27
|
+
async handler(args) {
|
|
28
|
+
const p = this.zodSchema.parse(args);
|
|
29
|
+
try {
|
|
30
|
+
const { data } = await http.delete(`/mcp/labs/${encodeURIComponent(p.lab)}/quiz/quizzes/${p.quiz_id}/items/${p.item_id}/answers/${p.answer_id}`);
|
|
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,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool `delete_quiz_item` — supprime une question / page.
|
|
3
|
+
* Scope : quiz.write.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { http, formatApiError } from '../http.js';
|
|
7
|
+
export const deleteQuizItemTool = {
|
|
8
|
+
name: 'delete_quiz_item',
|
|
9
|
+
description: "Supprime une question (et ses reponses) ou une page intermediaire.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
lab: { type: 'string', description: 'group_url ou id du Lab' },
|
|
14
|
+
quiz_id: { type: 'number', minimum: 1, description: 'id du quiz (list_quizzes)' },
|
|
15
|
+
item_id: { type: 'number', minimum: 1, description: 'id de la question / page (get_quiz)' },
|
|
16
|
+
},
|
|
17
|
+
required: ['lab', 'quiz_id', 'item_id'],
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
},
|
|
20
|
+
zodSchema: z.object({
|
|
21
|
+
lab: z.string(),
|
|
22
|
+
quiz_id: z.number().int().positive(),
|
|
23
|
+
item_id: z.number().int().positive(),
|
|
24
|
+
}),
|
|
25
|
+
async handler(args) {
|
|
26
|
+
const p = this.zodSchema.parse(args);
|
|
27
|
+
try {
|
|
28
|
+
const { data } = await http.delete(`/mcp/labs/${encodeURIComponent(p.lab)}/quiz/quizzes/${p.quiz_id}/items/${p.item_id}`);
|
|
29
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
return { isError: true, content: [{ type: 'text', text: formatApiError(err) }] };
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
};
|