@cerema/cadriciel-mcp 0.1.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 (53) hide show
  1. package/Dockerfile +26 -0
  2. package/README.md +98 -0
  3. package/dist/client.d.ts +31 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +77 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/http-server.d.ts +13 -0
  8. package/dist/http-server.d.ts.map +1 -0
  9. package/dist/http-server.js +184 -0
  10. package/dist/http-server.js.map +1 -0
  11. package/dist/index.d.ts +17 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +64 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/tools/database.d.ts +70 -0
  16. package/dist/tools/database.d.ts.map +1 -0
  17. package/dist/tools/database.js +77 -0
  18. package/dist/tools/database.js.map +1 -0
  19. package/dist/tools/deploy.d.ts +73 -0
  20. package/dist/tools/deploy.d.ts.map +1 -0
  21. package/dist/tools/deploy.js +103 -0
  22. package/dist/tools/deploy.js.map +1 -0
  23. package/dist/tools/handlers.d.ts +13 -0
  24. package/dist/tools/handlers.d.ts.map +1 -0
  25. package/dist/tools/handlers.js +225 -0
  26. package/dist/tools/handlers.js.map +1 -0
  27. package/dist/tools/index.d.ts +11 -0
  28. package/dist/tools/index.d.ts.map +1 -0
  29. package/dist/tools/index.js +298 -0
  30. package/dist/tools/index.js.map +1 -0
  31. package/dist/tools/projects.d.ts +45 -0
  32. package/dist/tools/projects.d.ts.map +1 -0
  33. package/dist/tools/projects.js +71 -0
  34. package/dist/tools/projects.js.map +1 -0
  35. package/dist/tools/workflows.d.ts +66 -0
  36. package/dist/tools/workflows.d.ts.map +1 -0
  37. package/dist/tools/workflows.js +90 -0
  38. package/dist/tools/workflows.js.map +1 -0
  39. package/k8s/deployment.yaml +48 -0
  40. package/k8s/ingress.yaml +27 -0
  41. package/k8s/kustomization.yaml +14 -0
  42. package/k8s/service.yaml +15 -0
  43. package/package.json +36 -0
  44. package/src/client.ts +97 -0
  45. package/src/http-server.ts +213 -0
  46. package/src/index.ts +75 -0
  47. package/src/tools/database.ts +105 -0
  48. package/src/tools/deploy.ts +127 -0
  49. package/src/tools/handlers.ts +241 -0
  50. package/src/tools/index.ts +275 -0
  51. package/src/tools/projects.ts +89 -0
  52. package/src/tools/workflows.ts +117 -0
  53. package/tsconfig.json +19 -0
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Tool Handlers Factory
3
+ *
4
+ * Creates tool handlers bound to a specific Cadriciel client.
5
+ * Used by the HTTP server where each session has its own client.
6
+ */
7
+
8
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
9
+ import {
10
+ CallToolRequestSchema,
11
+ ListToolsRequestSchema,
12
+ } from '@modelcontextprotocol/sdk/types.js';
13
+ import { CadricielClient } from '../client';
14
+
15
+ /**
16
+ * Tool definitions (schema only, handlers are created dynamically)
17
+ */
18
+ const TOOL_DEFINITIONS = [
19
+ {
20
+ name: 'list_projects',
21
+ description: 'List all Cadriciel projects accessible by the authenticated user',
22
+ inputSchema: {
23
+ type: 'object' as const,
24
+ properties: {},
25
+ required: [],
26
+ },
27
+ },
28
+ {
29
+ name: 'get_project',
30
+ description: 'Get detailed information about a specific project',
31
+ inputSchema: {
32
+ type: 'object' as const,
33
+ properties: {
34
+ projectId: {
35
+ type: 'number',
36
+ description: 'The project ID',
37
+ },
38
+ },
39
+ required: ['projectId'],
40
+ },
41
+ },
42
+ {
43
+ name: 'list_workflows',
44
+ description: 'List all workflows in a workspace',
45
+ inputSchema: {
46
+ type: 'object' as const,
47
+ properties: {
48
+ workspaceId: {
49
+ type: 'number',
50
+ description: 'The workspace/project ID',
51
+ },
52
+ },
53
+ required: ['workspaceId'],
54
+ },
55
+ },
56
+ {
57
+ name: 'execute_workflow',
58
+ description: 'Execute a workflow with optional input parameters',
59
+ inputSchema: {
60
+ type: 'object' as const,
61
+ properties: {
62
+ workspaceId: {
63
+ type: 'number',
64
+ description: 'The workspace/project ID',
65
+ },
66
+ workflowId: {
67
+ type: 'string',
68
+ description: 'The workflow ID to execute',
69
+ },
70
+ input: {
71
+ type: 'object',
72
+ description: 'Input parameters for the workflow',
73
+ },
74
+ },
75
+ required: ['workspaceId', 'workflowId'],
76
+ },
77
+ },
78
+ {
79
+ name: 'get_execution',
80
+ description: 'Get the status and results of a workflow execution',
81
+ inputSchema: {
82
+ type: 'object' as const,
83
+ properties: {
84
+ workspaceId: {
85
+ type: 'number',
86
+ description: 'The workspace/project ID',
87
+ },
88
+ executionId: {
89
+ type: 'string',
90
+ description: 'The execution ID',
91
+ },
92
+ },
93
+ required: ['workspaceId', 'executionId'],
94
+ },
95
+ },
96
+ {
97
+ name: 'get_schema',
98
+ description: 'Get the database schema (tables, columns, relationships)',
99
+ inputSchema: {
100
+ type: 'object' as const,
101
+ properties: {
102
+ workspaceId: {
103
+ type: 'number',
104
+ description: 'The workspace/project ID',
105
+ },
106
+ },
107
+ required: ['workspaceId'],
108
+ },
109
+ },
110
+ {
111
+ name: 'query_database',
112
+ description: 'Execute a read-only SQL query (SELECT only)',
113
+ inputSchema: {
114
+ type: 'object' as const,
115
+ properties: {
116
+ workspaceId: {
117
+ type: 'number',
118
+ description: 'The workspace/project ID',
119
+ },
120
+ query: {
121
+ type: 'string',
122
+ description: 'SQL SELECT query to execute',
123
+ },
124
+ },
125
+ required: ['workspaceId', 'query'],
126
+ },
127
+ },
128
+ ];
129
+
130
+ /**
131
+ * Create tool handler implementations bound to a client
132
+ */
133
+ function createHandlers(client: CadricielClient) {
134
+ return {
135
+ // ============================================================
136
+ // IMPLEMENTED
137
+ // ============================================================
138
+
139
+ async list_projects() {
140
+ const response = await client.get('/api/studio/projects');
141
+ if (!response.success) {
142
+ throw new Error(`Failed to list projects: ${response.error}`);
143
+ }
144
+ const projects = (response.data || []).map((p: any) => ({
145
+ id: p.id,
146
+ name: p.name || p.title,
147
+ description: p.description,
148
+ path: p.path || p.path_with_namespace,
149
+ created_at: p.created_at,
150
+ updated_at: p.updated_at || p.last_activity_at,
151
+ }));
152
+ return { projects };
153
+ },
154
+
155
+ // ============================================================
156
+ // TODO: Implement these
157
+ // ============================================================
158
+
159
+ async get_project(args: { projectId: number }) {
160
+ // TODO: Implement
161
+ // const response = await client.get(`/api/studio/workspace/${args.projectId}`);
162
+ throw new Error('Not implemented yet');
163
+ },
164
+
165
+ async list_workflows(args: { workspaceId: number }) {
166
+ // TODO: Implement
167
+ // const response = await client.get(`/api/studio/workspace/${args.workspaceId}/airjobs/workflows`);
168
+ throw new Error('Not implemented yet');
169
+ },
170
+
171
+ async execute_workflow(args: { workspaceId: number; workflowId: string; input?: any }) {
172
+ // TODO: Implement
173
+ // const response = await client.post(`/api/studio/workspace/${args.workspaceId}/airjobs/execute`, { ... });
174
+ throw new Error('Not implemented yet');
175
+ },
176
+
177
+ async get_execution(args: { workspaceId: number; executionId: string }) {
178
+ // TODO: Implement
179
+ // const response = await client.get(`/api/studio/workspace/${args.workspaceId}/airjobs/executions?id=${args.executionId}`);
180
+ throw new Error('Not implemented yet');
181
+ },
182
+
183
+ async get_schema(args: { workspaceId: number }) {
184
+ // TODO: Implement
185
+ // const response = await client.get(`/api/studio/workspace/${args.workspaceId}/db/tables`);
186
+ throw new Error('Not implemented yet');
187
+ },
188
+
189
+ async query_database(args: { workspaceId: number; query: string }) {
190
+ // TODO: Implement
191
+ // IMPORTANT: Validate query is SELECT only
192
+ // const response = await client.post(`/api/studio/workspace/${args.workspaceId}/db/sql`, { sql: args.query });
193
+ throw new Error('Not implemented yet');
194
+ },
195
+ };
196
+ }
197
+
198
+ /**
199
+ * Register tool handlers with an MCP server
200
+ */
201
+ export function createToolHandlers(server: Server, client: CadricielClient): void {
202
+ const handlers = createHandlers(client);
203
+
204
+ // List available tools
205
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
206
+ return { tools: TOOL_DEFINITIONS };
207
+ });
208
+
209
+ // Handle tool calls
210
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
211
+ const { name, arguments: args } = request.params;
212
+
213
+ const handler = (handlers as any)[name];
214
+ if (!handler) {
215
+ throw new Error(`Unknown tool: ${name}`);
216
+ }
217
+
218
+ try {
219
+ const result = await handler(args);
220
+ return {
221
+ content: [
222
+ {
223
+ type: 'text',
224
+ text: JSON.stringify(result, null, 2),
225
+ },
226
+ ],
227
+ };
228
+ } catch (error) {
229
+ const message = error instanceof Error ? error.message : 'Unknown error';
230
+ return {
231
+ content: [
232
+ {
233
+ type: 'text',
234
+ text: `Error: ${message}`,
235
+ },
236
+ ],
237
+ isError: true,
238
+ };
239
+ }
240
+ });
241
+ }
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Tool Registry
3
+ *
4
+ * Registers all available MCP tools with their schemas and handlers.
5
+ */
6
+
7
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
8
+ import {
9
+ CallToolRequestSchema,
10
+ ListToolsRequestSchema,
11
+ } from '@modelcontextprotocol/sdk/types.js';
12
+
13
+ import * as projects from './projects';
14
+ import * as workflows from './workflows';
15
+ import * as database from './database';
16
+ import * as deploy from './deploy';
17
+
18
+ /**
19
+ * Tool definitions for MCP
20
+ */
21
+ const TOOLS = [
22
+ // ============================================================
23
+ // IMPLEMENTED
24
+ // ============================================================
25
+ {
26
+ name: 'list_projects',
27
+ description: 'List all Cadriciel projects accessible by the authenticated user',
28
+ inputSchema: {
29
+ type: 'object',
30
+ properties: {},
31
+ required: [],
32
+ },
33
+ handler: projects.listProjects,
34
+ },
35
+
36
+ // ============================================================
37
+ // TODO: Implement handlers for these tools
38
+ // ============================================================
39
+ {
40
+ name: 'get_project',
41
+ description: 'Get detailed information about a specific project',
42
+ inputSchema: {
43
+ type: 'object',
44
+ properties: {
45
+ projectId: {
46
+ type: 'number',
47
+ description: 'The project ID',
48
+ },
49
+ },
50
+ required: ['projectId'],
51
+ },
52
+ handler: async (args: { projectId: number }) => {
53
+ // TODO: Implement
54
+ throw new Error('Not implemented yet - see tools/projects.ts');
55
+ },
56
+ },
57
+ {
58
+ name: 'list_workflows',
59
+ description: 'List all workflows in a workspace',
60
+ inputSchema: {
61
+ type: 'object',
62
+ properties: {
63
+ workspaceId: {
64
+ type: 'number',
65
+ description: 'The workspace/project ID',
66
+ },
67
+ },
68
+ required: ['workspaceId'],
69
+ },
70
+ handler: async (args: { workspaceId: number }) => {
71
+ // TODO: Implement
72
+ throw new Error('Not implemented yet - see tools/workflows.ts');
73
+ },
74
+ },
75
+ {
76
+ name: 'execute_workflow',
77
+ description: 'Execute a workflow with optional input parameters',
78
+ inputSchema: {
79
+ type: 'object',
80
+ properties: {
81
+ workspaceId: {
82
+ type: 'number',
83
+ description: 'The workspace/project ID',
84
+ },
85
+ workflowId: {
86
+ type: 'string',
87
+ description: 'The workflow ID to execute',
88
+ },
89
+ input: {
90
+ type: 'object',
91
+ description: 'Input parameters for the workflow',
92
+ },
93
+ },
94
+ required: ['workspaceId', 'workflowId'],
95
+ },
96
+ handler: async (args: { workspaceId: number; workflowId: string; input?: any }) => {
97
+ // TODO: Implement
98
+ throw new Error('Not implemented yet - see tools/workflows.ts');
99
+ },
100
+ },
101
+ {
102
+ name: 'get_execution',
103
+ description: 'Get the status and results of a workflow execution',
104
+ inputSchema: {
105
+ type: 'object',
106
+ properties: {
107
+ workspaceId: {
108
+ type: 'number',
109
+ description: 'The workspace/project ID',
110
+ },
111
+ executionId: {
112
+ type: 'string',
113
+ description: 'The execution ID',
114
+ },
115
+ },
116
+ required: ['workspaceId', 'executionId'],
117
+ },
118
+ handler: async (args: { workspaceId: number; executionId: string }) => {
119
+ // TODO: Implement
120
+ throw new Error('Not implemented yet - see tools/workflows.ts');
121
+ },
122
+ },
123
+ {
124
+ name: 'get_schema',
125
+ description: 'Get the database schema (tables, columns, relationships)',
126
+ inputSchema: {
127
+ type: 'object',
128
+ properties: {
129
+ workspaceId: {
130
+ type: 'number',
131
+ description: 'The workspace/project ID',
132
+ },
133
+ },
134
+ required: ['workspaceId'],
135
+ },
136
+ handler: async (args: { workspaceId: number }) => {
137
+ // TODO: Implement
138
+ throw new Error('Not implemented yet - see tools/database.ts');
139
+ },
140
+ },
141
+ {
142
+ name: 'query_database',
143
+ description: 'Execute a read-only SQL query (SELECT only)',
144
+ inputSchema: {
145
+ type: 'object',
146
+ properties: {
147
+ workspaceId: {
148
+ type: 'number',
149
+ description: 'The workspace/project ID',
150
+ },
151
+ query: {
152
+ type: 'string',
153
+ description: 'SQL SELECT query to execute',
154
+ },
155
+ },
156
+ required: ['workspaceId', 'query'],
157
+ },
158
+ handler: async (args: { workspaceId: number; query: string }) => {
159
+ // TODO: Implement
160
+ throw new Error('Not implemented yet - see tools/database.ts');
161
+ },
162
+ },
163
+ {
164
+ name: 'get_deployment_status',
165
+ description: 'Get the current deployment status of a project',
166
+ inputSchema: {
167
+ type: 'object',
168
+ properties: {
169
+ workspaceId: {
170
+ type: 'number',
171
+ description: 'The workspace/project ID',
172
+ },
173
+ },
174
+ required: ['workspaceId'],
175
+ },
176
+ handler: async (args: { workspaceId: number }) => {
177
+ // TODO: Implement
178
+ throw new Error('Not implemented yet - see tools/deploy.ts');
179
+ },
180
+ },
181
+ {
182
+ name: 'get_env_vars',
183
+ description: 'Get environment variables for a project (values hidden)',
184
+ inputSchema: {
185
+ type: 'object',
186
+ properties: {
187
+ workspaceId: {
188
+ type: 'number',
189
+ description: 'The workspace/project ID',
190
+ },
191
+ },
192
+ required: ['workspaceId'],
193
+ },
194
+ handler: async (args: { workspaceId: number }) => {
195
+ // TODO: Implement
196
+ throw new Error('Not implemented yet - see tools/deploy.ts');
197
+ },
198
+ },
199
+ {
200
+ name: 'service_control',
201
+ description: 'Control services (start, stop, restart)',
202
+ inputSchema: {
203
+ type: 'object',
204
+ properties: {
205
+ workspaceId: {
206
+ type: 'number',
207
+ description: 'The workspace/project ID',
208
+ },
209
+ action: {
210
+ type: 'string',
211
+ enum: ['start', 'stop', 'restart'],
212
+ description: 'Action to perform',
213
+ },
214
+ service: {
215
+ type: 'string',
216
+ description: 'Optional specific service name',
217
+ },
218
+ },
219
+ required: ['workspaceId', 'action'],
220
+ },
221
+ handler: async (args: { workspaceId: number; action: string; service?: string }) => {
222
+ // TODO: Implement
223
+ throw new Error('Not implemented yet - see tools/deploy.ts');
224
+ },
225
+ },
226
+ ];
227
+
228
+ /**
229
+ * Register all tools with the MCP server
230
+ */
231
+ export function registerTools(server: Server): void {
232
+ // List available tools
233
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
234
+ return {
235
+ tools: TOOLS.map(({ name, description, inputSchema }) => ({
236
+ name,
237
+ description,
238
+ inputSchema,
239
+ })),
240
+ };
241
+ });
242
+
243
+ // Handle tool calls
244
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
245
+ const { name, arguments: args } = request.params;
246
+
247
+ const tool = TOOLS.find((t) => t.name === name);
248
+ if (!tool) {
249
+ throw new Error(`Unknown tool: ${name}`);
250
+ }
251
+
252
+ try {
253
+ const result = await tool.handler(args as any);
254
+ return {
255
+ content: [
256
+ {
257
+ type: 'text',
258
+ text: JSON.stringify(result, null, 2),
259
+ },
260
+ ],
261
+ };
262
+ } catch (error) {
263
+ const message = error instanceof Error ? error.message : 'Unknown error';
264
+ return {
265
+ content: [
266
+ {
267
+ type: 'text',
268
+ text: `Error: ${message}`,
269
+ },
270
+ ],
271
+ isError: true,
272
+ };
273
+ }
274
+ });
275
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Project Tools
3
+ *
4
+ * Tools for managing Cadriciel projects.
5
+ */
6
+
7
+ import { getClient } from '../client';
8
+
9
+ // ============================================================
10
+ // IMPLEMENTED
11
+ // ============================================================
12
+
13
+ /**
14
+ * List all projects accessible by the authenticated user
15
+ */
16
+ export async function listProjects(): Promise<{
17
+ projects: Array<{
18
+ id: number;
19
+ name: string;
20
+ description?: string;
21
+ path: string;
22
+ created_at: string;
23
+ updated_at: string;
24
+ }>;
25
+ }> {
26
+ const client = getClient();
27
+ const response = await client.get('/api/studio/projects');
28
+
29
+ if (!response.success) {
30
+ throw new Error(`Failed to list projects: ${response.error}`);
31
+ }
32
+
33
+ // Map the response to a cleaner format
34
+ const projects = (response.data || []).map((p: any) => ({
35
+ id: p.id,
36
+ name: p.name || p.title,
37
+ description: p.description,
38
+ path: p.path || p.path_with_namespace,
39
+ created_at: p.created_at,
40
+ updated_at: p.updated_at || p.last_activity_at,
41
+ }));
42
+
43
+ return { projects };
44
+ }
45
+
46
+ // ============================================================
47
+ // TODO: Implement these tools
48
+ // ============================================================
49
+
50
+ /**
51
+ * TODO: Get detailed information about a specific project
52
+ *
53
+ * @param projectId - The project ID
54
+ * @returns Project details including config, members, environments
55
+ */
56
+ export async function getProject(projectId: number): Promise<any> {
57
+ // TODO: Implement
58
+ // Endpoint: GET /api/studio/workspace/:projectId
59
+ throw new Error('Not implemented yet');
60
+ }
61
+
62
+ /**
63
+ * TODO: Create a new project
64
+ *
65
+ * @param options - Project creation options
66
+ * @returns Created project details
67
+ */
68
+ export async function createProject(options: {
69
+ title: string;
70
+ description?: string;
71
+ template?: string;
72
+ mode?: 'fullstack' | 'frontend' | 'backend';
73
+ backendType?: 'node' | 'python' | 'springboot';
74
+ }): Promise<any> {
75
+ // TODO: Implement
76
+ // Endpoint: POST /api/studio/projects
77
+ throw new Error('Not implemented yet');
78
+ }
79
+
80
+ /**
81
+ * TODO: Delete a project
82
+ *
83
+ * @param projectId - The project ID to delete
84
+ */
85
+ export async function deleteProject(projectId: number): Promise<void> {
86
+ // TODO: Implement
87
+ // Endpoint: DELETE /api/studio/projects/:projectId
88
+ throw new Error('Not implemented yet');
89
+ }