@centrali-io/centrali-mcp 4.2.1 → 4.2.2
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/tools/compute.js +323 -0
- package/dist/tools/describe.js +179 -3
- package/dist/tools/orchestrations.js +146 -0
- package/dist/tools/smart-queries.js +152 -0
- package/dist/tools/structures.js +117 -0
- package/package.json +1 -1
- package/src/tools/compute.ts +371 -0
- package/src/tools/describe.ts +179 -3
- package/src/tools/orchestrations.ts +167 -0
- package/src/tools/smart-queries.ts +175 -0
- package/src/tools/structures.ts +123 -0
|
@@ -206,4 +206,171 @@ export function registerOrchestrationTools(server: McpServer, sdk: CentraliSDK)
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
);
|
|
209
|
+
|
|
210
|
+
server.tool(
|
|
211
|
+
"create_orchestration",
|
|
212
|
+
"Create a new orchestration workflow. Orchestrations chain compute functions together in multi-step workflows.",
|
|
213
|
+
{
|
|
214
|
+
slug: z.string().describe("URL-friendly unique slug (e.g., 'order-processing')"),
|
|
215
|
+
name: z.string().describe("Human-readable name"),
|
|
216
|
+
description: z.string().optional().describe("Optional description of the workflow"),
|
|
217
|
+
trigger: z
|
|
218
|
+
.record(z.string(), z.any())
|
|
219
|
+
.describe("Trigger configuration object. Must include 'type' (on-demand, event-driven, scheduled, webhook)"),
|
|
220
|
+
steps: z
|
|
221
|
+
.array(z.record(z.string(), z.any()))
|
|
222
|
+
.describe("Array of step definitions. Each step has id, type, functionId, and optional onSuccess/onFailure routing"),
|
|
223
|
+
},
|
|
224
|
+
async ({ slug, name, description, trigger, steps }) => {
|
|
225
|
+
try {
|
|
226
|
+
const input: Record<string, any> = { slug, name, trigger, steps };
|
|
227
|
+
if (description !== undefined) input.description = description;
|
|
228
|
+
|
|
229
|
+
const result = await sdk.orchestrations.create(input as any);
|
|
230
|
+
return {
|
|
231
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
232
|
+
};
|
|
233
|
+
} catch (error: unknown) {
|
|
234
|
+
return {
|
|
235
|
+
content: [
|
|
236
|
+
{
|
|
237
|
+
type: "text",
|
|
238
|
+
text: formatError(error, `creating orchestration '${slug}'`),
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
isError: true,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
server.tool(
|
|
248
|
+
"update_orchestration",
|
|
249
|
+
"Update an existing orchestration by ID. Only include the fields you want to change.",
|
|
250
|
+
{
|
|
251
|
+
orchestrationId: z.string().describe("The orchestration ID (UUID) to update"),
|
|
252
|
+
name: z.string().optional().describe("Updated name"),
|
|
253
|
+
description: z.string().optional().describe("Updated description"),
|
|
254
|
+
status: z
|
|
255
|
+
.enum(["draft", "active", "paused"])
|
|
256
|
+
.optional()
|
|
257
|
+
.describe("Updated status"),
|
|
258
|
+
trigger: z
|
|
259
|
+
.record(z.string(), z.any())
|
|
260
|
+
.optional()
|
|
261
|
+
.describe("Updated trigger configuration"),
|
|
262
|
+
steps: z
|
|
263
|
+
.array(z.record(z.string(), z.any()))
|
|
264
|
+
.optional()
|
|
265
|
+
.describe("Updated step definitions"),
|
|
266
|
+
},
|
|
267
|
+
async ({ orchestrationId, name, description, status, trigger, steps }) => {
|
|
268
|
+
try {
|
|
269
|
+
const input: Record<string, any> = {};
|
|
270
|
+
if (name !== undefined) input.name = name;
|
|
271
|
+
if (description !== undefined) input.description = description;
|
|
272
|
+
if (status !== undefined) input.status = status;
|
|
273
|
+
if (trigger !== undefined) input.trigger = trigger;
|
|
274
|
+
if (steps !== undefined) input.steps = steps;
|
|
275
|
+
|
|
276
|
+
const result = await sdk.orchestrations.update(orchestrationId, input as any);
|
|
277
|
+
return {
|
|
278
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
279
|
+
};
|
|
280
|
+
} catch (error: unknown) {
|
|
281
|
+
return {
|
|
282
|
+
content: [
|
|
283
|
+
{
|
|
284
|
+
type: "text",
|
|
285
|
+
text: formatError(error, `updating orchestration '${orchestrationId}'`),
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
isError: true,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
server.tool(
|
|
295
|
+
"delete_orchestration",
|
|
296
|
+
"Delete an orchestration by ID. This also deletes all runs associated with the orchestration.",
|
|
297
|
+
{
|
|
298
|
+
orchestrationId: z.string().describe("The orchestration ID (UUID) to delete"),
|
|
299
|
+
},
|
|
300
|
+
async ({ orchestrationId }) => {
|
|
301
|
+
try {
|
|
302
|
+
await sdk.orchestrations.delete(orchestrationId);
|
|
303
|
+
return {
|
|
304
|
+
content: [
|
|
305
|
+
{
|
|
306
|
+
type: "text",
|
|
307
|
+
text: `Orchestration '${orchestrationId}' deleted successfully.`,
|
|
308
|
+
},
|
|
309
|
+
],
|
|
310
|
+
};
|
|
311
|
+
} catch (error: unknown) {
|
|
312
|
+
return {
|
|
313
|
+
content: [
|
|
314
|
+
{
|
|
315
|
+
type: "text",
|
|
316
|
+
text: formatError(error, `deleting orchestration '${orchestrationId}'`),
|
|
317
|
+
},
|
|
318
|
+
],
|
|
319
|
+
isError: true,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
server.tool(
|
|
326
|
+
"activate_orchestration",
|
|
327
|
+
"Activate an orchestration. Active orchestrations can be triggered by scheduled events, record events, and webhooks.",
|
|
328
|
+
{
|
|
329
|
+
orchestrationId: z.string().describe("The orchestration ID (UUID) to activate"),
|
|
330
|
+
},
|
|
331
|
+
async ({ orchestrationId }) => {
|
|
332
|
+
try {
|
|
333
|
+
const result = await sdk.orchestrations.activate(orchestrationId);
|
|
334
|
+
return {
|
|
335
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
336
|
+
};
|
|
337
|
+
} catch (error: unknown) {
|
|
338
|
+
return {
|
|
339
|
+
content: [
|
|
340
|
+
{
|
|
341
|
+
type: "text",
|
|
342
|
+
text: formatError(error, `activating orchestration '${orchestrationId}'`),
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
isError: true,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
server.tool(
|
|
352
|
+
"pause_orchestration",
|
|
353
|
+
"Pause an orchestration. Paused orchestrations cannot be triggered by any mechanism.",
|
|
354
|
+
{
|
|
355
|
+
orchestrationId: z.string().describe("The orchestration ID (UUID) to pause"),
|
|
356
|
+
},
|
|
357
|
+
async ({ orchestrationId }) => {
|
|
358
|
+
try {
|
|
359
|
+
const result = await sdk.orchestrations.pause(orchestrationId);
|
|
360
|
+
return {
|
|
361
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
362
|
+
};
|
|
363
|
+
} catch (error: unknown) {
|
|
364
|
+
return {
|
|
365
|
+
content: [
|
|
366
|
+
{
|
|
367
|
+
type: "text",
|
|
368
|
+
text: formatError(error, `pausing orchestration '${orchestrationId}'`),
|
|
369
|
+
},
|
|
370
|
+
],
|
|
371
|
+
isError: true,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
);
|
|
209
376
|
}
|
|
@@ -100,4 +100,179 @@ export function registerSmartQueryTools(server: McpServer, sdk: CentraliSDK) {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
);
|
|
103
|
+
|
|
104
|
+
server.tool(
|
|
105
|
+
"get_smart_query",
|
|
106
|
+
"Get a smart query by ID. Returns the full query definition including filters, sort, and variable declarations.",
|
|
107
|
+
{
|
|
108
|
+
recordSlug: z.string().describe("The structure's record slug the query belongs to"),
|
|
109
|
+
queryId: z.string().describe("The smart query ID (UUID)"),
|
|
110
|
+
},
|
|
111
|
+
async ({ recordSlug, queryId }) => {
|
|
112
|
+
try {
|
|
113
|
+
const result = await sdk.smartQueries.get(recordSlug, queryId);
|
|
114
|
+
return {
|
|
115
|
+
content: [
|
|
116
|
+
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
117
|
+
],
|
|
118
|
+
};
|
|
119
|
+
} catch (error: unknown) {
|
|
120
|
+
return {
|
|
121
|
+
content: [
|
|
122
|
+
{
|
|
123
|
+
type: "text",
|
|
124
|
+
text: formatError(error, `getting smart query '${queryId}'`),
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
isError: true,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
server.tool(
|
|
134
|
+
"create_smart_query",
|
|
135
|
+
"Create a new smart query for a collection. Smart queries are reusable, parameterized queries with filter, sort, and variable support.",
|
|
136
|
+
{
|
|
137
|
+
recordSlug: z.string().describe("The structure's record slug to create the query for"),
|
|
138
|
+
name: z.string().describe("Display name for the smart query"),
|
|
139
|
+
description: z.string().optional().describe("Optional description"),
|
|
140
|
+
queryDefinition: z
|
|
141
|
+
.record(z.string(), z.any())
|
|
142
|
+
.describe("The query definition object with where, sort, limit, select, join, etc."),
|
|
143
|
+
},
|
|
144
|
+
async ({ recordSlug, name, description, queryDefinition }) => {
|
|
145
|
+
try {
|
|
146
|
+
const input: Record<string, any> = { name, queryDefinition };
|
|
147
|
+
if (description !== undefined) input.description = description;
|
|
148
|
+
|
|
149
|
+
const result = await sdk.smartQueries.create(recordSlug, input as any);
|
|
150
|
+
return {
|
|
151
|
+
content: [
|
|
152
|
+
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
153
|
+
],
|
|
154
|
+
};
|
|
155
|
+
} catch (error: unknown) {
|
|
156
|
+
return {
|
|
157
|
+
content: [
|
|
158
|
+
{
|
|
159
|
+
type: "text",
|
|
160
|
+
text: formatError(error, `creating smart query '${name}' for '${recordSlug}'`),
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
isError: true,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
server.tool(
|
|
170
|
+
"update_smart_query",
|
|
171
|
+
"Update an existing smart query. Only include the fields you want to change.",
|
|
172
|
+
{
|
|
173
|
+
recordSlug: z.string().describe("The structure's record slug the query belongs to"),
|
|
174
|
+
queryId: z.string().describe("The smart query ID (UUID) to update"),
|
|
175
|
+
name: z.string().optional().describe("Updated display name"),
|
|
176
|
+
description: z.string().optional().describe("Updated description"),
|
|
177
|
+
queryDefinition: z
|
|
178
|
+
.record(z.string(), z.any())
|
|
179
|
+
.optional()
|
|
180
|
+
.describe("Updated query definition object"),
|
|
181
|
+
},
|
|
182
|
+
async ({ recordSlug, queryId, name, description, queryDefinition }) => {
|
|
183
|
+
try {
|
|
184
|
+
const input: Record<string, any> = {};
|
|
185
|
+
if (name !== undefined) input.name = name;
|
|
186
|
+
if (description !== undefined) input.description = description;
|
|
187
|
+
if (queryDefinition !== undefined) input.queryDefinition = queryDefinition;
|
|
188
|
+
|
|
189
|
+
const result = await sdk.smartQueries.update(recordSlug, queryId, input as any);
|
|
190
|
+
return {
|
|
191
|
+
content: [
|
|
192
|
+
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
193
|
+
],
|
|
194
|
+
};
|
|
195
|
+
} catch (error: unknown) {
|
|
196
|
+
return {
|
|
197
|
+
content: [
|
|
198
|
+
{
|
|
199
|
+
type: "text",
|
|
200
|
+
text: formatError(error, `updating smart query '${queryId}'`),
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
isError: true,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
server.tool(
|
|
210
|
+
"delete_smart_query",
|
|
211
|
+
"Delete a smart query by ID.",
|
|
212
|
+
{
|
|
213
|
+
recordSlug: z.string().describe("The structure's record slug the query belongs to"),
|
|
214
|
+
queryId: z.string().describe("The smart query ID (UUID) to delete"),
|
|
215
|
+
},
|
|
216
|
+
async ({ recordSlug, queryId }) => {
|
|
217
|
+
try {
|
|
218
|
+
await sdk.smartQueries.delete(recordSlug, queryId);
|
|
219
|
+
return {
|
|
220
|
+
content: [
|
|
221
|
+
{
|
|
222
|
+
type: "text",
|
|
223
|
+
text: `Smart query '${queryId}' deleted from '${recordSlug}'.`,
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
};
|
|
227
|
+
} catch (error: unknown) {
|
|
228
|
+
return {
|
|
229
|
+
content: [
|
|
230
|
+
{
|
|
231
|
+
type: "text",
|
|
232
|
+
text: formatError(error, `deleting smart query '${queryId}'`),
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
isError: true,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
server.tool(
|
|
242
|
+
"test_smart_query",
|
|
243
|
+
"Test execute a query definition without saving it. Useful for validating query syntax and previewing results before creating a smart query.",
|
|
244
|
+
{
|
|
245
|
+
recordSlug: z.string().describe("The structure's record slug to test against"),
|
|
246
|
+
queryDefinition: z
|
|
247
|
+
.record(z.string(), z.any())
|
|
248
|
+
.describe("The query definition to test (where, sort, limit, select, etc.)"),
|
|
249
|
+
variables: z
|
|
250
|
+
.record(z.string(), z.string())
|
|
251
|
+
.optional()
|
|
252
|
+
.describe("Optional variables to substitute in the query"),
|
|
253
|
+
},
|
|
254
|
+
async ({ recordSlug, queryDefinition, variables }) => {
|
|
255
|
+
try {
|
|
256
|
+
const input: Record<string, any> = { queryDefinition };
|
|
257
|
+
if (variables !== undefined) input.variables = variables;
|
|
258
|
+
|
|
259
|
+
const result = await sdk.smartQueries.test(recordSlug, input as any);
|
|
260
|
+
return {
|
|
261
|
+
content: [
|
|
262
|
+
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
263
|
+
],
|
|
264
|
+
};
|
|
265
|
+
} catch (error: unknown) {
|
|
266
|
+
return {
|
|
267
|
+
content: [
|
|
268
|
+
{
|
|
269
|
+
type: "text",
|
|
270
|
+
text: formatError(error, `test-executing smart query for '${recordSlug}'`),
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
isError: true,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
);
|
|
103
278
|
}
|
package/src/tools/structures.ts
CHANGED
|
@@ -143,4 +143,127 @@ export function registerCollectionTools(server: McpServer, sdk: CentraliSDK) {
|
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
);
|
|
146
|
+
|
|
147
|
+
server.tool(
|
|
148
|
+
"create_collection",
|
|
149
|
+
"Create a new data collection (schema). Define the name, slug, description, and properties (fields) for the collection.",
|
|
150
|
+
{
|
|
151
|
+
name: z.string().describe("Display name for the collection (e.g., 'Customers')"),
|
|
152
|
+
slug: z.string().describe("URL-safe identifier used in API calls (e.g., 'customers')"),
|
|
153
|
+
description: z.string().optional().describe("Optional description of the collection"),
|
|
154
|
+
properties: z
|
|
155
|
+
.array(z.record(z.string(), z.any()))
|
|
156
|
+
.optional()
|
|
157
|
+
.describe("Array of property definitions. Each property has name, type, and optional config (required, unique, defaultValue, description, config)"),
|
|
158
|
+
enableVersioning: z.boolean().optional().describe("Enable record versioning (default: false)"),
|
|
159
|
+
schemaDiscoveryMode: z
|
|
160
|
+
.enum(["strict", "flexible"])
|
|
161
|
+
.optional()
|
|
162
|
+
.describe("Schema discovery mode: 'strict' rejects unknown fields, 'flexible' auto-adds them"),
|
|
163
|
+
tags: z.array(z.string()).optional().describe("Optional tags for organizing collections"),
|
|
164
|
+
},
|
|
165
|
+
async ({ name, slug, description, properties, enableVersioning, schemaDiscoveryMode, tags }) => {
|
|
166
|
+
try {
|
|
167
|
+
const input: Record<string, any> = { name, slug };
|
|
168
|
+
if (description !== undefined) input.description = description;
|
|
169
|
+
if (properties !== undefined) input.properties = properties;
|
|
170
|
+
if (enableVersioning !== undefined) input.enableVersioning = enableVersioning;
|
|
171
|
+
if (schemaDiscoveryMode !== undefined) input.schemaDiscoveryMode = schemaDiscoveryMode;
|
|
172
|
+
if (tags !== undefined) input.tags = tags;
|
|
173
|
+
|
|
174
|
+
const result = await sdk.collections.create(input as any);
|
|
175
|
+
return {
|
|
176
|
+
content: [
|
|
177
|
+
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
178
|
+
],
|
|
179
|
+
};
|
|
180
|
+
} catch (error: unknown) {
|
|
181
|
+
return {
|
|
182
|
+
content: [
|
|
183
|
+
{
|
|
184
|
+
type: "text",
|
|
185
|
+
text: formatError(error, `creating collection '${slug}'`),
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
isError: true,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
server.tool(
|
|
195
|
+
"update_collection",
|
|
196
|
+
"Update an existing collection by ID. Only include the fields you want to change.",
|
|
197
|
+
{
|
|
198
|
+
collectionId: z.string().describe("The collection ID (UUID) to update"),
|
|
199
|
+
name: z.string().optional().describe("Updated display name"),
|
|
200
|
+
description: z.string().optional().describe("Updated description"),
|
|
201
|
+
properties: z
|
|
202
|
+
.array(z.record(z.string(), z.any()))
|
|
203
|
+
.optional()
|
|
204
|
+
.describe("Updated array of property definitions (replaces existing properties)"),
|
|
205
|
+
enableVersioning: z.boolean().optional().describe("Enable or disable record versioning"),
|
|
206
|
+
tags: z.array(z.string()).optional().describe("Updated tags"),
|
|
207
|
+
defaultTtlSeconds: z.number().nullable().optional().describe("Default TTL in seconds for new records. Set to null to clear."),
|
|
208
|
+
},
|
|
209
|
+
async ({ collectionId, name, description, properties, enableVersioning, tags, defaultTtlSeconds }) => {
|
|
210
|
+
try {
|
|
211
|
+
const input: Record<string, any> = {};
|
|
212
|
+
if (name !== undefined) input.name = name;
|
|
213
|
+
if (description !== undefined) input.description = description;
|
|
214
|
+
if (properties !== undefined) input.properties = properties;
|
|
215
|
+
if (enableVersioning !== undefined) input.enableVersioning = enableVersioning;
|
|
216
|
+
if (tags !== undefined) input.tags = tags;
|
|
217
|
+
if (defaultTtlSeconds !== undefined) input.defaultTtlSeconds = defaultTtlSeconds;
|
|
218
|
+
|
|
219
|
+
const result = await sdk.collections.update(collectionId, input as any);
|
|
220
|
+
return {
|
|
221
|
+
content: [
|
|
222
|
+
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
223
|
+
],
|
|
224
|
+
};
|
|
225
|
+
} catch (error: unknown) {
|
|
226
|
+
return {
|
|
227
|
+
content: [
|
|
228
|
+
{
|
|
229
|
+
type: "text",
|
|
230
|
+
text: formatError(error, `updating collection '${collectionId}'`),
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
isError: true,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
server.tool(
|
|
240
|
+
"delete_collection",
|
|
241
|
+
"Delete a collection by ID. This permanently removes the collection schema and all its records.",
|
|
242
|
+
{
|
|
243
|
+
collectionId: z.string().describe("The collection ID (UUID) to delete"),
|
|
244
|
+
},
|
|
245
|
+
async ({ collectionId }) => {
|
|
246
|
+
try {
|
|
247
|
+
await sdk.collections.delete(collectionId);
|
|
248
|
+
return {
|
|
249
|
+
content: [
|
|
250
|
+
{
|
|
251
|
+
type: "text",
|
|
252
|
+
text: `Collection '${collectionId}' deleted successfully.`,
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
};
|
|
256
|
+
} catch (error: unknown) {
|
|
257
|
+
return {
|
|
258
|
+
content: [
|
|
259
|
+
{
|
|
260
|
+
type: "text",
|
|
261
|
+
text: formatError(error, `deleting collection '${collectionId}'`),
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
isError: true,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
);
|
|
146
269
|
}
|