@centrali-io/centrali-mcp 4.4.8-rc.4 → 4.4.8-rc.6
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/describe.js +136 -0
- package/package.json +2 -2
- package/src/tools/describe.ts +136 -0
package/dist/tools/describe.js
CHANGED
|
@@ -287,6 +287,142 @@ function registerDescribeTools(server) {
|
|
|
287
287
|
},
|
|
288
288
|
note: "workspaceId is the workspace slug (e.g., 'acme'), not a UUID. See https://docs.centrali.io/guides/centrali-sdk for the full guide.",
|
|
289
289
|
},
|
|
290
|
+
file_storage: {
|
|
291
|
+
description: "Centrali has built-in file storage (Azure Blob). Use the SDK to upload files and get render/download URLs. Not available via MCP — use in app code.",
|
|
292
|
+
folder_system: {
|
|
293
|
+
description: "Files live in folders. Every workspace starts with system folders: /root, /root/shared, /root/users, /root/_data_directory. You MUST create a folder before uploading to it — uploading to a non-existent folder will fail.",
|
|
294
|
+
system_folders: {
|
|
295
|
+
"/root/shared": "Default location for app files. Always exists. Create subfolders here (e.g., /root/shared/logos).",
|
|
296
|
+
"/root/users": "Per-user folders (managed by the platform)",
|
|
297
|
+
},
|
|
298
|
+
creating_folders: {
|
|
299
|
+
method: "client.createFolder(name, location?)",
|
|
300
|
+
example: "await centrali.createFolder('logos', '/root/shared'); // Creates /root/shared/logos",
|
|
301
|
+
note: "Defaults to /root/shared if location is omitted. Only needed when nesting deeper (e.g., creating a subfolder inside a subfolder — the parent must exist first).",
|
|
302
|
+
},
|
|
303
|
+
listing_folders: {
|
|
304
|
+
method: "client.listFolders(location?)",
|
|
305
|
+
example: "const folders = await centrali.listFolders('/root/shared');",
|
|
306
|
+
note: "Use this to check if a folder exists before uploading.",
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
upload: {
|
|
310
|
+
method: "client.uploadFile(file, location?, isPublic?)",
|
|
311
|
+
returns: "renderId (string) — use this to construct render/download URLs",
|
|
312
|
+
important: "Uploading to /root/shared works out of the box. For custom subfolders (e.g., /root/shared/logos), create the folder first if it doesn't exist.",
|
|
313
|
+
example: [
|
|
314
|
+
"// Next.js API route for file upload with folder creation",
|
|
315
|
+
"import { CentraliSDK } from '@centrali-io/centrali-sdk';",
|
|
316
|
+
"",
|
|
317
|
+
"export async function POST(req: Request) {",
|
|
318
|
+
" const formData = await req.formData();",
|
|
319
|
+
" const file = formData.get('file') as File;",
|
|
320
|
+
"",
|
|
321
|
+
" const centrali = new CentraliSDK({ baseUrl, workspaceId, clientId, clientSecret });",
|
|
322
|
+
"",
|
|
323
|
+
" // Ensure the target folder exists (create if needed)",
|
|
324
|
+
" const folders = await centrali.listFolders('/root/shared');",
|
|
325
|
+
" if (!folders.data.some((f: any) => f.name === 'logos')) {",
|
|
326
|
+
" await centrali.createFolder('logos', '/root/shared');",
|
|
327
|
+
" }",
|
|
328
|
+
"",
|
|
329
|
+
" const { data: renderId } = await centrali.uploadFile(file, '/root/shared/logos', true);",
|
|
330
|
+
" const url = centrali.getFileRenderUrl(renderId);",
|
|
331
|
+
"",
|
|
332
|
+
" // Store the URL on a record",
|
|
333
|
+
" await centrali.updateRecord('organizations', orgId, { logoUrl: url });",
|
|
334
|
+
"",
|
|
335
|
+
" return Response.json({ url });",
|
|
336
|
+
"}",
|
|
337
|
+
].join("\n"),
|
|
338
|
+
},
|
|
339
|
+
render_url: {
|
|
340
|
+
method: "client.getFileRenderUrl(renderId, options?)",
|
|
341
|
+
note: "Returns a URL that serves the file. Supports image transformations: width, height, fit ('cover'|'contain'|'fill'), format ('webp'|'png'|'jpeg'), quality (1-100).",
|
|
342
|
+
example: "const url = centrali.getFileRenderUrl(renderId, { width: 200, height: 200, fit: 'cover', format: 'webp' });",
|
|
343
|
+
},
|
|
344
|
+
download_url: {
|
|
345
|
+
method: "client.getFileDownloadUrl(renderId)",
|
|
346
|
+
note: "Returns a URL that triggers a file download.",
|
|
347
|
+
},
|
|
348
|
+
tips: [
|
|
349
|
+
"/root/shared always exists — upload there directly or create subfolders like /root/shared/logos",
|
|
350
|
+
"Set isPublic=true for files that need to be accessible without auth (logos, avatars, public images)",
|
|
351
|
+
"Store the renderId or full URL on a record field for easy retrieval",
|
|
352
|
+
"Use image transformations for thumbnails instead of uploading multiple sizes",
|
|
353
|
+
],
|
|
354
|
+
},
|
|
355
|
+
realtime: {
|
|
356
|
+
description: "Centrali supports real-time event streaming via SSE (Server-Sent Events). Use the SDK to subscribe to events across records, compute, orchestrations, validation, and anomaly detection. Not available via MCP — use in app code.",
|
|
357
|
+
event_types: {
|
|
358
|
+
records: [
|
|
359
|
+
"record_created — a new record was inserted",
|
|
360
|
+
"record_updated — a record was modified",
|
|
361
|
+
"record_deleted — a record was deleted",
|
|
362
|
+
"records_bulk_created — multiple records created in batch",
|
|
363
|
+
],
|
|
364
|
+
compute: [
|
|
365
|
+
"function_run_completed — a compute function finished successfully",
|
|
366
|
+
"function_run_failed — a compute function errored",
|
|
367
|
+
],
|
|
368
|
+
orchestrations: [
|
|
369
|
+
"orchestration_run_started — a workflow run began",
|
|
370
|
+
"orchestration_run_completed — a workflow run finished",
|
|
371
|
+
"orchestration_run_failed — a workflow run errored",
|
|
372
|
+
],
|
|
373
|
+
validation: [
|
|
374
|
+
"validation_suggestion_created — a new data quality suggestion was generated",
|
|
375
|
+
"validation_batch_completed — a validation scan batch finished",
|
|
376
|
+
],
|
|
377
|
+
anomalies: [
|
|
378
|
+
"anomaly_insight_created — a new anomaly was detected",
|
|
379
|
+
"anomaly_detection_completed — an anomaly scan finished",
|
|
380
|
+
],
|
|
381
|
+
},
|
|
382
|
+
subscribe: {
|
|
383
|
+
method: "client.realtime.subscribe(options)",
|
|
384
|
+
options: {
|
|
385
|
+
recordSlug: "string — filter to a specific collection (optional)",
|
|
386
|
+
events: "RealtimeEventType[] — filter to specific event types (optional, defaults to all)",
|
|
387
|
+
jobId: "string — filter compute events to a specific job (optional)",
|
|
388
|
+
triggerType: "string — filter compute events by trigger type (optional)",
|
|
389
|
+
orchestrationId: "string — filter orchestration events to a specific orchestration (optional)",
|
|
390
|
+
runId: "string — filter orchestration events to a specific run (optional)",
|
|
391
|
+
},
|
|
392
|
+
returns: "{ unsubscribe: () => void }",
|
|
393
|
+
example: [
|
|
394
|
+
"// Subscribe to all record changes for a collection",
|
|
395
|
+
"const sub = centrali.realtime.subscribe({",
|
|
396
|
+
" recordSlug: 'orders',",
|
|
397
|
+
" events: ['record_created', 'record_updated'],",
|
|
398
|
+
" onEvent: (event) => {",
|
|
399
|
+
" console.log(event.event, event.data);",
|
|
400
|
+
" // Refresh your UI, invalidate cache, etc.",
|
|
401
|
+
" },",
|
|
402
|
+
"});",
|
|
403
|
+
"",
|
|
404
|
+
"// Track a compute function run in real-time",
|
|
405
|
+
"const sub2 = centrali.realtime.subscribe({",
|
|
406
|
+
" events: ['function_run_completed', 'function_run_failed'],",
|
|
407
|
+
" jobId: 'some-job-id',",
|
|
408
|
+
" onEvent: (event) => {",
|
|
409
|
+
" if (event.event === 'function_run_completed') { /* success */ }",
|
|
410
|
+
" if (event.event === 'function_run_failed') { /* handle error */ }",
|
|
411
|
+
" },",
|
|
412
|
+
"});",
|
|
413
|
+
"",
|
|
414
|
+
"// Cleanup",
|
|
415
|
+
"sub.unsubscribe();",
|
|
416
|
+
].join("\n"),
|
|
417
|
+
},
|
|
418
|
+
tips: [
|
|
419
|
+
"SSE connections are long-lived — the SDK handles automatic reconnection",
|
|
420
|
+
"Use events filter to only receive the types you care about",
|
|
421
|
+
"Combine with React Query's invalidateQueries() for automatic UI refresh",
|
|
422
|
+
"For compute jobs: subscribe with jobId to track a specific execution",
|
|
423
|
+
"For orchestrations: subscribe with orchestrationId + runId to track a specific workflow run",
|
|
424
|
+
],
|
|
425
|
+
},
|
|
290
426
|
}, null, 2),
|
|
291
427
|
},
|
|
292
428
|
],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@centrali-io/centrali-mcp",
|
|
3
|
-
"version": "4.4.8-rc.
|
|
3
|
+
"version": "4.4.8-rc.6",
|
|
4
4
|
"description": "Centrali MCP Server - AI assistant integration for Centrali workspaces",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"author": "Blueinit",
|
|
26
26
|
"license": "ISC",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@centrali-io/centrali-sdk": "^4.4.
|
|
28
|
+
"@centrali-io/centrali-sdk": "^4.4.8",
|
|
29
29
|
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
package/src/tools/describe.ts
CHANGED
|
@@ -295,6 +295,142 @@ export function registerDescribeTools(server: McpServer) {
|
|
|
295
295
|
},
|
|
296
296
|
note: "workspaceId is the workspace slug (e.g., 'acme'), not a UUID. See https://docs.centrali.io/guides/centrali-sdk for the full guide.",
|
|
297
297
|
},
|
|
298
|
+
file_storage: {
|
|
299
|
+
description: "Centrali has built-in file storage (Azure Blob). Use the SDK to upload files and get render/download URLs. Not available via MCP — use in app code.",
|
|
300
|
+
folder_system: {
|
|
301
|
+
description: "Files live in folders. Every workspace starts with system folders: /root, /root/shared, /root/users, /root/_data_directory. You MUST create a folder before uploading to it — uploading to a non-existent folder will fail.",
|
|
302
|
+
system_folders: {
|
|
303
|
+
"/root/shared": "Default location for app files. Always exists. Create subfolders here (e.g., /root/shared/logos).",
|
|
304
|
+
"/root/users": "Per-user folders (managed by the platform)",
|
|
305
|
+
},
|
|
306
|
+
creating_folders: {
|
|
307
|
+
method: "client.createFolder(name, location?)",
|
|
308
|
+
example: "await centrali.createFolder('logos', '/root/shared'); // Creates /root/shared/logos",
|
|
309
|
+
note: "Defaults to /root/shared if location is omitted. Only needed when nesting deeper (e.g., creating a subfolder inside a subfolder — the parent must exist first).",
|
|
310
|
+
},
|
|
311
|
+
listing_folders: {
|
|
312
|
+
method: "client.listFolders(location?)",
|
|
313
|
+
example: "const folders = await centrali.listFolders('/root/shared');",
|
|
314
|
+
note: "Use this to check if a folder exists before uploading.",
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
upload: {
|
|
318
|
+
method: "client.uploadFile(file, location?, isPublic?)",
|
|
319
|
+
returns: "renderId (string) — use this to construct render/download URLs",
|
|
320
|
+
important: "Uploading to /root/shared works out of the box. For custom subfolders (e.g., /root/shared/logos), create the folder first if it doesn't exist.",
|
|
321
|
+
example: [
|
|
322
|
+
"// Next.js API route for file upload with folder creation",
|
|
323
|
+
"import { CentraliSDK } from '@centrali-io/centrali-sdk';",
|
|
324
|
+
"",
|
|
325
|
+
"export async function POST(req: Request) {",
|
|
326
|
+
" const formData = await req.formData();",
|
|
327
|
+
" const file = formData.get('file') as File;",
|
|
328
|
+
"",
|
|
329
|
+
" const centrali = new CentraliSDK({ baseUrl, workspaceId, clientId, clientSecret });",
|
|
330
|
+
"",
|
|
331
|
+
" // Ensure the target folder exists (create if needed)",
|
|
332
|
+
" const folders = await centrali.listFolders('/root/shared');",
|
|
333
|
+
" if (!folders.data.some((f: any) => f.name === 'logos')) {",
|
|
334
|
+
" await centrali.createFolder('logos', '/root/shared');",
|
|
335
|
+
" }",
|
|
336
|
+
"",
|
|
337
|
+
" const { data: renderId } = await centrali.uploadFile(file, '/root/shared/logos', true);",
|
|
338
|
+
" const url = centrali.getFileRenderUrl(renderId);",
|
|
339
|
+
"",
|
|
340
|
+
" // Store the URL on a record",
|
|
341
|
+
" await centrali.updateRecord('organizations', orgId, { logoUrl: url });",
|
|
342
|
+
"",
|
|
343
|
+
" return Response.json({ url });",
|
|
344
|
+
"}",
|
|
345
|
+
].join("\n"),
|
|
346
|
+
},
|
|
347
|
+
render_url: {
|
|
348
|
+
method: "client.getFileRenderUrl(renderId, options?)",
|
|
349
|
+
note: "Returns a URL that serves the file. Supports image transformations: width, height, fit ('cover'|'contain'|'fill'), format ('webp'|'png'|'jpeg'), quality (1-100).",
|
|
350
|
+
example: "const url = centrali.getFileRenderUrl(renderId, { width: 200, height: 200, fit: 'cover', format: 'webp' });",
|
|
351
|
+
},
|
|
352
|
+
download_url: {
|
|
353
|
+
method: "client.getFileDownloadUrl(renderId)",
|
|
354
|
+
note: "Returns a URL that triggers a file download.",
|
|
355
|
+
},
|
|
356
|
+
tips: [
|
|
357
|
+
"/root/shared always exists — upload there directly or create subfolders like /root/shared/logos",
|
|
358
|
+
"Set isPublic=true for files that need to be accessible without auth (logos, avatars, public images)",
|
|
359
|
+
"Store the renderId or full URL on a record field for easy retrieval",
|
|
360
|
+
"Use image transformations for thumbnails instead of uploading multiple sizes",
|
|
361
|
+
],
|
|
362
|
+
},
|
|
363
|
+
realtime: {
|
|
364
|
+
description: "Centrali supports real-time event streaming via SSE (Server-Sent Events). Use the SDK to subscribe to events across records, compute, orchestrations, validation, and anomaly detection. Not available via MCP — use in app code.",
|
|
365
|
+
event_types: {
|
|
366
|
+
records: [
|
|
367
|
+
"record_created — a new record was inserted",
|
|
368
|
+
"record_updated — a record was modified",
|
|
369
|
+
"record_deleted — a record was deleted",
|
|
370
|
+
"records_bulk_created — multiple records created in batch",
|
|
371
|
+
],
|
|
372
|
+
compute: [
|
|
373
|
+
"function_run_completed — a compute function finished successfully",
|
|
374
|
+
"function_run_failed — a compute function errored",
|
|
375
|
+
],
|
|
376
|
+
orchestrations: [
|
|
377
|
+
"orchestration_run_started — a workflow run began",
|
|
378
|
+
"orchestration_run_completed — a workflow run finished",
|
|
379
|
+
"orchestration_run_failed — a workflow run errored",
|
|
380
|
+
],
|
|
381
|
+
validation: [
|
|
382
|
+
"validation_suggestion_created — a new data quality suggestion was generated",
|
|
383
|
+
"validation_batch_completed — a validation scan batch finished",
|
|
384
|
+
],
|
|
385
|
+
anomalies: [
|
|
386
|
+
"anomaly_insight_created — a new anomaly was detected",
|
|
387
|
+
"anomaly_detection_completed — an anomaly scan finished",
|
|
388
|
+
],
|
|
389
|
+
},
|
|
390
|
+
subscribe: {
|
|
391
|
+
method: "client.realtime.subscribe(options)",
|
|
392
|
+
options: {
|
|
393
|
+
recordSlug: "string — filter to a specific collection (optional)",
|
|
394
|
+
events: "RealtimeEventType[] — filter to specific event types (optional, defaults to all)",
|
|
395
|
+
jobId: "string — filter compute events to a specific job (optional)",
|
|
396
|
+
triggerType: "string — filter compute events by trigger type (optional)",
|
|
397
|
+
orchestrationId: "string — filter orchestration events to a specific orchestration (optional)",
|
|
398
|
+
runId: "string — filter orchestration events to a specific run (optional)",
|
|
399
|
+
},
|
|
400
|
+
returns: "{ unsubscribe: () => void }",
|
|
401
|
+
example: [
|
|
402
|
+
"// Subscribe to all record changes for a collection",
|
|
403
|
+
"const sub = centrali.realtime.subscribe({",
|
|
404
|
+
" recordSlug: 'orders',",
|
|
405
|
+
" events: ['record_created', 'record_updated'],",
|
|
406
|
+
" onEvent: (event) => {",
|
|
407
|
+
" console.log(event.event, event.data);",
|
|
408
|
+
" // Refresh your UI, invalidate cache, etc.",
|
|
409
|
+
" },",
|
|
410
|
+
"});",
|
|
411
|
+
"",
|
|
412
|
+
"// Track a compute function run in real-time",
|
|
413
|
+
"const sub2 = centrali.realtime.subscribe({",
|
|
414
|
+
" events: ['function_run_completed', 'function_run_failed'],",
|
|
415
|
+
" jobId: 'some-job-id',",
|
|
416
|
+
" onEvent: (event) => {",
|
|
417
|
+
" if (event.event === 'function_run_completed') { /* success */ }",
|
|
418
|
+
" if (event.event === 'function_run_failed') { /* handle error */ }",
|
|
419
|
+
" },",
|
|
420
|
+
"});",
|
|
421
|
+
"",
|
|
422
|
+
"// Cleanup",
|
|
423
|
+
"sub.unsubscribe();",
|
|
424
|
+
].join("\n"),
|
|
425
|
+
},
|
|
426
|
+
tips: [
|
|
427
|
+
"SSE connections are long-lived — the SDK handles automatic reconnection",
|
|
428
|
+
"Use events filter to only receive the types you care about",
|
|
429
|
+
"Combine with React Query's invalidateQueries() for automatic UI refresh",
|
|
430
|
+
"For compute jobs: subscribe with jobId to track a specific execution",
|
|
431
|
+
"For orchestrations: subscribe with orchestrationId + runId to track a specific workflow run",
|
|
432
|
+
],
|
|
433
|
+
},
|
|
298
434
|
},
|
|
299
435
|
null,
|
|
300
436
|
2
|