@centrali-io/centrali-mcp 4.2.0 → 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/README.md +25 -1
- package/dist/index.js +4 -0
- package/dist/tools/compute.js +323 -0
- package/dist/tools/describe.d.ts +10 -0
- package/dist/tools/describe.js +1485 -0
- package/dist/tools/orchestrations.js +146 -0
- package/dist/tools/pages.d.ts +3 -0
- package/dist/tools/pages.js +477 -0
- package/dist/tools/smart-queries.js +152 -0
- package/dist/tools/structures.js +117 -0
- package/package.json +2 -2
- package/src/index.ts +4 -0
- package/src/tools/compute.ts +371 -0
- package/src/tools/describe.ts +1798 -0
- package/src/tools/orchestrations.ts +167 -0
- package/src/tools/pages.ts +573 -0
- package/src/tools/smart-queries.ts +175 -0
- package/src/tools/structures.ts +123 -0
|
@@ -179,4 +179,150 @@ function registerOrchestrationTools(server, sdk) {
|
|
|
179
179
|
};
|
|
180
180
|
}
|
|
181
181
|
}));
|
|
182
|
+
server.tool("create_orchestration", "Create a new orchestration workflow. Orchestrations chain compute functions together in multi-step workflows.", {
|
|
183
|
+
slug: zod_1.z.string().describe("URL-friendly unique slug (e.g., 'order-processing')"),
|
|
184
|
+
name: zod_1.z.string().describe("Human-readable name"),
|
|
185
|
+
description: zod_1.z.string().optional().describe("Optional description of the workflow"),
|
|
186
|
+
trigger: zod_1.z
|
|
187
|
+
.record(zod_1.z.string(), zod_1.z.any())
|
|
188
|
+
.describe("Trigger configuration object. Must include 'type' (on-demand, event-driven, scheduled, webhook)"),
|
|
189
|
+
steps: zod_1.z
|
|
190
|
+
.array(zod_1.z.record(zod_1.z.string(), zod_1.z.any()))
|
|
191
|
+
.describe("Array of step definitions. Each step has id, type, functionId, and optional onSuccess/onFailure routing"),
|
|
192
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ slug, name, description, trigger, steps }) {
|
|
193
|
+
try {
|
|
194
|
+
const input = { slug, name, trigger, steps };
|
|
195
|
+
if (description !== undefined)
|
|
196
|
+
input.description = description;
|
|
197
|
+
const result = yield sdk.orchestrations.create(input);
|
|
198
|
+
return {
|
|
199
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
return {
|
|
204
|
+
content: [
|
|
205
|
+
{
|
|
206
|
+
type: "text",
|
|
207
|
+
text: formatError(error, `creating orchestration '${slug}'`),
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
isError: true,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}));
|
|
214
|
+
server.tool("update_orchestration", "Update an existing orchestration by ID. Only include the fields you want to change.", {
|
|
215
|
+
orchestrationId: zod_1.z.string().describe("The orchestration ID (UUID) to update"),
|
|
216
|
+
name: zod_1.z.string().optional().describe("Updated name"),
|
|
217
|
+
description: zod_1.z.string().optional().describe("Updated description"),
|
|
218
|
+
status: zod_1.z
|
|
219
|
+
.enum(["draft", "active", "paused"])
|
|
220
|
+
.optional()
|
|
221
|
+
.describe("Updated status"),
|
|
222
|
+
trigger: zod_1.z
|
|
223
|
+
.record(zod_1.z.string(), zod_1.z.any())
|
|
224
|
+
.optional()
|
|
225
|
+
.describe("Updated trigger configuration"),
|
|
226
|
+
steps: zod_1.z
|
|
227
|
+
.array(zod_1.z.record(zod_1.z.string(), zod_1.z.any()))
|
|
228
|
+
.optional()
|
|
229
|
+
.describe("Updated step definitions"),
|
|
230
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ orchestrationId, name, description, status, trigger, steps }) {
|
|
231
|
+
try {
|
|
232
|
+
const input = {};
|
|
233
|
+
if (name !== undefined)
|
|
234
|
+
input.name = name;
|
|
235
|
+
if (description !== undefined)
|
|
236
|
+
input.description = description;
|
|
237
|
+
if (status !== undefined)
|
|
238
|
+
input.status = status;
|
|
239
|
+
if (trigger !== undefined)
|
|
240
|
+
input.trigger = trigger;
|
|
241
|
+
if (steps !== undefined)
|
|
242
|
+
input.steps = steps;
|
|
243
|
+
const result = yield sdk.orchestrations.update(orchestrationId, input);
|
|
244
|
+
return {
|
|
245
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
return {
|
|
250
|
+
content: [
|
|
251
|
+
{
|
|
252
|
+
type: "text",
|
|
253
|
+
text: formatError(error, `updating orchestration '${orchestrationId}'`),
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
isError: true,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
}));
|
|
260
|
+
server.tool("delete_orchestration", "Delete an orchestration by ID. This also deletes all runs associated with the orchestration.", {
|
|
261
|
+
orchestrationId: zod_1.z.string().describe("The orchestration ID (UUID) to delete"),
|
|
262
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ orchestrationId }) {
|
|
263
|
+
try {
|
|
264
|
+
yield sdk.orchestrations.delete(orchestrationId);
|
|
265
|
+
return {
|
|
266
|
+
content: [
|
|
267
|
+
{
|
|
268
|
+
type: "text",
|
|
269
|
+
text: `Orchestration '${orchestrationId}' deleted successfully.`,
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
return {
|
|
276
|
+
content: [
|
|
277
|
+
{
|
|
278
|
+
type: "text",
|
|
279
|
+
text: formatError(error, `deleting orchestration '${orchestrationId}'`),
|
|
280
|
+
},
|
|
281
|
+
],
|
|
282
|
+
isError: true,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
}));
|
|
286
|
+
server.tool("activate_orchestration", "Activate an orchestration. Active orchestrations can be triggered by scheduled events, record events, and webhooks.", {
|
|
287
|
+
orchestrationId: zod_1.z.string().describe("The orchestration ID (UUID) to activate"),
|
|
288
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ orchestrationId }) {
|
|
289
|
+
try {
|
|
290
|
+
const result = yield sdk.orchestrations.activate(orchestrationId);
|
|
291
|
+
return {
|
|
292
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
return {
|
|
297
|
+
content: [
|
|
298
|
+
{
|
|
299
|
+
type: "text",
|
|
300
|
+
text: formatError(error, `activating orchestration '${orchestrationId}'`),
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
isError: true,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
}));
|
|
307
|
+
server.tool("pause_orchestration", "Pause an orchestration. Paused orchestrations cannot be triggered by any mechanism.", {
|
|
308
|
+
orchestrationId: zod_1.z.string().describe("The orchestration ID (UUID) to pause"),
|
|
309
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ orchestrationId }) {
|
|
310
|
+
try {
|
|
311
|
+
const result = yield sdk.orchestrations.pause(orchestrationId);
|
|
312
|
+
return {
|
|
313
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
return {
|
|
318
|
+
content: [
|
|
319
|
+
{
|
|
320
|
+
type: "text",
|
|
321
|
+
text: formatError(error, `pausing orchestration '${orchestrationId}'`),
|
|
322
|
+
},
|
|
323
|
+
],
|
|
324
|
+
isError: true,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
}));
|
|
182
328
|
}
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.registerPageTools = registerPageTools;
|
|
16
|
+
const zod_1 = require("zod");
|
|
17
|
+
const axios_1 = __importDefault(require("axios"));
|
|
18
|
+
function formatError(error, context) {
|
|
19
|
+
var _a, _b, _c;
|
|
20
|
+
if (axios_1.default.isAxiosError(error) && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.data)) {
|
|
21
|
+
const body = error.response.data;
|
|
22
|
+
const status = error.response.status;
|
|
23
|
+
const message = body.message || body.error || error.message;
|
|
24
|
+
return `Error ${context}: [${status}] ${message}`;
|
|
25
|
+
}
|
|
26
|
+
if (error && typeof error === "object") {
|
|
27
|
+
const e = error;
|
|
28
|
+
if ("message" in e) {
|
|
29
|
+
let msg = `Error ${context}`;
|
|
30
|
+
if ("code" in e || "status" in e) {
|
|
31
|
+
msg += `: [${(_c = (_b = e.code) !== null && _b !== void 0 ? _b : e.status) !== null && _c !== void 0 ? _c : "ERROR"}] ${e.message}`;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
msg += `: ${e.message}`;
|
|
35
|
+
}
|
|
36
|
+
return msg;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return `Error ${context}: ${error instanceof Error ? error.message : String(error)}`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Derives the pages API base URL from the CENTRALI_URL.
|
|
43
|
+
* Pattern: https://centrali.io -> https://api.centrali.io/pages
|
|
44
|
+
* Or uses CENTRALI_PAGES_URL env var if explicitly set.
|
|
45
|
+
*/
|
|
46
|
+
function getPagesBaseUrl(centraliUrl) {
|
|
47
|
+
const override = process.env.CENTRALI_PAGES_URL;
|
|
48
|
+
if (override)
|
|
49
|
+
return override.replace(/\/$/, "");
|
|
50
|
+
const url = new URL(centraliUrl);
|
|
51
|
+
const hostname = url.hostname.startsWith("api.")
|
|
52
|
+
? url.hostname
|
|
53
|
+
: `api.${url.hostname}`;
|
|
54
|
+
return `${url.protocol}//${hostname}/pages`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Creates an axios instance for the pages API that uses the SDK's token.
|
|
58
|
+
*/
|
|
59
|
+
function createPagesClient(sdk, centraliUrl, workspaceId) {
|
|
60
|
+
const baseURL = getPagesBaseUrl(centraliUrl);
|
|
61
|
+
const client = axios_1.default.create({ baseURL });
|
|
62
|
+
// Attach the SDK's bearer token to every request
|
|
63
|
+
client.interceptors.request.use((config) => __awaiter(this, void 0, void 0, function* () {
|
|
64
|
+
var _a, _b, _c, _d, _e;
|
|
65
|
+
const token = (_c = (_b = (_a = sdk).getToken) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : sdk.token;
|
|
66
|
+
if (!token) {
|
|
67
|
+
// Force the SDK to fetch a token by calling getTokenOrFetch
|
|
68
|
+
const freshToken = yield ((_e = (_d = sdk).getTokenOrFetch) === null || _e === void 0 ? void 0 : _e.call(_d));
|
|
69
|
+
if (freshToken) {
|
|
70
|
+
config.headers.Authorization = `Bearer ${freshToken}`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
75
|
+
}
|
|
76
|
+
return config;
|
|
77
|
+
}));
|
|
78
|
+
return { client, workspaceId };
|
|
79
|
+
}
|
|
80
|
+
function registerPageTools(server, sdk, centraliUrl, workspaceId) {
|
|
81
|
+
const { client } = createPagesClient(sdk, centraliUrl, workspaceId);
|
|
82
|
+
const basePath = `/ws/${workspaceId}/api/v1/pages`;
|
|
83
|
+
// ── Page CRUD ──────────────────────────────────────────────────────
|
|
84
|
+
server.tool("list_pages", "List all pages in the workspace. Pages are pre-built UI views (lists, detail views, forms, dashboards) that surface data from structures.", {
|
|
85
|
+
page: zod_1.z.number().optional().describe("Page number (1-indexed, default: 1)"),
|
|
86
|
+
pageSize: zod_1.z.number().optional().describe("Items per page (default: 20)"),
|
|
87
|
+
pageType: zod_1.z
|
|
88
|
+
.enum(["list", "detail", "form", "dashboard"])
|
|
89
|
+
.optional()
|
|
90
|
+
.describe("Filter by page type"),
|
|
91
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ page, pageSize, pageType }) {
|
|
92
|
+
try {
|
|
93
|
+
const params = {};
|
|
94
|
+
if (page !== undefined)
|
|
95
|
+
params.page = page;
|
|
96
|
+
if (pageSize !== undefined)
|
|
97
|
+
params.pageSize = pageSize;
|
|
98
|
+
if (pageType)
|
|
99
|
+
params.pageType = pageType;
|
|
100
|
+
const resp = yield client.get(basePath, { params });
|
|
101
|
+
return {
|
|
102
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
return {
|
|
107
|
+
content: [{ type: "text", text: formatError(error, "listing pages") }],
|
|
108
|
+
isError: true,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}));
|
|
112
|
+
server.tool("get_page", "Get a page by its ID. Returns the page metadata including name, slug, type, and description.", {
|
|
113
|
+
pageId: zod_1.z.string().describe("The page ID (UUID)"),
|
|
114
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ pageId }) {
|
|
115
|
+
try {
|
|
116
|
+
const resp = yield client.get(`${basePath}/${pageId}`);
|
|
117
|
+
return {
|
|
118
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
return {
|
|
123
|
+
content: [{ type: "text", text: formatError(error, `getting page '${pageId}'`) }],
|
|
124
|
+
isError: true,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}));
|
|
128
|
+
server.tool("create_page", "Create a new page in the workspace. A page is a UI view backed by data from structures. Specify the page type: 'list' for data tables, 'detail' for single-record views, 'form' for data entry, 'dashboard' for metrics and charts.", {
|
|
129
|
+
name: zod_1.z.string().describe("Display name for the page (e.g., 'Customer List')"),
|
|
130
|
+
slug: zod_1.z.string().describe("URL-safe slug (e.g., 'customer-list')"),
|
|
131
|
+
pageType: zod_1.z
|
|
132
|
+
.enum(["list", "detail", "form", "dashboard"])
|
|
133
|
+
.describe("The type of page to create"),
|
|
134
|
+
description: zod_1.z.string().optional().describe("Optional description of the page's purpose"),
|
|
135
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ name, slug, pageType, description }) {
|
|
136
|
+
try {
|
|
137
|
+
const resp = yield client.post(basePath, { name, slug, pageType, description });
|
|
138
|
+
return {
|
|
139
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
return {
|
|
144
|
+
content: [{ type: "text", text: formatError(error, "creating page") }],
|
|
145
|
+
isError: true,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}));
|
|
149
|
+
server.tool("update_page", "Update a page's metadata (name, slug, description). Does not modify the page definition — use save_page_draft for that.", {
|
|
150
|
+
pageId: zod_1.z.string().describe("The page ID (UUID) to update"),
|
|
151
|
+
name: zod_1.z.string().optional().describe("New display name"),
|
|
152
|
+
slug: zod_1.z.string().optional().describe("New URL slug"),
|
|
153
|
+
description: zod_1.z.string().optional().describe("New description"),
|
|
154
|
+
showInNavShell: zod_1.z.boolean().optional().describe("Whether to show this page in the navigation shell"),
|
|
155
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ pageId, name, slug, description, showInNavShell }) {
|
|
156
|
+
try {
|
|
157
|
+
const body = {};
|
|
158
|
+
if (name !== undefined)
|
|
159
|
+
body.name = name;
|
|
160
|
+
if (slug !== undefined)
|
|
161
|
+
body.slug = slug;
|
|
162
|
+
if (description !== undefined)
|
|
163
|
+
body.description = description;
|
|
164
|
+
if (showInNavShell !== undefined)
|
|
165
|
+
body.showInNavShell = showInNavShell;
|
|
166
|
+
const resp = yield client.patch(`${basePath}/${pageId}`, body);
|
|
167
|
+
return {
|
|
168
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
return {
|
|
173
|
+
content: [{ type: "text", text: formatError(error, `updating page '${pageId}'`) }],
|
|
174
|
+
isError: true,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}));
|
|
178
|
+
server.tool("delete_page", "Soft-delete a page by its ID. The page will no longer be accessible but can potentially be restored.", {
|
|
179
|
+
pageId: zod_1.z.string().describe("The page ID (UUID) to delete"),
|
|
180
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ pageId }) {
|
|
181
|
+
try {
|
|
182
|
+
yield client.delete(`${basePath}/${pageId}`);
|
|
183
|
+
return {
|
|
184
|
+
content: [{ type: "text", text: `Page '${pageId}' deleted successfully.` }],
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
return {
|
|
189
|
+
content: [{ type: "text", text: formatError(error, `deleting page '${pageId}'`) }],
|
|
190
|
+
isError: true,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}));
|
|
194
|
+
// ── Drafts & Versions ─────────────────────────────────────────────
|
|
195
|
+
server.tool("save_page_draft", "Save or update the draft definition for a page. The definition describes the page's layout: sections, blocks, data sources, actions, and presentation. This does NOT publish the page — use publish_page after saving.", {
|
|
196
|
+
pageId: zod_1.z.string().describe("The page ID (UUID)"),
|
|
197
|
+
definition: zod_1.z
|
|
198
|
+
.record(zod_1.z.string(), zod_1.z.any())
|
|
199
|
+
.describe("The page definition object containing sections with blocks. Each section has: id, kind (content|metrics|exceptions|actions|hero|supporting), title, layout (single-column|two-column|metric-strip|stack), and blocks array."),
|
|
200
|
+
changeSummary: zod_1.z.string().optional().describe("Summary of changes in this draft"),
|
|
201
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ pageId, definition, changeSummary }) {
|
|
202
|
+
try {
|
|
203
|
+
const body = { definition };
|
|
204
|
+
if (changeSummary)
|
|
205
|
+
body.changeSummary = changeSummary;
|
|
206
|
+
const resp = yield client.put(`${basePath}/${pageId}/draft`, body);
|
|
207
|
+
return {
|
|
208
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
return {
|
|
213
|
+
content: [{ type: "text", text: formatError(error, `saving draft for page '${pageId}'`) }],
|
|
214
|
+
isError: true,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}));
|
|
218
|
+
server.tool("get_page_draft", "Get the current draft version of a page, including its full definition (sections, blocks, data sources).", {
|
|
219
|
+
pageId: zod_1.z.string().describe("The page ID (UUID)"),
|
|
220
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ pageId }) {
|
|
221
|
+
try {
|
|
222
|
+
const resp = yield client.get(`${basePath}/${pageId}/draft`);
|
|
223
|
+
return {
|
|
224
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
return {
|
|
229
|
+
content: [{ type: "text", text: formatError(error, `getting draft for page '${pageId}'`) }],
|
|
230
|
+
isError: true,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}));
|
|
234
|
+
server.tool("list_page_versions", "List all versions of a page. Each version captures a snapshot of the page definition at a point in time.", {
|
|
235
|
+
pageId: zod_1.z.string().describe("The page ID (UUID)"),
|
|
236
|
+
page: zod_1.z.number().optional().describe("Page number (1-indexed, default: 1)"),
|
|
237
|
+
pageSize: zod_1.z.number().optional().describe("Items per page (default: 20)"),
|
|
238
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ pageId, page, pageSize }) {
|
|
239
|
+
try {
|
|
240
|
+
const params = {};
|
|
241
|
+
if (page !== undefined)
|
|
242
|
+
params.page = page;
|
|
243
|
+
if (pageSize !== undefined)
|
|
244
|
+
params.pageSize = pageSize;
|
|
245
|
+
const resp = yield client.get(`${basePath}/${pageId}/versions`, { params });
|
|
246
|
+
return {
|
|
247
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
return {
|
|
252
|
+
content: [{ type: "text", text: formatError(error, `listing versions for page '${pageId}'`) }],
|
|
253
|
+
isError: true,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
}));
|
|
257
|
+
// ── Publishing ────────────────────────────────────────────────────
|
|
258
|
+
server.tool("validate_page", "Run validation checks on a page's current draft to determine if it is ready to publish. Returns a list of issues (errors and warnings) that must be resolved before publishing.", {
|
|
259
|
+
pageId: zod_1.z.string().describe("The page ID (UUID) to validate"),
|
|
260
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ pageId }) {
|
|
261
|
+
try {
|
|
262
|
+
const resp = yield client.post(`${basePath}/${pageId}/validate`);
|
|
263
|
+
return {
|
|
264
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
return {
|
|
269
|
+
content: [{ type: "text", text: formatError(error, `validating page '${pageId}'`) }],
|
|
270
|
+
isError: true,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
}));
|
|
274
|
+
server.tool("publish_page", "Publish the current draft of a page, making it accessible at its runtime URL. Validates the draft first — if there are errors, publishing is rejected with details. Returns the publication record and the public runtime URL.", {
|
|
275
|
+
pageId: zod_1.z.string().describe("The page ID (UUID) to publish"),
|
|
276
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ pageId }) {
|
|
277
|
+
try {
|
|
278
|
+
const resp = yield client.post(`${basePath}/${pageId}/publish`);
|
|
279
|
+
return {
|
|
280
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
return {
|
|
285
|
+
content: [{ type: "text", text: formatError(error, `publishing page '${pageId}'`) }],
|
|
286
|
+
isError: true,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
}));
|
|
290
|
+
server.tool("unpublish_page", "Unpublish a page, making it no longer accessible at its runtime URL. The page definition is preserved and can be re-published later.", {
|
|
291
|
+
pageId: zod_1.z.string().describe("The page ID (UUID) to unpublish"),
|
|
292
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ pageId }) {
|
|
293
|
+
try {
|
|
294
|
+
const resp = yield client.post(`${basePath}/${pageId}/unpublish`);
|
|
295
|
+
return {
|
|
296
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
return {
|
|
301
|
+
content: [{ type: "text", text: formatError(error, `unpublishing page '${pageId}'`) }],
|
|
302
|
+
isError: true,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
}));
|
|
306
|
+
// ── Access Policy ─────────────────────────────────────────────────
|
|
307
|
+
server.tool("set_page_access_policy", "Set the access policy for a page. Controls who can view the published page: 'public' (anyone), 'authenticated' (logged-in users), or 'role-gated' (users with specific roles).", {
|
|
308
|
+
pageId: zod_1.z.string().describe("The page ID (UUID)"),
|
|
309
|
+
accessMode: zod_1.z
|
|
310
|
+
.enum(["public", "authenticated", "role-gated"])
|
|
311
|
+
.describe("Access control mode"),
|
|
312
|
+
requiredRoles: zod_1.z
|
|
313
|
+
.array(zod_1.z.string())
|
|
314
|
+
.optional()
|
|
315
|
+
.describe("Required roles (only used when accessMode is 'role-gated')"),
|
|
316
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ pageId, accessMode, requiredRoles }) {
|
|
317
|
+
try {
|
|
318
|
+
const body = { accessMode };
|
|
319
|
+
if (requiredRoles)
|
|
320
|
+
body.requiredRoles = requiredRoles;
|
|
321
|
+
const resp = yield client.put(`${basePath}/${pageId}/access-policy`, body);
|
|
322
|
+
return {
|
|
323
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
return {
|
|
328
|
+
content: [{ type: "text", text: formatError(error, `setting access policy for page '${pageId}'`) }],
|
|
329
|
+
isError: true,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
}));
|
|
333
|
+
// ── Theme ─────────────────────────────────────────────────────────
|
|
334
|
+
server.tool("get_page_theme", "Get the workspace theme configuration used by published pages. Includes primary color, accent color, optional logo URL, and font family.", {}, () => __awaiter(this, void 0, void 0, function* () {
|
|
335
|
+
try {
|
|
336
|
+
const resp = yield client.get(`${basePath}/theme`);
|
|
337
|
+
return {
|
|
338
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
catch (error) {
|
|
342
|
+
return {
|
|
343
|
+
content: [{ type: "text", text: formatError(error, "getting page theme") }],
|
|
344
|
+
isError: true,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
}));
|
|
348
|
+
server.tool("set_page_theme", "Set the workspace theme for published pages. Controls the visual branding of all published pages.", {
|
|
349
|
+
primaryColor: zod_1.z.string().describe("Primary brand color (hex, e.g., '#1a73e8')"),
|
|
350
|
+
accentColor: zod_1.z.string().describe("Accent color (hex, e.g., '#ff6d00')"),
|
|
351
|
+
logoUrl: zod_1.z.string().optional().describe("URL to the workspace logo"),
|
|
352
|
+
fontFamily: zod_1.z.string().optional().describe("Font family name (e.g., 'Inter', 'Roboto')"),
|
|
353
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ primaryColor, accentColor, logoUrl, fontFamily }) {
|
|
354
|
+
try {
|
|
355
|
+
const config = { primaryColor, accentColor };
|
|
356
|
+
if (logoUrl !== undefined)
|
|
357
|
+
config.logoUrl = logoUrl;
|
|
358
|
+
if (fontFamily !== undefined)
|
|
359
|
+
config.fontFamily = fontFamily;
|
|
360
|
+
const resp = yield client.put(`${basePath}/theme`, { config });
|
|
361
|
+
return {
|
|
362
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
return {
|
|
367
|
+
content: [{ type: "text", text: formatError(error, "setting page theme") }],
|
|
368
|
+
isError: true,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}));
|
|
372
|
+
// ── Navigation ────────────────────────────────────────────────────
|
|
373
|
+
server.tool("get_navigation", "Get the workspace navigation configuration. Controls the sidebar/nav shell that wraps published pages.", {}, () => __awaiter(this, void 0, void 0, function* () {
|
|
374
|
+
try {
|
|
375
|
+
const resp = yield client.get(`${basePath}/navigation`);
|
|
376
|
+
return {
|
|
377
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
return {
|
|
382
|
+
content: [{ type: "text", text: formatError(error, "getting navigation config") }],
|
|
383
|
+
isError: true,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
}));
|
|
387
|
+
server.tool("set_navigation", "Set the workspace navigation configuration. Defines the sidebar items, branding, and grouping for the page navigation shell.", {
|
|
388
|
+
config: zod_1.z
|
|
389
|
+
.record(zod_1.z.string(), zod_1.z.any())
|
|
390
|
+
.describe("Navigation config object with: enabled (boolean), branding ({ logoUrl, displayName }), items (array of nav items with pageId, label, icon, group)"),
|
|
391
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ config }) {
|
|
392
|
+
try {
|
|
393
|
+
const resp = yield client.put(`${basePath}/navigation`, { config });
|
|
394
|
+
return {
|
|
395
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
return {
|
|
400
|
+
content: [{ type: "text", text: formatError(error, "setting navigation config") }],
|
|
401
|
+
isError: true,
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
}));
|
|
405
|
+
server.tool("delete_navigation", "Delete the workspace navigation configuration. Pages revert to standalone rendering without a sidebar/nav shell.", {}, () => __awaiter(this, void 0, void 0, function* () {
|
|
406
|
+
try {
|
|
407
|
+
yield client.delete(`${basePath}/navigation`);
|
|
408
|
+
return {
|
|
409
|
+
content: [{ type: "text", text: "Navigation config deleted. Pages will render standalone." }],
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
catch (error) {
|
|
413
|
+
return {
|
|
414
|
+
content: [{ type: "text", text: formatError(error, "deleting navigation config") }],
|
|
415
|
+
isError: true,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
}));
|
|
419
|
+
// ── Assembly (AI-assisted page generation) ────────────────────────
|
|
420
|
+
server.tool("generate_starter_pages", "Generate page proposals from structure IDs. Uses guided assembly to create page definitions (list, detail, form, dashboard) tailored to the data schema. Returns proposals that can be reviewed and accepted.", {
|
|
421
|
+
structureIds: zod_1.z
|
|
422
|
+
.array(zod_1.z.string())
|
|
423
|
+
.describe("Array of structure IDs (UUIDs) to generate pages for"),
|
|
424
|
+
goals: zod_1.z
|
|
425
|
+
.array(zod_1.z.string())
|
|
426
|
+
.optional()
|
|
427
|
+
.describe("Optional goals to guide page generation (e.g., 'customer management dashboard', 'order tracking')"),
|
|
428
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ structureIds, goals }) {
|
|
429
|
+
try {
|
|
430
|
+
const body = { structureIds };
|
|
431
|
+
if (goals)
|
|
432
|
+
body.goals = goals;
|
|
433
|
+
const resp = yield client.post(`${basePath}/generate-starter-pages`, body);
|
|
434
|
+
return {
|
|
435
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
catch (error) {
|
|
439
|
+
return {
|
|
440
|
+
content: [{ type: "text", text: formatError(error, "generating starter pages") }],
|
|
441
|
+
isError: true,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
}));
|
|
445
|
+
server.tool("accept_page_proposal", "Accept a generated page proposal and create the page with its initial draft definition. Use after reviewing proposals from generate_starter_pages.", {
|
|
446
|
+
name: zod_1.z.string().describe("Display name for the page"),
|
|
447
|
+
slug: zod_1.z.string().describe("URL-safe slug for the page"),
|
|
448
|
+
pageType: zod_1.z
|
|
449
|
+
.enum(["list", "detail", "form", "dashboard"])
|
|
450
|
+
.describe("Page type"),
|
|
451
|
+
definition: zod_1.z
|
|
452
|
+
.record(zod_1.z.string(), zod_1.z.any())
|
|
453
|
+
.describe("The page definition from the proposal"),
|
|
454
|
+
generationSource: zod_1.z
|
|
455
|
+
.string()
|
|
456
|
+
.describe("The source that generated this proposal (from the proposal object)"),
|
|
457
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ name, slug, pageType, definition, generationSource }) {
|
|
458
|
+
try {
|
|
459
|
+
const resp = yield client.post(`${basePath}/accept-proposal`, {
|
|
460
|
+
name,
|
|
461
|
+
slug,
|
|
462
|
+
pageType,
|
|
463
|
+
definition,
|
|
464
|
+
generationSource,
|
|
465
|
+
});
|
|
466
|
+
return {
|
|
467
|
+
content: [{ type: "text", text: JSON.stringify(resp.data, null, 2) }],
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
catch (error) {
|
|
471
|
+
return {
|
|
472
|
+
content: [{ type: "text", text: formatError(error, "accepting page proposal") }],
|
|
473
|
+
isError: true,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
}));
|
|
477
|
+
}
|