@centrali-io/centrali-mcp 4.4.5 → 4.4.7

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.
@@ -8,8 +8,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  exports.registerComputeTools = registerComputeTools;
16
+ const axios_1 = __importDefault(require("axios"));
13
17
  const zod_1 = require("zod");
14
18
  function formatError(error, context) {
15
19
  var _a, _b;
@@ -33,7 +37,22 @@ function formatError(error, context) {
33
37
  }
34
38
  return `Error ${context}: ${error instanceof Error ? error.message : String(error)}`;
35
39
  }
36
- function registerComputeTools(server, sdk) {
40
+ /**
41
+ * Ensures the SDK has a valid token.
42
+ */
43
+ function ensureToken(sdk) {
44
+ return __awaiter(this, void 0, void 0, function* () {
45
+ let token = sdk.getToken();
46
+ if (token)
47
+ return token;
48
+ try {
49
+ yield sdk.functions.list({ limit: 1 });
50
+ }
51
+ catch ( /* token refresh side effect */_a) { /* token refresh side effect */ }
52
+ return sdk.getToken();
53
+ });
54
+ }
55
+ function registerComputeTools(server, sdk, centraliUrl, workspaceId) {
37
56
  server.tool("list_functions", "List all compute functions in the workspace. Compute functions are JavaScript code blocks that run server-side.", {
38
57
  page: zod_1.z.number().optional().describe("Page number"),
39
58
  limit: zod_1.z.number().optional().describe("Results per page"),
@@ -63,9 +82,9 @@ function registerComputeTools(server, sdk) {
63
82
  };
64
83
  }
65
84
  }));
66
- server.tool("list_triggers", "List function triggers in the workspace. Triggers define how and when compute functions are executed (on-demand, event-driven, scheduled, http-trigger).", {
85
+ server.tool("list_triggers", "List function triggers in the workspace. Triggers define how and when compute functions are executed (on-demand, event-driven, scheduled, http-trigger, endpoint).", {
67
86
  executionType: zod_1.z
68
- .enum(["on-demand", "event-driven", "scheduled", "http-trigger"])
87
+ .enum(["on-demand", "event-driven", "scheduled", "http-trigger", "endpoint"])
69
88
  .optional()
70
89
  .describe("Filter by trigger execution type"),
71
90
  page: zod_1.z.number().optional().describe("Page number"),
@@ -112,7 +131,11 @@ function registerComputeTools(server, sdk) {
112
131
  content: [
113
132
  {
114
133
  type: "text",
115
- text: JSON.stringify({ jobId: result.data, message: "Trigger invoked successfully" }, null, 2),
134
+ text: JSON.stringify({
135
+ jobId: result.data,
136
+ message: "Trigger invoked successfully. Execution is async — the function is running in the background.",
137
+ next_step: `To check the result, call get_compute_job_status with jobId='${result.data}'. It returns the job state (queued → running → completed | failed) and the return value or error.`,
138
+ }, null, 2),
116
139
  },
117
140
  ],
118
141
  };
@@ -129,6 +152,37 @@ function registerComputeTools(server, sdk) {
129
152
  };
130
153
  }
131
154
  }));
155
+ server.tool("get_compute_job_status", "Check the status of an async compute job by job ID. Returns the current state (queued, running, completed, failed), the return value on success, or the failure reason on error. Use this after invoke_trigger to poll for results.", {
156
+ jobId: zod_1.z.string().describe("The job ID returned by invoke_trigger"),
157
+ }, (_a) => __awaiter(this, [_a], void 0, function* ({ jobId }) {
158
+ try {
159
+ const token = yield ensureToken(sdk);
160
+ const url = new URL(centraliUrl);
161
+ const hostname = url.hostname.startsWith("api.")
162
+ ? url.hostname
163
+ : `api.${url.hostname}`;
164
+ const apiUrl = `${url.protocol}//${hostname}/data/workspace/${workspaceId}/api/v1/jobs/compute/${jobId}`;
165
+ const result = yield axios_1.default.get(apiUrl, {
166
+ headers: token ? { Authorization: `Bearer ${token}` } : {},
167
+ });
168
+ return {
169
+ content: [
170
+ { type: "text", text: JSON.stringify(result.data, null, 2) },
171
+ ],
172
+ };
173
+ }
174
+ catch (error) {
175
+ return {
176
+ content: [
177
+ {
178
+ type: "text",
179
+ text: formatError(error, `getting job status for '${jobId}'`),
180
+ },
181
+ ],
182
+ isError: true,
183
+ };
184
+ }
185
+ }));
132
186
  // ── Function CRUD tools ──────────────────────────────────────────
133
187
  server.tool("get_function", "Get a compute function by ID. Returns the full function definition including code.", {
134
188
  functionId: zod_1.z.string().describe("The compute function ID (UUID)"),
@@ -340,13 +394,13 @@ function registerComputeTools(server, sdk) {
340
394
  name: zod_1.z.string().describe("Display name for the trigger"),
341
395
  functionId: zod_1.z.string().describe("The compute function ID (UUID) to execute"),
342
396
  executionType: zod_1.z
343
- .enum(["on-demand", "event-driven", "scheduled", "http-trigger"])
344
- .describe("How the trigger fires: on-demand (manual), event-driven (data events), scheduled (cron), or http-trigger (external HTTP POST)"),
397
+ .enum(["on-demand", "event-driven", "scheduled", "http-trigger", "endpoint"])
398
+ .describe("How the trigger fires: on-demand (manual), event-driven (data events), scheduled (cron), http-trigger (external HTTP POST), or endpoint (synchronous HTTP API — returns response inline)"),
345
399
  description: zod_1.z.string().optional().describe("Optional description"),
346
400
  triggerMetadata: zod_1.z
347
401
  .record(zod_1.z.string(), zod_1.z.any())
348
402
  .optional()
349
- .describe("Type-specific configuration. For event-driven: { eventType, recordSlug } where eventType is record_created | record_updated | record_deleted. For scheduled: { scheduleType, cronExpression, timezone }. For http-trigger: auto-generated URL."),
403
+ .describe("Type-specific configuration. For event-driven: { eventType, recordSlug }. For scheduled: { scheduleType, cronExpression, timezone }. For http-trigger: auto-generated URL. For endpoint: { path, allowedMethods?, timeoutMs?, auth? } where path is URL-safe (e.g., 'create-order'), allowedMethods defaults to ['POST'], timeoutMs 1000-30000 (default 30000), auth is { mode: 'bearer'|'public'|'apiKey'|'hmac' }."),
350
404
  enabled: zod_1.z.boolean().optional().describe("Whether the trigger is enabled (default: true)"),
351
405
  }, (_a) => __awaiter(this, [_a], void 0, function* ({ name, functionId, executionType, description, triggerMetadata, enabled }) {
352
406
  try {
@@ -487,6 +541,129 @@ function registerComputeTools(server, sdk) {
487
541
  };
488
542
  }
489
543
  }));
544
+ // ── Function Runs tools ────────────────────────────────────────────
545
+ server.tool("get_function_run", "Get a function run by ID. Returns status, output, error, timing, and execution metadata. Use this to check the result of an async trigger invocation or test execution.", {
546
+ runId: zod_1.z.string().describe("The function run ID (UUID)"),
547
+ }, (_a) => __awaiter(this, [_a], void 0, function* ({ runId }) {
548
+ try {
549
+ const result = yield sdk.runs.get(runId);
550
+ return {
551
+ content: [
552
+ { type: "text", text: JSON.stringify(result.data, null, 2) },
553
+ ],
554
+ };
555
+ }
556
+ catch (error) {
557
+ return {
558
+ content: [
559
+ {
560
+ type: "text",
561
+ text: formatError(error, `getting function run '${runId}'`),
562
+ },
563
+ ],
564
+ isError: true,
565
+ };
566
+ }
567
+ }));
568
+ server.tool("list_function_runs", "List function runs filtered by trigger ID or function ID. Returns execution history with status, timing, and errors. Useful for checking whether a trigger invocation completed and what it returned.", {
569
+ triggerId: zod_1.z.string().optional().describe("Filter runs by trigger ID (UUID)"),
570
+ functionId: zod_1.z.string().optional().describe("Filter runs by function ID (UUID)"),
571
+ status: zod_1.z
572
+ .enum(["pending", "running", "completed", "failure", "timeout"])
573
+ .optional()
574
+ .describe("Filter by run status"),
575
+ page: zod_1.z.number().optional().describe("Page number"),
576
+ limit: zod_1.z.number().optional().describe("Results per page"),
577
+ }, (_a) => __awaiter(this, [_a], void 0, function* ({ triggerId, functionId, status, page, limit }) {
578
+ try {
579
+ if (!triggerId && !functionId) {
580
+ return {
581
+ content: [
582
+ {
583
+ type: "text",
584
+ text: "Error: provide either triggerId or functionId to list runs.",
585
+ },
586
+ ],
587
+ isError: true,
588
+ };
589
+ }
590
+ const options = {};
591
+ if (status)
592
+ options.status = status;
593
+ if (page !== undefined)
594
+ options.page = page;
595
+ if (limit !== undefined)
596
+ options.limit = limit;
597
+ const opts = Object.keys(options).length > 0 ? options : undefined;
598
+ const result = triggerId
599
+ ? yield sdk.runs.listByTrigger(triggerId, opts)
600
+ : yield sdk.runs.listByFunction(functionId, opts);
601
+ return {
602
+ content: [
603
+ { type: "text", text: JSON.stringify(result.data, null, 2) },
604
+ ],
605
+ };
606
+ }
607
+ catch (error) {
608
+ return {
609
+ content: [
610
+ {
611
+ type: "text",
612
+ text: formatError(error, `listing function runs`),
613
+ },
614
+ ],
615
+ isError: true,
616
+ };
617
+ }
618
+ }));
619
+ // ── Endpoint Trigger (Sync Execution) ─────────────────────────────
620
+ server.tool("invoke_endpoint", "Invoke a compute endpoint trigger by path. The function executes synchronously — Centrali waits for the function to complete and returns its output directly in the response. No polling needed. Max execution time: 30 seconds (configurable via triggerMetadata.timeoutMs, range 1–30s). If the function exceeds the timeout, returns 504. Endpoint triggers must be created first with executionType='endpoint'. Use this for real-time API responses; use invoke_trigger for long-running background work that doesn't need an immediate response.", {
621
+ path: zod_1.z.string().describe("The endpoint path (e.g., 'create-order', 'webhook/shipments'). This is set in the trigger's triggerMetadata.path."),
622
+ method: zod_1.z.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]).optional().describe("HTTP method (default: POST). Must be in the trigger's allowedMethods."),
623
+ payload: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional().describe("Request body payload (sent as JSON)"),
624
+ headers: zod_1.z.record(zod_1.z.string(), zod_1.z.string()).optional().describe("Additional headers (e.g., X-API-Key for apiKey auth)"),
625
+ }, (_a) => __awaiter(this, [_a], void 0, function* ({ path, method, payload, headers: extraHeaders }) {
626
+ try {
627
+ const token = yield ensureToken(sdk);
628
+ const url = new URL(centraliUrl);
629
+ const hostname = url.hostname.startsWith("api.")
630
+ ? url.hostname
631
+ : `api.${url.hostname}`;
632
+ const apiUrl = `${url.protocol}//${hostname}/data/workspace/${workspaceId}/api/v1/endpoints/${path}`;
633
+ const reqHeaders = {};
634
+ if (token)
635
+ reqHeaders.Authorization = `Bearer ${token}`;
636
+ if (extraHeaders)
637
+ Object.assign(reqHeaders, extraHeaders);
638
+ const httpMethod = (method || "POST").toLowerCase();
639
+ const result = yield (0, axios_1.default)({
640
+ method: httpMethod,
641
+ url: apiUrl,
642
+ data: ["get", "delete"].includes(httpMethod) ? undefined : (payload || {}),
643
+ headers: reqHeaders,
644
+ validateStatus: () => true, // Don't throw on non-2xx — return the function's response as-is
645
+ });
646
+ return {
647
+ content: [{
648
+ type: "text",
649
+ text: JSON.stringify({
650
+ status: result.status,
651
+ headers: {
652
+ "content-type": result.headers["content-type"],
653
+ "x-execution-id": result.headers["x-execution-id"],
654
+ },
655
+ body: result.data,
656
+ }, null, 2),
657
+ }],
658
+ };
659
+ }
660
+ catch (error) {
661
+ return {
662
+ content: [{ type: "text", text: formatError(error, `invoking endpoint '${path}'`) }],
663
+ isError: true,
664
+ };
665
+ }
666
+ }));
490
667
  // ── Allowed Domains tools ──────────────────────────────────────────
491
668
  server.tool("list_allowed_domains", "List all allowed domains for compute function HTTP requests. Functions can only call external APIs on domains in this allowlist.", {}, () => __awaiter(this, void 0, void 0, function* () {
492
669
  try {