@lyrra/mcp-server 1.0.1 → 1.1.1
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/Dockerfile +16 -0
- package/README.md +95 -16
- package/dist/client.d.ts +7 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +5 -5
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/http-server.d.ts +8 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +466 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.js +3 -69
- package/dist/index.js.map +1 -1
- package/dist/server-factory.d.ts +8 -0
- package/dist/server-factory.d.ts.map +1 -0
- package/dist/server-factory.js +82 -0
- package/dist/server-factory.js.map +1 -0
- package/dist/tools/admin.d.ts +132 -0
- package/dist/tools/admin.d.ts.map +1 -1
- package/dist/tools/admin.js +105 -101
- package/dist/tools/admin.js.map +1 -1
- package/dist/tools/ai-designer.d.ts +148 -0
- package/dist/tools/ai-designer.d.ts.map +1 -1
- package/dist/tools/ai-designer.js +80 -76
- package/dist/tools/ai-designer.js.map +1 -1
- package/dist/tools/analytics.d.ts +47 -0
- package/dist/tools/analytics.d.ts.map +1 -1
- package/dist/tools/analytics.js +38 -34
- package/dist/tools/analytics.js.map +1 -1
- package/dist/tools/auth.d.ts +30 -0
- package/dist/tools/auth.d.ts.map +1 -1
- package/dist/tools/auth.js +31 -27
- package/dist/tools/auth.js.map +1 -1
- package/dist/tools/blocks.d.ts +200 -0
- package/dist/tools/blocks.d.ts.map +1 -1
- package/dist/tools/blocks.js +154 -150
- package/dist/tools/blocks.js.map +1 -1
- package/dist/tools/connections.d.ts +86 -0
- package/dist/tools/connections.d.ts.map +1 -1
- package/dist/tools/connections.js +70 -66
- package/dist/tools/connections.js.map +1 -1
- package/dist/tools/eduflow.d.ts +223 -0
- package/dist/tools/eduflow.d.ts.map +1 -1
- package/dist/tools/eduflow.js +114 -93
- package/dist/tools/eduflow.js.map +1 -1
- package/dist/tools/participants.d.ts +110 -0
- package/dist/tools/participants.d.ts.map +1 -1
- package/dist/tools/participants.js +62 -58
- package/dist/tools/participants.js.map +1 -1
- package/dist/tools/presentation.d.ts +116 -0
- package/dist/tools/presentation.d.ts.map +1 -1
- package/dist/tools/presentation.js +51 -47
- package/dist/tools/presentation.js.map +1 -1
- package/dist/tools/projects.d.ts +65 -0
- package/dist/tools/projects.d.ts.map +1 -1
- package/dist/tools/projects.js +48 -44
- package/dist/tools/projects.js.map +1 -1
- package/dist/tools/resources.d.ts +46 -0
- package/dist/tools/resources.d.ts.map +1 -1
- package/dist/tools/resources.js +32 -28
- package/dist/tools/resources.js.map +1 -1
- package/dist/tools/store.d.ts +62 -0
- package/dist/tools/store.d.ts.map +1 -1
- package/dist/tools/store.js +59 -55
- package/dist/tools/store.js.map +1 -1
- package/mcp-config.example.json +4 -5
- package/package.json +7 -2
- package/src/client.ts +12 -5
- package/src/config.ts +1 -0
- package/src/http-server.ts +573 -0
- package/src/index.ts +3 -94
- package/src/server-factory.ts +109 -0
- package/src/tools/admin.ts +20 -14
- package/src/tools/ai-designer.ts +16 -10
- package/src/tools/analytics.ts +13 -7
- package/src/tools/auth.ts +32 -26
- package/src/tools/blocks.ts +18 -12
- package/src/tools/connections.ts +14 -8
- package/src/tools/eduflow.ts +36 -12
- package/src/tools/participants.ts +15 -9
- package/src/tools/presentation.ts +12 -6
- package/src/tools/projects.ts +14 -8
- package/src/tools/resources.ts +12 -6
- package/src/tools/store.ts +14 -8
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { LyrraClient } from './client.js';
|
|
3
|
+
|
|
4
|
+
// Tool factory functions
|
|
5
|
+
import { createAuthTools } from './tools/auth.js';
|
|
6
|
+
import { createEduflowTools } from './tools/eduflow.js';
|
|
7
|
+
import { createBlocksTools } from './tools/blocks.js';
|
|
8
|
+
import { createConnectionsTools } from './tools/connections.js';
|
|
9
|
+
import { createParticipantsTools } from './tools/participants.js';
|
|
10
|
+
import { createAnalyticsTools } from './tools/analytics.js';
|
|
11
|
+
import { createAiDesignerTools } from './tools/ai-designer.js';
|
|
12
|
+
import { createPresentationTools } from './tools/presentation.js';
|
|
13
|
+
import { createStoreTools } from './tools/store.js';
|
|
14
|
+
import { createProjectsTools } from './tools/projects.js';
|
|
15
|
+
import { createResourcesTools } from './tools/resources.js';
|
|
16
|
+
import { createAdminTools } from './tools/admin.js';
|
|
17
|
+
|
|
18
|
+
// Resources
|
|
19
|
+
import { BLOCK_TYPES_RESOURCE } from './resources/block-types.js';
|
|
20
|
+
import { FLOW_SCHEMA_RESOURCE } from './resources/flow-schema.js';
|
|
21
|
+
|
|
22
|
+
type ToolDef = { description: string; inputSchema: any; handler: (args: any) => Promise<any> };
|
|
23
|
+
|
|
24
|
+
function registerToolsOnServer(server: McpServer, tools: Record<string, ToolDef>) {
|
|
25
|
+
for (const [name, tool] of Object.entries(tools)) {
|
|
26
|
+
server.tool(
|
|
27
|
+
name,
|
|
28
|
+
tool.description,
|
|
29
|
+
tool.inputSchema.shape
|
|
30
|
+
? Object.fromEntries(
|
|
31
|
+
Object.entries(tool.inputSchema.shape).map(([key, schema]: [string, any]) => [key, schema])
|
|
32
|
+
)
|
|
33
|
+
: {},
|
|
34
|
+
async (args: any) => {
|
|
35
|
+
try {
|
|
36
|
+
const result = await tool.handler(args);
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
39
|
+
};
|
|
40
|
+
} catch (error: any) {
|
|
41
|
+
return {
|
|
42
|
+
content: [{ type: 'text' as const, text: `Erreur: ${error.message}` }],
|
|
43
|
+
isError: true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Create and configure an MCP server with all tools registered.
|
|
53
|
+
* @param client - LyrraClient to use for API calls. If not provided, uses default (env vars).
|
|
54
|
+
*/
|
|
55
|
+
export function createMcpServer(client?: LyrraClient): McpServer {
|
|
56
|
+
const c = client || new LyrraClient();
|
|
57
|
+
|
|
58
|
+
const server = new McpServer({
|
|
59
|
+
name: 'lyrra-studio',
|
|
60
|
+
version: '1.0.0',
|
|
61
|
+
description: 'Serveur MCP pour piloter LYRRA Studio - Plateforme EdTech de création de parcours pédagogiques, conversion PDF→Audio, et store d\'audiobooks.',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const allTools: Record<string, ToolDef> = {
|
|
65
|
+
...createAuthTools(c),
|
|
66
|
+
...createEduflowTools(c),
|
|
67
|
+
...createBlocksTools(c),
|
|
68
|
+
...createConnectionsTools(c),
|
|
69
|
+
...createParticipantsTools(c),
|
|
70
|
+
...createAnalyticsTools(c),
|
|
71
|
+
...createAiDesignerTools(c),
|
|
72
|
+
...createPresentationTools(c),
|
|
73
|
+
...createStoreTools(c),
|
|
74
|
+
...createProjectsTools(c),
|
|
75
|
+
...createResourcesTools(c),
|
|
76
|
+
...createAdminTools(c),
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
registerToolsOnServer(server, allTools);
|
|
80
|
+
|
|
81
|
+
// Resources
|
|
82
|
+
server.resource(
|
|
83
|
+
'block-types',
|
|
84
|
+
BLOCK_TYPES_RESOURCE.uri,
|
|
85
|
+
{ description: BLOCK_TYPES_RESOURCE.description, mimeType: BLOCK_TYPES_RESOURCE.mimeType },
|
|
86
|
+
async () => ({
|
|
87
|
+
contents: [{
|
|
88
|
+
uri: BLOCK_TYPES_RESOURCE.uri,
|
|
89
|
+
mimeType: BLOCK_TYPES_RESOURCE.mimeType,
|
|
90
|
+
text: JSON.stringify(BLOCK_TYPES_RESOURCE.content, null, 2),
|
|
91
|
+
}],
|
|
92
|
+
})
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
server.resource(
|
|
96
|
+
'flow-construction-guide',
|
|
97
|
+
FLOW_SCHEMA_RESOURCE.uri,
|
|
98
|
+
{ description: FLOW_SCHEMA_RESOURCE.description, mimeType: FLOW_SCHEMA_RESOURCE.mimeType },
|
|
99
|
+
async () => ({
|
|
100
|
+
contents: [{
|
|
101
|
+
uri: FLOW_SCHEMA_RESOURCE.uri,
|
|
102
|
+
mimeType: FLOW_SCHEMA_RESOURCE.mimeType,
|
|
103
|
+
text: JSON.stringify(FLOW_SCHEMA_RESOURCE.content, null, 2),
|
|
104
|
+
}],
|
|
105
|
+
})
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
return server;
|
|
109
|
+
}
|
package/src/tools/admin.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { LyrraClient } from '../client.js';
|
|
3
|
+
import { client as defaultClient } from '../client.js';
|
|
3
4
|
|
|
4
|
-
export
|
|
5
|
+
export function createAdminTools(c: LyrraClient) {
|
|
6
|
+
return {
|
|
5
7
|
// --- Versions ---
|
|
6
8
|
version_list: {
|
|
7
9
|
description: 'Lister toutes les versions d\'un parcours EduFlow.',
|
|
@@ -9,7 +11,7 @@ export const adminTools = {
|
|
|
9
11
|
flowId: z.string().uuid().describe('ID du parcours'),
|
|
10
12
|
}),
|
|
11
13
|
handler: async ({ flowId }: { flowId: string }) => {
|
|
12
|
-
return
|
|
14
|
+
return c.get(`/flows/${flowId}/versions`, 'eduflow');
|
|
13
15
|
},
|
|
14
16
|
},
|
|
15
17
|
|
|
@@ -20,7 +22,7 @@ export const adminTools = {
|
|
|
20
22
|
versionLabel: z.string().optional().describe('Label de la version (ex: "v2.0 - Ajout quiz")'),
|
|
21
23
|
}),
|
|
22
24
|
handler: async ({ flowId, versionLabel }: any) => {
|
|
23
|
-
return
|
|
25
|
+
return c.post(`/flows/${flowId}/versions`, { versionLabel }, 'eduflow');
|
|
24
26
|
},
|
|
25
27
|
},
|
|
26
28
|
|
|
@@ -31,7 +33,7 @@ export const adminTools = {
|
|
|
31
33
|
versionId: z.string().uuid().describe('ID de la version à activer'),
|
|
32
34
|
}),
|
|
33
35
|
handler: async ({ flowId, versionId }: { flowId: string; versionId: string }) => {
|
|
34
|
-
return
|
|
36
|
+
return c.post(`/flows/${flowId}/versions/${versionId}/activate`, {}, 'eduflow');
|
|
35
37
|
},
|
|
36
38
|
},
|
|
37
39
|
|
|
@@ -40,7 +42,7 @@ export const adminTools = {
|
|
|
40
42
|
description: 'Récupérer les statistiques de gamification de l\'utilisateur (niveau, streak, badges, missions).',
|
|
41
43
|
inputSchema: z.object({}),
|
|
42
44
|
handler: async () => {
|
|
43
|
-
return
|
|
45
|
+
return c.get('/gamification/stats');
|
|
44
46
|
},
|
|
45
47
|
},
|
|
46
48
|
|
|
@@ -48,7 +50,7 @@ export const adminTools = {
|
|
|
48
50
|
description: 'Récupérer les prochains objectifs de gamification à atteindre.',
|
|
49
51
|
inputSchema: z.object({}),
|
|
50
52
|
handler: async () => {
|
|
51
|
-
return
|
|
53
|
+
return c.get('/gamification/objectives');
|
|
52
54
|
},
|
|
53
55
|
},
|
|
54
56
|
|
|
@@ -64,7 +66,7 @@ export const adminTools = {
|
|
|
64
66
|
if (page) params.set('page', String(page));
|
|
65
67
|
if (limit) params.set('limit', String(limit));
|
|
66
68
|
const query = params.toString() ? `?${params}` : '';
|
|
67
|
-
return
|
|
69
|
+
return c.get(`/activity${query}`);
|
|
68
70
|
},
|
|
69
71
|
},
|
|
70
72
|
|
|
@@ -75,7 +77,7 @@ export const adminTools = {
|
|
|
75
77
|
}),
|
|
76
78
|
handler: async ({ period }: { period?: string }) => {
|
|
77
79
|
const query = period ? `?period=${period}` : '';
|
|
78
|
-
return
|
|
80
|
+
return c.get(`/activity/stats${query}`);
|
|
79
81
|
},
|
|
80
82
|
},
|
|
81
83
|
|
|
@@ -84,7 +86,7 @@ export const adminTools = {
|
|
|
84
86
|
description: 'Lister les webhooks configurés pour recevoir des événements (block.completed, flow.completed, etc.).',
|
|
85
87
|
inputSchema: z.object({}),
|
|
86
88
|
handler: async () => {
|
|
87
|
-
return
|
|
89
|
+
return c.get('/webhooks');
|
|
88
90
|
},
|
|
89
91
|
},
|
|
90
92
|
|
|
@@ -96,7 +98,7 @@ export const adminTools = {
|
|
|
96
98
|
name: z.string().optional().describe('Nom du webhook'),
|
|
97
99
|
}),
|
|
98
100
|
handler: async (data: any) => {
|
|
99
|
-
return
|
|
101
|
+
return c.post('/webhooks', data);
|
|
100
102
|
},
|
|
101
103
|
},
|
|
102
104
|
|
|
@@ -106,7 +108,7 @@ export const adminTools = {
|
|
|
106
108
|
webhookId: z.string().uuid().describe('ID du webhook'),
|
|
107
109
|
}),
|
|
108
110
|
handler: async ({ webhookId }: { webhookId: string }) => {
|
|
109
|
-
return
|
|
111
|
+
return c.delete(`/webhooks/${webhookId}`);
|
|
110
112
|
},
|
|
111
113
|
},
|
|
112
114
|
|
|
@@ -116,7 +118,11 @@ export const adminTools = {
|
|
|
116
118
|
webhookId: z.string().uuid().describe('ID du webhook à tester'),
|
|
117
119
|
}),
|
|
118
120
|
handler: async ({ webhookId }: { webhookId: string }) => {
|
|
119
|
-
return
|
|
121
|
+
return c.post(`/webhooks/${webhookId}/test`, {});
|
|
120
122
|
},
|
|
121
123
|
},
|
|
122
|
-
};
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Backward compatibility for stdio mode
|
|
128
|
+
export const adminTools = createAdminTools(defaultClient);
|
package/src/tools/ai-designer.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { LyrraClient } from '../client.js';
|
|
3
|
+
import { client as defaultClient } from '../client.js';
|
|
3
4
|
|
|
4
|
-
export
|
|
5
|
+
export function createAiDesignerTools(c: LyrraClient) {
|
|
6
|
+
return {
|
|
5
7
|
ai_generate_plan: {
|
|
6
8
|
description: 'Générer automatiquement un plan/structure de parcours pédagogique à partir d\'un sujet et d\'objectifs. L\'IA propose une liste de blocs organisés.',
|
|
7
9
|
inputSchema: z.object({
|
|
@@ -13,7 +15,7 @@ export const aiDesignerTools = {
|
|
|
13
15
|
context: z.string().optional().describe('Contexte additionnel pour l\'IA'),
|
|
14
16
|
}),
|
|
15
17
|
handler: async ({ flowId, ...data }: any) => {
|
|
16
|
-
return
|
|
18
|
+
return c.post(`/flows/${flowId}/chatbot/generate-plan`, data, 'eduflow');
|
|
17
19
|
},
|
|
18
20
|
},
|
|
19
21
|
|
|
@@ -26,7 +28,7 @@ export const aiDesignerTools = {
|
|
|
26
28
|
context: z.string().optional().describe('Contexte du parcours pour l\'IA'),
|
|
27
29
|
}),
|
|
28
30
|
handler: async ({ flowId, ...data }: any) => {
|
|
29
|
-
return
|
|
31
|
+
return c.post(`/flows/${flowId}/chatbot/generate-block`, data, 'eduflow');
|
|
30
32
|
},
|
|
31
33
|
},
|
|
32
34
|
|
|
@@ -37,7 +39,7 @@ export const aiDesignerTools = {
|
|
|
37
39
|
style: z.string().optional().describe('Style de présentation souhaité'),
|
|
38
40
|
}),
|
|
39
41
|
handler: async ({ flowId, ...data }: any) => {
|
|
40
|
-
return
|
|
42
|
+
return c.post(`/flows/${flowId}/chatbot/generate-presentation`, data, 'eduflow');
|
|
41
43
|
},
|
|
42
44
|
},
|
|
43
45
|
|
|
@@ -47,7 +49,7 @@ export const aiDesignerTools = {
|
|
|
47
49
|
flowId: z.string().uuid().describe('ID du parcours'),
|
|
48
50
|
}),
|
|
49
51
|
handler: async ({ flowId }: { flowId: string }) => {
|
|
50
|
-
return
|
|
52
|
+
return c.post(`/flows/${flowId}/chatbot/generate-objectives`, {}, 'eduflow');
|
|
51
53
|
},
|
|
52
54
|
},
|
|
53
55
|
|
|
@@ -64,7 +66,7 @@ export const aiDesignerTools = {
|
|
|
64
66
|
})).describe('Liste des objectifs par étape'),
|
|
65
67
|
}),
|
|
66
68
|
handler: async ({ flowId, ...objectives }: any) => {
|
|
67
|
-
return
|
|
69
|
+
return c.post(`/flows/${flowId}/chatbot/save-objectives`, objectives, 'eduflow');
|
|
68
70
|
},
|
|
69
71
|
},
|
|
70
72
|
|
|
@@ -75,7 +77,7 @@ export const aiDesignerTools = {
|
|
|
75
77
|
message: z.string().describe('Message à envoyer à l\'IA designer'),
|
|
76
78
|
}),
|
|
77
79
|
handler: async ({ flowId, message }: { flowId: string; message: string }) => {
|
|
78
|
-
return
|
|
80
|
+
return c.post(`/flows/${flowId}/chatbot/message`, { message }, 'eduflow');
|
|
79
81
|
},
|
|
80
82
|
},
|
|
81
83
|
|
|
@@ -85,7 +87,11 @@ export const aiDesignerTools = {
|
|
|
85
87
|
flowId: z.string().uuid().describe('ID du parcours'),
|
|
86
88
|
}),
|
|
87
89
|
handler: async ({ flowId }: { flowId: string }) => {
|
|
88
|
-
return
|
|
90
|
+
return c.get(`/flows/${flowId}/chatbot/conversation`, 'eduflow');
|
|
89
91
|
},
|
|
90
92
|
},
|
|
91
|
-
};
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Backward compatibility for stdio mode
|
|
97
|
+
export const aiDesignerTools = createAiDesignerTools(defaultClient);
|
package/src/tools/analytics.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { LyrraClient } from '../client.js';
|
|
3
|
+
import { client as defaultClient } from '../client.js';
|
|
3
4
|
|
|
4
|
-
export
|
|
5
|
+
export function createAnalyticsTools(c: LyrraClient) {
|
|
6
|
+
return {
|
|
5
7
|
analytics_overview: {
|
|
6
8
|
description: 'Tableau de bord global : nombre de projets, parcours EduFlow, apprenants, crédits utilisés, avec évolution par période.',
|
|
7
9
|
inputSchema: z.object({
|
|
@@ -9,7 +11,7 @@ export const analyticsTools = {
|
|
|
9
11
|
}),
|
|
10
12
|
handler: async ({ period }: { period?: string }) => {
|
|
11
13
|
const query = period ? `?period=${period}` : '';
|
|
12
|
-
return
|
|
14
|
+
return c.get(`/analytics/overview${query}`);
|
|
13
15
|
},
|
|
14
16
|
},
|
|
15
17
|
|
|
@@ -19,7 +21,7 @@ export const analyticsTools = {
|
|
|
19
21
|
flowId: z.string().uuid().describe('ID du parcours'),
|
|
20
22
|
}),
|
|
21
23
|
handler: async ({ flowId }: { flowId: string }) => {
|
|
22
|
-
return
|
|
24
|
+
return c.get(`/analytics/flow/${flowId}/learners`);
|
|
23
25
|
},
|
|
24
26
|
},
|
|
25
27
|
|
|
@@ -29,7 +31,7 @@ export const analyticsTools = {
|
|
|
29
31
|
flowId: z.string().uuid().describe('ID du parcours'),
|
|
30
32
|
}),
|
|
31
33
|
handler: async ({ flowId }: { flowId: string }) => {
|
|
32
|
-
return
|
|
34
|
+
return c.get(`/flows/${flowId}/analytics`, 'eduflow');
|
|
33
35
|
},
|
|
34
36
|
},
|
|
35
37
|
|
|
@@ -37,7 +39,11 @@ export const analyticsTools = {
|
|
|
37
39
|
description: 'Mes statistiques personnelles : projets créés, parcours créés, temps total, crédits utilisés.',
|
|
38
40
|
inputSchema: z.object({}),
|
|
39
41
|
handler: async () => {
|
|
40
|
-
return
|
|
42
|
+
return c.get('/analytics/my-stats');
|
|
41
43
|
},
|
|
42
44
|
},
|
|
43
|
-
};
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Backward compatibility for stdio mode
|
|
49
|
+
export const analyticsTools = createAnalyticsTools(defaultClient);
|
package/src/tools/auth.ts
CHANGED
|
@@ -1,33 +1,39 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { LyrraClient } from '../client.js';
|
|
3
|
+
import { client as defaultClient } from '../client.js';
|
|
3
4
|
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
export function createAuthTools(c: LyrraClient) {
|
|
6
|
+
return {
|
|
7
|
+
auth_login: {
|
|
8
|
+
description: 'Se connecter à LYRRA Studio avec email et mot de passe. ⚠️ NE PAS utiliser si LYRRA_CLIENT_SECRET est configuré — l\'authentification est alors automatique via API Key. Utiliser uniquement si aucune clé API n\'est définie.',
|
|
9
|
+
inputSchema: z.object({
|
|
10
|
+
email: z.string().email().describe('Adresse email du compte'),
|
|
11
|
+
password: z.string().describe('Mot de passe'),
|
|
12
|
+
}),
|
|
13
|
+
handler: async ({ email, password }: { email: string; password: string }) => {
|
|
14
|
+
const result = await c.post('/auth/login', { email, password });
|
|
15
|
+
if (result.token) c.setToken(result.token);
|
|
16
|
+
return result;
|
|
17
|
+
},
|
|
15
18
|
},
|
|
16
|
-
},
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
auth_get_profile: {
|
|
21
|
+
description: 'Récupérer le profil de l\'utilisateur connecté (nom, email, crédits, rôle, institution, etc.).',
|
|
22
|
+
inputSchema: z.object({}),
|
|
23
|
+
handler: async () => {
|
|
24
|
+
return c.get('/auth/me');
|
|
25
|
+
},
|
|
23
26
|
},
|
|
24
|
-
},
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
auth_list_api_keys: {
|
|
29
|
+
description: 'Lister toutes les clés API de l\'utilisateur connecté.',
|
|
30
|
+
inputSchema: z.object({}),
|
|
31
|
+
handler: async () => {
|
|
32
|
+
return c.get('/api-keys');
|
|
33
|
+
},
|
|
31
34
|
},
|
|
32
|
-
}
|
|
33
|
-
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Backward compatibility for stdio mode
|
|
39
|
+
export const authTools = createAuthTools(defaultClient);
|
package/src/tools/blocks.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { LyrraClient } from '../client.js';
|
|
3
|
+
import { client as defaultClient } from '../client.js';
|
|
3
4
|
|
|
4
5
|
const blockContentSchema = z.record(z.any()).describe(
|
|
5
6
|
'Contenu du bloc (structure variable selon le type). Utiliser la resource lyrra://block-types pour connaître la structure attendue.'
|
|
6
7
|
);
|
|
7
8
|
|
|
8
|
-
export
|
|
9
|
+
export function createBlocksTools(c: LyrraClient) {
|
|
10
|
+
return {
|
|
9
11
|
block_list_types: {
|
|
10
12
|
description: `Lister tous les types de blocs disponibles avec leur documentation complète.
|
|
11
13
|
Types disponibles : text, audio, quiz, video, pdf, image, loop, evaluation, split, merge, timer, start, end, chart, timeline, dys_reader, dys_image_zones, dys_reading_practice, dys_clock, glossary, subflow, mindmap, form, certification, email, voice_assessment, presentation, browser, self_assessment.
|
|
@@ -55,7 +57,7 @@ Utiliser plutôt la resource lyrra://block-types pour la documentation complète
|
|
|
55
57
|
blockId: z.string().uuid().describe('ID du bloc'),
|
|
56
58
|
}),
|
|
57
59
|
handler: async ({ flowId, blockId }: { flowId: string; blockId: string }) => {
|
|
58
|
-
return
|
|
60
|
+
return c.get(`/flows/${flowId}/blocks/${blockId}`, 'eduflow');
|
|
59
61
|
},
|
|
60
62
|
},
|
|
61
63
|
|
|
@@ -79,7 +81,7 @@ IMPORTANT pour le type "text" : toujours utiliser content.format = "html" et du
|
|
|
79
81
|
}),
|
|
80
82
|
handler: async ({ flowId, ...blockData }: any) => {
|
|
81
83
|
// Use batch update to add a single block
|
|
82
|
-
const flow = await
|
|
84
|
+
const flow = await c.get(`/flows/${flowId}`, 'eduflow');
|
|
83
85
|
const existingBlocks = flow.blocks || [];
|
|
84
86
|
const newBlock = {
|
|
85
87
|
id: crypto.randomUUID(),
|
|
@@ -93,7 +95,7 @@ IMPORTANT pour le type "text" : toujours utiliser content.format = "html" et du
|
|
|
93
95
|
content: b.content, positionX: b.positionX, positionY: b.positionY,
|
|
94
96
|
order: b.order, conditions: b.conditions, comment: b.comment,
|
|
95
97
|
})), newBlock];
|
|
96
|
-
await
|
|
98
|
+
await c.put(`/flows/${flowId}/blocks`, allBlocks, 'eduflow');
|
|
97
99
|
return { success: true, block: newBlock };
|
|
98
100
|
},
|
|
99
101
|
},
|
|
@@ -112,7 +114,7 @@ IMPORTANT pour le type "text" : toujours utiliser content.format = "html" et du
|
|
|
112
114
|
comment: z.string().optional().describe('Commentaire créateur'),
|
|
113
115
|
}),
|
|
114
116
|
handler: async ({ flowId, blockId, ...data }: any) => {
|
|
115
|
-
return
|
|
117
|
+
return c.put(`/flows/${flowId}/blocks/${blockId}`, data, 'eduflow');
|
|
116
118
|
},
|
|
117
119
|
},
|
|
118
120
|
|
|
@@ -133,7 +135,7 @@ IMPORTANT pour le type "text" : toujours utiliser content.format = "html" et du
|
|
|
133
135
|
})).describe('Liste complète des blocs (REMPLACE tous les blocs existants)'),
|
|
134
136
|
}),
|
|
135
137
|
handler: async ({ flowId, blocks }: any) => {
|
|
136
|
-
return
|
|
138
|
+
return c.put(`/flows/${flowId}/blocks`, blocks, 'eduflow');
|
|
137
139
|
},
|
|
138
140
|
},
|
|
139
141
|
|
|
@@ -145,7 +147,7 @@ IMPORTANT pour le type "text" : toujours utiliser content.format = "html" et du
|
|
|
145
147
|
}),
|
|
146
148
|
handler: async ({ flowId, blockId }: { flowId: string; blockId: string }) => {
|
|
147
149
|
// Get current flow, remove block, remove related edges, batch update
|
|
148
|
-
const flow = await
|
|
150
|
+
const flow = await c.get(`/flows/${flowId}`, 'eduflow');
|
|
149
151
|
const blocks = (flow.blocks || []).filter((b: any) => b.id !== blockId);
|
|
150
152
|
const edges = (flow.edges || []).filter(
|
|
151
153
|
(e: any) => e.source !== blockId && e.target !== blockId
|
|
@@ -155,8 +157,8 @@ IMPORTANT pour le type "text" : toujours utiliser content.format = "html" et du
|
|
|
155
157
|
content: b.content, positionX: b.positionX, positionY: b.positionY,
|
|
156
158
|
order: b.order, conditions: b.conditions, comment: b.comment,
|
|
157
159
|
}));
|
|
158
|
-
await
|
|
159
|
-
await
|
|
160
|
+
await c.put(`/flows/${flowId}/blocks`, mappedBlocks, 'eduflow');
|
|
161
|
+
await c.put(`/flows/${flowId}`, { edges }, 'eduflow');
|
|
160
162
|
return { success: true, remainingBlocks: blocks.length, remainingEdges: edges.length };
|
|
161
163
|
},
|
|
162
164
|
},
|
|
@@ -168,7 +170,11 @@ IMPORTANT pour le type "text" : toujours utiliser content.format = "html" et du
|
|
|
168
170
|
blockId: z.string().uuid().describe('ID du bloc'),
|
|
169
171
|
}),
|
|
170
172
|
handler: async ({ flowId, blockId }: { flowId: string; blockId: string }) => {
|
|
171
|
-
return
|
|
173
|
+
return c.post(`/blocks/${blockId}/generate-tts`, { flowId }, 'eduflow');
|
|
172
174
|
},
|
|
173
175
|
},
|
|
174
|
-
};
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Backward compatibility for stdio mode
|
|
180
|
+
export const blocksTools = createBlocksTools(defaultClient);
|
package/src/tools/connections.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { LyrraClient } from '../client.js';
|
|
3
|
+
import { client as defaultClient } from '../client.js';
|
|
3
4
|
|
|
4
|
-
export
|
|
5
|
+
export function createConnectionsTools(c: LyrraClient) {
|
|
6
|
+
return {
|
|
5
7
|
connection_list: {
|
|
6
8
|
description: `Lister toutes les connexions (edges) d'un parcours EduFlow. Chaque connexion relie un bloc source à un bloc cible.
|
|
7
9
|
Règles de connexion :
|
|
@@ -14,7 +16,7 @@ Règles de connexion :
|
|
|
14
16
|
flowId: z.string().uuid().describe('ID du parcours'),
|
|
15
17
|
}),
|
|
16
18
|
handler: async ({ flowId }: { flowId: string }) => {
|
|
17
|
-
const flow = await
|
|
19
|
+
const flow = await c.get(`/flows/${flowId}`, 'eduflow');
|
|
18
20
|
return {
|
|
19
21
|
edges: flow.edges || [],
|
|
20
22
|
blocks: (flow.blocks || []).map((b: any) => ({ id: b.id, type: b.type, title: b.title })),
|
|
@@ -32,7 +34,7 @@ Règles de connexion :
|
|
|
32
34
|
animated: z.boolean().optional().describe('Animer la connexion visuellement'),
|
|
33
35
|
}),
|
|
34
36
|
handler: async ({ flowId, source, target, label, animated }: any) => {
|
|
35
|
-
const flow = await
|
|
37
|
+
const flow = await c.get(`/flows/${flowId}`, 'eduflow');
|
|
36
38
|
const edges = flow.edges || [];
|
|
37
39
|
const newEdge = {
|
|
38
40
|
id: `e-${source}-${target}`,
|
|
@@ -47,7 +49,7 @@ Règles de connexion :
|
|
|
47
49
|
return { success: false, error: 'Cette connexion existe déjà' };
|
|
48
50
|
}
|
|
49
51
|
edges.push(newEdge);
|
|
50
|
-
await
|
|
52
|
+
await c.put(`/flows/${flowId}`, { edges }, 'eduflow');
|
|
51
53
|
return { success: true, edge: newEdge, totalEdges: edges.length };
|
|
52
54
|
},
|
|
53
55
|
},
|
|
@@ -61,7 +63,7 @@ Règles de connexion :
|
|
|
61
63
|
target: z.string().optional().describe('Alternative : ID du bloc cible'),
|
|
62
64
|
}),
|
|
63
65
|
handler: async ({ flowId, edgeId, source, target }: any) => {
|
|
64
|
-
const flow = await
|
|
66
|
+
const flow = await c.get(`/flows/${flowId}`, 'eduflow');
|
|
65
67
|
let edges = flow.edges || [];
|
|
66
68
|
if (edgeId) {
|
|
67
69
|
edges = edges.filter((e: any) => e.id !== edgeId);
|
|
@@ -70,8 +72,12 @@ Règles de connexion :
|
|
|
70
72
|
} else {
|
|
71
73
|
return { success: false, error: 'Fournir edgeId OU source+target' };
|
|
72
74
|
}
|
|
73
|
-
await
|
|
75
|
+
await c.put(`/flows/${flowId}`, { edges }, 'eduflow');
|
|
74
76
|
return { success: true, remainingEdges: edges.length };
|
|
75
77
|
},
|
|
76
78
|
},
|
|
77
|
-
};
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Backward compatibility for stdio mode
|
|
83
|
+
export const connectionsTools = createConnectionsTools(defaultClient);
|