@lumibase/mcp-server 0.10.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.
- package/LICENSE +21 -0
- package/dist/index.cjs +1695 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1694 -0
- package/package.json +50 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1695 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// src/index.ts
|
|
5
|
+
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
6
|
+
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
7
|
+
|
|
8
|
+
// src/client.ts
|
|
9
|
+
var LumiBaseApiError = class extends Error {
|
|
10
|
+
constructor(status, errors) {
|
|
11
|
+
super(errors[0]?.message ?? `HTTP ${status}`);
|
|
12
|
+
this.status = status;
|
|
13
|
+
this.errors = errors;
|
|
14
|
+
this.name = "LumiBaseApiError";
|
|
15
|
+
}
|
|
16
|
+
status;
|
|
17
|
+
errors;
|
|
18
|
+
};
|
|
19
|
+
var LumiBaseClient = class {
|
|
20
|
+
baseUrl;
|
|
21
|
+
origin;
|
|
22
|
+
headers;
|
|
23
|
+
constructor(config) {
|
|
24
|
+
this.origin = config.url.replace(/\/$/, "");
|
|
25
|
+
this.baseUrl = this.origin + "/api/v1";
|
|
26
|
+
this.headers = {
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
Authorization: `Bearer ${config.token}`,
|
|
29
|
+
"X-Lumi-Site": config.siteId
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async request(method, path, body) {
|
|
33
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
34
|
+
method,
|
|
35
|
+
headers: this.headers,
|
|
36
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
37
|
+
});
|
|
38
|
+
if (res.status === 204) return void 0;
|
|
39
|
+
const json = await res.json();
|
|
40
|
+
if (!res.ok) {
|
|
41
|
+
throw new LumiBaseApiError(res.status, json.errors ?? [{ code: "UNKNOWN", message: `HTTP ${res.status}` }]);
|
|
42
|
+
}
|
|
43
|
+
return json.data;
|
|
44
|
+
}
|
|
45
|
+
get(path) {
|
|
46
|
+
return this.request("GET", path);
|
|
47
|
+
}
|
|
48
|
+
post(path, body) {
|
|
49
|
+
return this.request("POST", path, body);
|
|
50
|
+
}
|
|
51
|
+
patch(path, body) {
|
|
52
|
+
return this.request("PATCH", path, body);
|
|
53
|
+
}
|
|
54
|
+
put(path, body) {
|
|
55
|
+
return this.request("PUT", path, body);
|
|
56
|
+
}
|
|
57
|
+
delete(path) {
|
|
58
|
+
return this.request("DELETE", path);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* GET a root-level (non-`/api/v1`) endpoint such as `/health` or `/metrics`
|
|
62
|
+
* and return the raw response body as text. These endpoints are not
|
|
63
|
+
* tenant-scoped and do not use the `{data}` envelope.
|
|
64
|
+
*/
|
|
65
|
+
getRootText(path) {
|
|
66
|
+
return this.textRequest(`${this.origin}${path}`, "GET");
|
|
67
|
+
}
|
|
68
|
+
/** GET an `/api/v1` endpoint that returns a non-JSON body (e.g. NDJSON backup). */
|
|
69
|
+
getText(path) {
|
|
70
|
+
return this.textRequest(`${this.baseUrl}${path}`, "GET");
|
|
71
|
+
}
|
|
72
|
+
async textRequest(url, method) {
|
|
73
|
+
const res = await fetch(url, { method, headers: this.headers });
|
|
74
|
+
const text = await res.text();
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
throw new LumiBaseApiError(res.status, [
|
|
77
|
+
{ code: "HTTP", message: `HTTP ${res.status}: ${text.slice(0, 200)}` }
|
|
78
|
+
]);
|
|
79
|
+
}
|
|
80
|
+
return text;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* POST a raw (non-JSON) request body to an `/api/v1` endpoint and unwrap the
|
|
84
|
+
* `{data}` envelope from the JSON response (e.g. the NDJSON restore endpoint).
|
|
85
|
+
*/
|
|
86
|
+
async postRaw(path, body, contentType = "application/x-ndjson") {
|
|
87
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
88
|
+
method: "POST",
|
|
89
|
+
headers: { ...this.headers, "Content-Type": contentType },
|
|
90
|
+
body
|
|
91
|
+
});
|
|
92
|
+
if (res.status === 204) return void 0;
|
|
93
|
+
const json = await res.json();
|
|
94
|
+
if (!res.ok) {
|
|
95
|
+
throw new LumiBaseApiError(res.status, json.errors ?? [{ code: "UNKNOWN", message: `HTTP ${res.status}` }]);
|
|
96
|
+
}
|
|
97
|
+
return json.data;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
function configFromEnv() {
|
|
101
|
+
const url = process.env["LUMIBASE_URL"];
|
|
102
|
+
const siteId = process.env["LUMIBASE_SITE_ID"];
|
|
103
|
+
const token = process.env["LUMIBASE_TOKEN"];
|
|
104
|
+
if (!url || !siteId || !token) {
|
|
105
|
+
throw new Error(
|
|
106
|
+
"Missing required env vars: LUMIBASE_URL, LUMIBASE_SITE_ID, LUMIBASE_TOKEN"
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
return { url, siteId, token };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// src/tools/access.ts
|
|
113
|
+
var import_zod2 = require("zod");
|
|
114
|
+
|
|
115
|
+
// src/tools/_crud.ts
|
|
116
|
+
var import_zod = require("zod");
|
|
117
|
+
|
|
118
|
+
// src/tools/_shared.ts
|
|
119
|
+
function formatError(err) {
|
|
120
|
+
if (err instanceof LumiBaseApiError) {
|
|
121
|
+
return err.errors.map((e) => `[${e.code}] ${e.message}`).join("; ");
|
|
122
|
+
}
|
|
123
|
+
return String(err);
|
|
124
|
+
}
|
|
125
|
+
function buildQs(params) {
|
|
126
|
+
const q = new URLSearchParams();
|
|
127
|
+
for (const [k, v] of Object.entries(params)) {
|
|
128
|
+
if (v !== void 0) q.set(k, String(v));
|
|
129
|
+
}
|
|
130
|
+
const s = q.toString();
|
|
131
|
+
return s ? `?${s}` : "";
|
|
132
|
+
}
|
|
133
|
+
function ok(data) {
|
|
134
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
135
|
+
}
|
|
136
|
+
function okText(text) {
|
|
137
|
+
return { content: [{ type: "text", text }] };
|
|
138
|
+
}
|
|
139
|
+
function fail(err) {
|
|
140
|
+
return { content: [{ type: "text", text: `Error: ${formatError(err)}` }], isError: true };
|
|
141
|
+
}
|
|
142
|
+
async function run(fn) {
|
|
143
|
+
try {
|
|
144
|
+
const result = await fn();
|
|
145
|
+
if (result && typeof result === "object" && "content" in result) {
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
if (typeof result === "string") {
|
|
149
|
+
return okText(result);
|
|
150
|
+
}
|
|
151
|
+
return ok(result);
|
|
152
|
+
} catch (err) {
|
|
153
|
+
return fail(err);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
var confirmDescription = "Must be true to confirm the destructive operation";
|
|
157
|
+
|
|
158
|
+
// src/tools/_crud.ts
|
|
159
|
+
function registerCrud(server, client, opts) {
|
|
160
|
+
const {
|
|
161
|
+
basePath,
|
|
162
|
+
resource,
|
|
163
|
+
namePrefix,
|
|
164
|
+
listName = `list_${namePrefix}s`,
|
|
165
|
+
createSchema,
|
|
166
|
+
updateSchema,
|
|
167
|
+
listQuery,
|
|
168
|
+
enableDelete = true,
|
|
169
|
+
enableGet = true,
|
|
170
|
+
idParam = "id"
|
|
171
|
+
} = opts;
|
|
172
|
+
server.registerTool(
|
|
173
|
+
listName,
|
|
174
|
+
{
|
|
175
|
+
description: `List ${resource}s for the current site.`,
|
|
176
|
+
inputSchema: listQuery ?? {}
|
|
177
|
+
},
|
|
178
|
+
async (args) => run(() => {
|
|
179
|
+
const qs = buildQs(args);
|
|
180
|
+
return client.get(`${basePath}${qs}`);
|
|
181
|
+
})
|
|
182
|
+
);
|
|
183
|
+
if (enableGet) {
|
|
184
|
+
server.registerTool(
|
|
185
|
+
`get_${namePrefix}`,
|
|
186
|
+
{
|
|
187
|
+
description: `Get a single ${resource} by ${idParam}.`,
|
|
188
|
+
inputSchema: { [idParam]: import_zod.z.string().min(1) }
|
|
189
|
+
},
|
|
190
|
+
async (args) => run(() => client.get(`${basePath}/${String(args[idParam])}`))
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
if (createSchema) {
|
|
194
|
+
server.registerTool(
|
|
195
|
+
`create_${namePrefix}`,
|
|
196
|
+
{
|
|
197
|
+
description: `Create a new ${resource}.`,
|
|
198
|
+
inputSchema: createSchema
|
|
199
|
+
},
|
|
200
|
+
async (args) => run(() => client.post(basePath, args))
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
if (updateSchema) {
|
|
204
|
+
server.registerTool(
|
|
205
|
+
`update_${namePrefix}`,
|
|
206
|
+
{
|
|
207
|
+
description: `Update an existing ${resource} (partial PATCH).`,
|
|
208
|
+
inputSchema: { [idParam]: import_zod.z.string().min(1), ...updateSchema }
|
|
209
|
+
},
|
|
210
|
+
async (args) => {
|
|
211
|
+
const { [idParam]: id, ...patch } = args;
|
|
212
|
+
return run(() => client.patch(`${basePath}/${String(id)}`, patch));
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
if (enableDelete) {
|
|
217
|
+
server.registerTool(
|
|
218
|
+
`delete_${namePrefix}`,
|
|
219
|
+
{
|
|
220
|
+
description: `Delete a ${resource}. DESTRUCTIVE \u2014 warn the user first and pass confirm=true.`,
|
|
221
|
+
inputSchema: {
|
|
222
|
+
[idParam]: import_zod.z.string().min(1),
|
|
223
|
+
confirm: import_zod.z.literal(true).describe(confirmDescription)
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
async (args) => {
|
|
227
|
+
const id = String(args[idParam]);
|
|
228
|
+
return run(async () => {
|
|
229
|
+
await client.delete(`${basePath}/${id}`);
|
|
230
|
+
return okText(`${resource} "${id}" deleted.`);
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// src/tools/access.ts
|
|
238
|
+
var roleSchema = import_zod2.z.object({
|
|
239
|
+
key: import_zod2.z.string().min(1).max(96).optional(),
|
|
240
|
+
systemKey: import_zod2.z.string().min(1).max(96).optional(),
|
|
241
|
+
name: import_zod2.z.string().min(1).max(64),
|
|
242
|
+
description: import_zod2.z.string().max(512).optional(),
|
|
243
|
+
icon: import_zod2.z.string().max(64).optional(),
|
|
244
|
+
parentId: import_zod2.z.string().nullable().optional(),
|
|
245
|
+
adminAccess: import_zod2.z.boolean().optional(),
|
|
246
|
+
appAccess: import_zod2.z.boolean().optional()
|
|
247
|
+
});
|
|
248
|
+
var policySchema = import_zod2.z.object({
|
|
249
|
+
key: import_zod2.z.string().min(1).max(96).optional(),
|
|
250
|
+
name: import_zod2.z.string().min(1).max(64),
|
|
251
|
+
icon: import_zod2.z.string().max(64).optional(),
|
|
252
|
+
description: import_zod2.z.string().max(512).optional(),
|
|
253
|
+
adminAccess: import_zod2.z.boolean().optional(),
|
|
254
|
+
appAccess: import_zod2.z.boolean().optional(),
|
|
255
|
+
enforceTfa: import_zod2.z.boolean().optional(),
|
|
256
|
+
ipAllow: import_zod2.z.array(import_zod2.z.string()).optional(),
|
|
257
|
+
ipDeny: import_zod2.z.array(import_zod2.z.string()).optional(),
|
|
258
|
+
validFrom: import_zod2.z.string().datetime().nullable().optional(),
|
|
259
|
+
validUntil: import_zod2.z.string().datetime().nullable().optional(),
|
|
260
|
+
rules: import_zod2.z.record(import_zod2.z.unknown()).optional()
|
|
261
|
+
});
|
|
262
|
+
var permissionSchema = import_zod2.z.object({
|
|
263
|
+
collection: import_zod2.z.string().min(1).max(64),
|
|
264
|
+
action: import_zod2.z.enum(["create", "read", "update", "delete", "share"]),
|
|
265
|
+
permissions: import_zod2.z.record(import_zod2.z.unknown()).optional(),
|
|
266
|
+
validation: import_zod2.z.record(import_zod2.z.unknown()).optional(),
|
|
267
|
+
presets: import_zod2.z.record(import_zod2.z.unknown()).optional(),
|
|
268
|
+
fields: import_zod2.z.array(import_zod2.z.string()).optional()
|
|
269
|
+
});
|
|
270
|
+
function registerAccessTools(server, client) {
|
|
271
|
+
registerCrud(server, client, {
|
|
272
|
+
basePath: "/roles",
|
|
273
|
+
resource: "role",
|
|
274
|
+
namePrefix: "role",
|
|
275
|
+
createSchema: roleSchema.shape,
|
|
276
|
+
updateSchema: roleSchema.partial().shape
|
|
277
|
+
});
|
|
278
|
+
server.registerTool(
|
|
279
|
+
"attach_role_policy",
|
|
280
|
+
{
|
|
281
|
+
description: "Attach a policy to a role. Conflicts/warnings may require overrideWarnings=true.",
|
|
282
|
+
inputSchema: {
|
|
283
|
+
id: import_zod2.z.string().min(1).describe("Role id."),
|
|
284
|
+
policyId: import_zod2.z.string().min(1),
|
|
285
|
+
priority: import_zod2.z.number().int().optional(),
|
|
286
|
+
overrideWarnings: import_zod2.z.boolean().optional()
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
async ({ id, ...body }) => run(() => client.post(`/roles/${id}/policies`, body))
|
|
290
|
+
);
|
|
291
|
+
server.registerTool(
|
|
292
|
+
"detach_role_policy",
|
|
293
|
+
{
|
|
294
|
+
description: "Detach a policy from a role. DESTRUCTIVE \u2014 pass confirm=true.",
|
|
295
|
+
inputSchema: {
|
|
296
|
+
id: import_zod2.z.string().min(1).describe("Role id."),
|
|
297
|
+
policyId: import_zod2.z.string().min(1),
|
|
298
|
+
confirm: import_zod2.z.literal(true).describe(confirmDescription)
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
async ({ id, policyId }) => run(async () => {
|
|
302
|
+
await client.delete(`/roles/${id}/policies/${policyId}`);
|
|
303
|
+
return okText(`Policy "${policyId}" detached from role "${id}".`);
|
|
304
|
+
})
|
|
305
|
+
);
|
|
306
|
+
server.registerTool(
|
|
307
|
+
"assign_role_user",
|
|
308
|
+
{
|
|
309
|
+
description: "Assign a role to a user (sets the user's primary role for this site).",
|
|
310
|
+
inputSchema: { id: import_zod2.z.string().min(1).describe("Role id."), userId: import_zod2.z.string().min(1) }
|
|
311
|
+
},
|
|
312
|
+
async ({ id, userId }) => run(() => client.post(`/roles/${id}/users`, { userId }))
|
|
313
|
+
);
|
|
314
|
+
server.registerTool(
|
|
315
|
+
"remove_role_user",
|
|
316
|
+
{
|
|
317
|
+
description: "Remove a user's role assignment. DESTRUCTIVE \u2014 pass confirm=true.",
|
|
318
|
+
inputSchema: {
|
|
319
|
+
id: import_zod2.z.string().min(1).describe("Role id."),
|
|
320
|
+
userId: import_zod2.z.string().min(1),
|
|
321
|
+
confirm: import_zod2.z.literal(true).describe(confirmDescription)
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
async ({ id, userId }) => run(async () => {
|
|
325
|
+
await client.delete(`/roles/${id}/users/${userId}`);
|
|
326
|
+
return okText(`User "${userId}" removed from role "${id}".`);
|
|
327
|
+
})
|
|
328
|
+
);
|
|
329
|
+
registerCrud(server, client, {
|
|
330
|
+
basePath: "/policies",
|
|
331
|
+
resource: "policy",
|
|
332
|
+
namePrefix: "policy",
|
|
333
|
+
listName: "list_policies",
|
|
334
|
+
createSchema: policySchema.shape,
|
|
335
|
+
updateSchema: policySchema.partial().shape
|
|
336
|
+
});
|
|
337
|
+
server.registerTool(
|
|
338
|
+
"add_policy_permission",
|
|
339
|
+
{
|
|
340
|
+
description: "Add a permission row (collection + action) to a policy.",
|
|
341
|
+
inputSchema: { id: import_zod2.z.string().min(1).describe("Policy id."), ...permissionSchema.shape }
|
|
342
|
+
},
|
|
343
|
+
async ({ id, ...body }) => run(() => client.post(`/policies/${id}/permissions`, body))
|
|
344
|
+
);
|
|
345
|
+
server.registerTool(
|
|
346
|
+
"update_policy_permission",
|
|
347
|
+
{
|
|
348
|
+
description: "Update a permission row on a policy (partial PATCH).",
|
|
349
|
+
inputSchema: {
|
|
350
|
+
id: import_zod2.z.string().min(1).describe("Policy id."),
|
|
351
|
+
permId: import_zod2.z.string().min(1).describe("Permission row id."),
|
|
352
|
+
...permissionSchema.partial().shape
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
async ({ id, permId, ...body }) => run(() => client.patch(`/policies/${id}/permissions/${permId}`, body))
|
|
356
|
+
);
|
|
357
|
+
server.registerTool(
|
|
358
|
+
"delete_policy_permission",
|
|
359
|
+
{
|
|
360
|
+
description: "Delete a permission row from a policy. DESTRUCTIVE \u2014 pass confirm=true.",
|
|
361
|
+
inputSchema: {
|
|
362
|
+
id: import_zod2.z.string().min(1).describe("Policy id."),
|
|
363
|
+
permId: import_zod2.z.string().min(1).describe("Permission row id."),
|
|
364
|
+
confirm: import_zod2.z.literal(true).describe(confirmDescription)
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
async ({ id, permId }) => run(async () => {
|
|
368
|
+
await client.delete(`/policies/${id}/permissions/${permId}`);
|
|
369
|
+
return okText(`Permission "${permId}" deleted from policy "${id}".`);
|
|
370
|
+
})
|
|
371
|
+
);
|
|
372
|
+
server.registerTool(
|
|
373
|
+
"attach_policy_user",
|
|
374
|
+
{
|
|
375
|
+
description: "Attach a policy directly to a user. Warnings may require overrideWarnings=true.",
|
|
376
|
+
inputSchema: {
|
|
377
|
+
id: import_zod2.z.string().min(1).describe("Policy id."),
|
|
378
|
+
userId: import_zod2.z.string().min(1),
|
|
379
|
+
priority: import_zod2.z.number().int().optional(),
|
|
380
|
+
overrideWarnings: import_zod2.z.boolean().optional()
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
async ({ id, ...body }) => run(() => client.post(`/policies/${id}/users`, body))
|
|
384
|
+
);
|
|
385
|
+
server.registerTool(
|
|
386
|
+
"detach_policy_user",
|
|
387
|
+
{
|
|
388
|
+
description: "Detach a policy from a user. DESTRUCTIVE \u2014 pass confirm=true.",
|
|
389
|
+
inputSchema: {
|
|
390
|
+
id: import_zod2.z.string().min(1).describe("Policy id."),
|
|
391
|
+
userId: import_zod2.z.string().min(1),
|
|
392
|
+
confirm: import_zod2.z.literal(true).describe(confirmDescription)
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
async ({ id, userId }) => run(async () => {
|
|
396
|
+
await client.delete(`/policies/${id}/users/${userId}`);
|
|
397
|
+
return okText(`Policy "${id}" detached from user "${userId}".`);
|
|
398
|
+
})
|
|
399
|
+
);
|
|
400
|
+
server.registerTool(
|
|
401
|
+
"export_access",
|
|
402
|
+
{ description: "Export the full RBAC manifest (roles, policies, permissions, bindings).", inputSchema: {} },
|
|
403
|
+
async () => run(() => client.get("/access/export"))
|
|
404
|
+
);
|
|
405
|
+
server.registerTool(
|
|
406
|
+
"dry_run_access_import",
|
|
407
|
+
{
|
|
408
|
+
description: "Validate an RBAC manifest import without applying it. Returns the planned changes.",
|
|
409
|
+
inputSchema: { manifest: import_zod2.z.record(import_zod2.z.unknown()).describe("RBAC manifest from export_access.") }
|
|
410
|
+
},
|
|
411
|
+
async ({ manifest }) => run(() => client.post("/access/import?dryRun=true", manifest))
|
|
412
|
+
);
|
|
413
|
+
server.registerTool(
|
|
414
|
+
"apply_access_import",
|
|
415
|
+
{
|
|
416
|
+
description: "Apply an RBAC manifest import. High-impact \u2014 changes roles/policies/permissions. Pass confirm=true.",
|
|
417
|
+
inputSchema: {
|
|
418
|
+
manifest: import_zod2.z.record(import_zod2.z.unknown()).describe("RBAC manifest from export_access."),
|
|
419
|
+
mode: import_zod2.z.enum(["merge", "replace-managed", "replace-all"]).optional().describe("Import mode (default merge)."),
|
|
420
|
+
confirm: import_zod2.z.literal(true).describe(confirmDescription)
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
async ({ manifest, mode }) => run(() => client.post(`/access/import${mode ? `?mode=${mode}` : ""}`, manifest))
|
|
424
|
+
);
|
|
425
|
+
server.registerTool(
|
|
426
|
+
"check_access_conflicts",
|
|
427
|
+
{
|
|
428
|
+
description: "Check for permission conflicts before attaching/detaching policies on a target.",
|
|
429
|
+
inputSchema: {
|
|
430
|
+
target: import_zod2.z.object({ type: import_zod2.z.enum(["role", "user", "api_key"]), id: import_zod2.z.string().min(1) }).describe("The role/user/api_key the policies would apply to."),
|
|
431
|
+
addPolicies: import_zod2.z.array(import_zod2.z.string()).optional(),
|
|
432
|
+
removePolicies: import_zod2.z.array(import_zod2.z.string()).optional()
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
async (input) => run(() => client.post("/access/conflicts/check", input))
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// src/tools/admin.ts
|
|
440
|
+
var import_zod3 = require("zod");
|
|
441
|
+
var materializeSchema = import_zod3.z.object({
|
|
442
|
+
collection: import_zod3.z.string().min(1).describe("Source collection name."),
|
|
443
|
+
target: import_zod3.z.string().regex(/^[a-z][a-z0-9_]{0,62}$/).describe("Physical table name (snake_case)."),
|
|
444
|
+
refreshStrategy: import_zod3.z.enum(["auto", "cron", "manual"]).optional(),
|
|
445
|
+
refreshCron: import_zod3.z.string().optional(),
|
|
446
|
+
projection: import_zod3.z.object({ fields: import_zod3.z.array(import_zod3.z.string()).optional(), orderBy: import_zod3.z.string().optional() }).optional(),
|
|
447
|
+
filter: import_zod3.z.record(import_zod3.z.unknown()).optional()
|
|
448
|
+
});
|
|
449
|
+
function registerAdminTools(server, client) {
|
|
450
|
+
server.registerTool(
|
|
451
|
+
"export_backup",
|
|
452
|
+
{
|
|
453
|
+
description: "Export the full site configuration (collections, fields, RBAC, \u2026) as an NDJSON bundle.",
|
|
454
|
+
inputSchema: {}
|
|
455
|
+
},
|
|
456
|
+
async () => run(async () => okText(await client.getText("/admin/backup")))
|
|
457
|
+
);
|
|
458
|
+
server.registerTool(
|
|
459
|
+
"restore_backup",
|
|
460
|
+
{
|
|
461
|
+
description: "Restore a site configuration from an NDJSON bundle (as produced by export_backup). Existing rows are skipped (idempotent). DESTRUCTIVE / high-impact \u2014 pass confirm=true.",
|
|
462
|
+
inputSchema: {
|
|
463
|
+
ndjson: import_zod3.z.string().min(1).describe("Raw NDJSON backup content, one JSON object per line."),
|
|
464
|
+
confirm: import_zod3.z.literal(true).describe(confirmDescription)
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
async ({ ndjson }) => run(() => client.postRaw("/admin/restore", ndjson))
|
|
468
|
+
);
|
|
469
|
+
server.registerTool(
|
|
470
|
+
"list_materializations",
|
|
471
|
+
{ description: "List materialized collections (physical tables).", inputSchema: {} },
|
|
472
|
+
async () => run(() => client.get("/materialize"))
|
|
473
|
+
);
|
|
474
|
+
server.registerTool(
|
|
475
|
+
"register_materialization",
|
|
476
|
+
{
|
|
477
|
+
description: "Register a materialized collection and create its physical table.",
|
|
478
|
+
inputSchema: materializeSchema.shape
|
|
479
|
+
},
|
|
480
|
+
async (input) => run(() => client.post("/materialize", input))
|
|
481
|
+
);
|
|
482
|
+
server.registerTool(
|
|
483
|
+
"refresh_materialization",
|
|
484
|
+
{
|
|
485
|
+
description: "Refresh a materialized collection (truncate + re-insert from source).",
|
|
486
|
+
inputSchema: { id: import_zod3.z.string().min(1) }
|
|
487
|
+
},
|
|
488
|
+
async ({ id }) => run(() => client.post(`/materialize/${id}/refresh`, {}))
|
|
489
|
+
);
|
|
490
|
+
server.registerTool(
|
|
491
|
+
"query_materialization",
|
|
492
|
+
{
|
|
493
|
+
description: "Query the physical table of a materialized collection directly.",
|
|
494
|
+
inputSchema: { id: import_zod3.z.string().min(1) }
|
|
495
|
+
},
|
|
496
|
+
async ({ id }) => run(() => client.get(`/materialize/${id}/data`))
|
|
497
|
+
);
|
|
498
|
+
server.registerTool(
|
|
499
|
+
"drop_materialization",
|
|
500
|
+
{
|
|
501
|
+
description: "Drop a materialized collection (physical table + metadata). DESTRUCTIVE \u2014 pass confirm=true.",
|
|
502
|
+
inputSchema: { id: import_zod3.z.string().min(1), confirm: import_zod3.z.literal(true).describe(confirmDescription) }
|
|
503
|
+
},
|
|
504
|
+
async ({ id }) => run(async () => {
|
|
505
|
+
await client.delete(`/materialize/${id}`);
|
|
506
|
+
return okText(`Materialization "${id}" dropped.`);
|
|
507
|
+
})
|
|
508
|
+
);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// src/tools/agent.ts
|
|
512
|
+
var import_zod4 = require("zod");
|
|
513
|
+
var intentSchema = import_zod4.z.object({
|
|
514
|
+
name: import_zod4.z.string().min(1).max(120),
|
|
515
|
+
collection: import_zod4.z.string().min(1).max(120),
|
|
516
|
+
rules: import_zod4.z.array(import_zod4.z.record(import_zod4.z.unknown())).describe("SLO rules (required_fields, freshness, translations, link_health, \u2026)."),
|
|
517
|
+
schedule: import_zod4.z.string().describe("5-field cron expression for reconciliation cadence."),
|
|
518
|
+
budget: import_zod4.z.record(import_zod4.z.unknown()).optional(),
|
|
519
|
+
autonomyCap: import_zod4.z.number().int().min(0).max(4).optional().describe("Max autonomy level L0\u2013L4 for this intent."),
|
|
520
|
+
maintenanceWindow: import_zod4.z.record(import_zod4.z.unknown()).nullable().optional()
|
|
521
|
+
});
|
|
522
|
+
var flowNode = import_zod4.z.object({
|
|
523
|
+
id: import_zod4.z.string(),
|
|
524
|
+
key: import_zod4.z.string(),
|
|
525
|
+
options: import_zod4.z.record(import_zod4.z.unknown()).optional(),
|
|
526
|
+
next: import_zod4.z.string().nullable().optional(),
|
|
527
|
+
onError: import_zod4.z.string().nullable().optional()
|
|
528
|
+
});
|
|
529
|
+
var flowSchema = import_zod4.z.object({
|
|
530
|
+
name: import_zod4.z.string().min(1),
|
|
531
|
+
description: import_zod4.z.string().optional(),
|
|
532
|
+
status: import_zod4.z.enum(["active", "inactive", "draft"]).optional(),
|
|
533
|
+
triggerType: import_zod4.z.enum(["webhook", "event", "schedule", "manual"]),
|
|
534
|
+
triggerOptions: import_zod4.z.record(import_zod4.z.unknown()).optional(),
|
|
535
|
+
graph: import_zod4.z.object({
|
|
536
|
+
entry: import_zod4.z.string().optional(),
|
|
537
|
+
nodes: import_zod4.z.array(flowNode).optional()
|
|
538
|
+
})
|
|
539
|
+
});
|
|
540
|
+
function registerAgentTools(server, client) {
|
|
541
|
+
registerCrud(server, client, {
|
|
542
|
+
basePath: "/agent/intents",
|
|
543
|
+
resource: "intent",
|
|
544
|
+
namePrefix: "intent",
|
|
545
|
+
createSchema: intentSchema.shape,
|
|
546
|
+
updateSchema: intentSchema.partial().shape
|
|
547
|
+
});
|
|
548
|
+
server.registerTool(
|
|
549
|
+
"pause_intent",
|
|
550
|
+
{ description: "Pause an intent (stops scheduled reconciliation).", inputSchema: { id: import_zod4.z.string().min(1) } },
|
|
551
|
+
async ({ id }) => run(() => client.post(`/agent/intents/${id}/pause`, {}))
|
|
552
|
+
);
|
|
553
|
+
server.registerTool(
|
|
554
|
+
"resume_intent",
|
|
555
|
+
{ description: "Resume a paused intent.", inputSchema: { id: import_zod4.z.string().min(1) } },
|
|
556
|
+
async ({ id }) => run(() => client.post(`/agent/intents/${id}/resume`, {}))
|
|
557
|
+
);
|
|
558
|
+
server.registerTool(
|
|
559
|
+
"list_intent_drifts",
|
|
560
|
+
{ description: "List detected drifts (intent violations) for an intent.", inputSchema: { id: import_zod4.z.string().min(1) } },
|
|
561
|
+
async ({ id }) => run(() => client.get(`/agent/intents/${id}/drifts`))
|
|
562
|
+
);
|
|
563
|
+
server.registerTool(
|
|
564
|
+
"scan_intent",
|
|
565
|
+
{ description: "Trigger an on-demand drift scan for an intent.", inputSchema: { id: import_zod4.z.string().min(1) } },
|
|
566
|
+
async ({ id }) => run(() => client.post(`/agent/intents/${id}/scan`, {}))
|
|
567
|
+
);
|
|
568
|
+
server.registerTool(
|
|
569
|
+
"compile_intent",
|
|
570
|
+
{
|
|
571
|
+
description: "Compile a natural-language description into structured intent rules (preview, does not persist).",
|
|
572
|
+
inputSchema: {
|
|
573
|
+
description: import_zod4.z.string().min(1).max(4e3),
|
|
574
|
+
collection: import_zod4.z.string().min(1).max(120)
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
async (input) => run(() => client.post("/agent/intents/compile", input))
|
|
578
|
+
);
|
|
579
|
+
registerCrud(server, client, {
|
|
580
|
+
basePath: "/flows",
|
|
581
|
+
resource: "flow",
|
|
582
|
+
namePrefix: "flow",
|
|
583
|
+
createSchema: flowSchema.shape,
|
|
584
|
+
updateSchema: flowSchema.partial().shape
|
|
585
|
+
});
|
|
586
|
+
server.registerTool(
|
|
587
|
+
"run_flow",
|
|
588
|
+
{
|
|
589
|
+
description: "Trigger a manual run of a flow with an optional input payload.",
|
|
590
|
+
inputSchema: {
|
|
591
|
+
id: import_zod4.z.string().min(1),
|
|
592
|
+
input: import_zod4.z.record(import_zod4.z.unknown()).optional().describe("Initial context passed to the flow.")
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
async ({ id, input }) => run(() => client.post(`/flows/${id}/run`, input ?? {}))
|
|
596
|
+
);
|
|
597
|
+
server.registerTool(
|
|
598
|
+
"list_flow_runs",
|
|
599
|
+
{ description: "List recent runs of a flow.", inputSchema: { id: import_zod4.z.string().min(1) } },
|
|
600
|
+
async ({ id }) => run(() => client.get(`/flows/${id}/runs`))
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/tools/api-keys.ts
|
|
605
|
+
var import_zod5 = require("zod");
|
|
606
|
+
function registerApiKeyTools(server, client) {
|
|
607
|
+
server.registerTool(
|
|
608
|
+
"list_api_keys",
|
|
609
|
+
{ description: "List API keys for the site (token values are never returned).", inputSchema: {} },
|
|
610
|
+
async () => run(() => client.get("/api-keys"))
|
|
611
|
+
);
|
|
612
|
+
server.registerTool(
|
|
613
|
+
"get_api_key",
|
|
614
|
+
{ description: "Get a single API key by id.", inputSchema: { id: import_zod5.z.string().min(1) } },
|
|
615
|
+
async ({ id }) => run(() => client.get(`/api-keys/${id}`))
|
|
616
|
+
);
|
|
617
|
+
server.registerTool(
|
|
618
|
+
"create_api_key",
|
|
619
|
+
{
|
|
620
|
+
description: "Create a new API key. The plaintext token is returned ONCE in the response \u2014 surface it to the user and tell them it cannot be retrieved again.",
|
|
621
|
+
inputSchema: {
|
|
622
|
+
name: import_zod5.z.string().min(1).max(96),
|
|
623
|
+
description: import_zod5.z.string().max(512).optional(),
|
|
624
|
+
expiresAt: import_zod5.z.string().datetime().nullable().optional(),
|
|
625
|
+
metadata: import_zod5.z.record(import_zod5.z.unknown()).optional()
|
|
626
|
+
}
|
|
627
|
+
},
|
|
628
|
+
async (input) => run(() => client.post("/api-keys", input))
|
|
629
|
+
);
|
|
630
|
+
server.registerTool(
|
|
631
|
+
"rotate_api_key",
|
|
632
|
+
{
|
|
633
|
+
description: "Rotate an API key \u2014 issues a new token (returned once) and invalidates the old one. DESTRUCTIVE for existing integrations \u2014 pass confirm=true.",
|
|
634
|
+
inputSchema: {
|
|
635
|
+
id: import_zod5.z.string().min(1),
|
|
636
|
+
expiresAt: import_zod5.z.string().datetime().nullable().optional(),
|
|
637
|
+
confirm: import_zod5.z.literal(true).describe(confirmDescription)
|
|
638
|
+
}
|
|
639
|
+
},
|
|
640
|
+
async ({ id, expiresAt }) => run(() => client.post(`/api-keys/${id}/rotate`, expiresAt !== void 0 ? { expiresAt } : {}))
|
|
641
|
+
);
|
|
642
|
+
server.registerTool(
|
|
643
|
+
"revoke_api_key",
|
|
644
|
+
{
|
|
645
|
+
description: "Revoke an API key permanently. DESTRUCTIVE \u2014 pass confirm=true.",
|
|
646
|
+
inputSchema: { id: import_zod5.z.string().min(1), confirm: import_zod5.z.literal(true).describe(confirmDescription) }
|
|
647
|
+
},
|
|
648
|
+
async ({ id }) => run(() => client.post(`/api-keys/${id}/revoke`, {}))
|
|
649
|
+
);
|
|
650
|
+
server.registerTool(
|
|
651
|
+
"attach_api_key_role",
|
|
652
|
+
{
|
|
653
|
+
description: "Attach a role to an API key (grants the role\u2019s policies to the key).",
|
|
654
|
+
inputSchema: {
|
|
655
|
+
id: import_zod5.z.string().min(1).describe("API key id."),
|
|
656
|
+
roleId: import_zod5.z.string().min(1),
|
|
657
|
+
priority: import_zod5.z.number().int().optional(),
|
|
658
|
+
overrideWarnings: import_zod5.z.boolean().optional()
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
async ({ id, ...body }) => run(() => client.post(`/api-keys/${id}/roles`, body))
|
|
662
|
+
);
|
|
663
|
+
server.registerTool(
|
|
664
|
+
"detach_api_key_role",
|
|
665
|
+
{
|
|
666
|
+
description: "Detach a role from an API key. DESTRUCTIVE \u2014 pass confirm=true.",
|
|
667
|
+
inputSchema: {
|
|
668
|
+
id: import_zod5.z.string().min(1).describe("API key id."),
|
|
669
|
+
roleId: import_zod5.z.string().min(1),
|
|
670
|
+
confirm: import_zod5.z.literal(true).describe(confirmDescription)
|
|
671
|
+
}
|
|
672
|
+
},
|
|
673
|
+
async ({ id, roleId }) => run(async () => {
|
|
674
|
+
await client.delete(`/api-keys/${id}/roles/${roleId}`);
|
|
675
|
+
return okText(`Role "${roleId}" detached from API key "${id}".`);
|
|
676
|
+
})
|
|
677
|
+
);
|
|
678
|
+
server.registerTool(
|
|
679
|
+
"attach_api_key_policy",
|
|
680
|
+
{
|
|
681
|
+
description: "Attach a policy directly to an API key.",
|
|
682
|
+
inputSchema: {
|
|
683
|
+
id: import_zod5.z.string().min(1).describe("API key id."),
|
|
684
|
+
policyId: import_zod5.z.string().min(1),
|
|
685
|
+
priority: import_zod5.z.number().int().optional(),
|
|
686
|
+
overrideWarnings: import_zod5.z.boolean().optional()
|
|
687
|
+
}
|
|
688
|
+
},
|
|
689
|
+
async ({ id, ...body }) => run(() => client.post(`/api-keys/${id}/policies`, body))
|
|
690
|
+
);
|
|
691
|
+
server.registerTool(
|
|
692
|
+
"detach_api_key_policy",
|
|
693
|
+
{
|
|
694
|
+
description: "Detach a policy from an API key. DESTRUCTIVE \u2014 pass confirm=true.",
|
|
695
|
+
inputSchema: {
|
|
696
|
+
id: import_zod5.z.string().min(1).describe("API key id."),
|
|
697
|
+
policyId: import_zod5.z.string().min(1),
|
|
698
|
+
confirm: import_zod5.z.literal(true).describe(confirmDescription)
|
|
699
|
+
}
|
|
700
|
+
},
|
|
701
|
+
async ({ id, policyId }) => run(async () => {
|
|
702
|
+
await client.delete(`/api-keys/${id}/policies/${policyId}`);
|
|
703
|
+
return okText(`Policy "${policyId}" detached from API key "${id}".`);
|
|
704
|
+
})
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// src/tools/collections.ts
|
|
709
|
+
var import_zod6 = require("zod");
|
|
710
|
+
var collectionNameSchema = import_zod6.z.string().min(1).max(63).regex(/^[a-z][a-z0-9_]{0,62}$/, "Must be lowercase, start with a letter, only a-z0-9_");
|
|
711
|
+
var collectionInputSchema = import_zod6.z.object({
|
|
712
|
+
name: collectionNameSchema,
|
|
713
|
+
label: import_zod6.z.string().optional(),
|
|
714
|
+
pluralLabel: import_zod6.z.string().optional(),
|
|
715
|
+
hidden: import_zod6.z.boolean().optional(),
|
|
716
|
+
singleton: import_zod6.z.boolean().optional(),
|
|
717
|
+
icon: import_zod6.z.string().optional(),
|
|
718
|
+
color: import_zod6.z.string().optional(),
|
|
719
|
+
note: import_zod6.z.string().optional(),
|
|
720
|
+
primaryKeyField: import_zod6.z.string().optional(),
|
|
721
|
+
primaryKeyType: import_zod6.z.enum(["nanoid", "uuid", "integer", "bigInteger", "string"]).optional(),
|
|
722
|
+
storageMode: import_zod6.z.enum(["jsonb", "materialized", "physical", "external"]).optional(),
|
|
723
|
+
displayTemplate: import_zod6.z.string().optional(),
|
|
724
|
+
sortField: import_zod6.z.string().optional(),
|
|
725
|
+
archiveField: import_zod6.z.string().optional(),
|
|
726
|
+
archiveValue: import_zod6.z.string().optional(),
|
|
727
|
+
unarchiveValue: import_zod6.z.string().optional(),
|
|
728
|
+
accountability: import_zod6.z.enum(["all", "activity", "none"]).optional(),
|
|
729
|
+
versioning: import_zod6.z.boolean().optional()
|
|
730
|
+
});
|
|
731
|
+
var fieldInputSchema = import_zod6.z.object({
|
|
732
|
+
name: collectionNameSchema,
|
|
733
|
+
type: import_zod6.z.string().min(1),
|
|
734
|
+
interface: import_zod6.z.string().min(1),
|
|
735
|
+
display: import_zod6.z.string().optional(),
|
|
736
|
+
label: import_zod6.z.string().optional(),
|
|
737
|
+
note: import_zod6.z.string().optional(),
|
|
738
|
+
nullable: import_zod6.z.boolean().optional(),
|
|
739
|
+
unique: import_zod6.z.boolean().optional(),
|
|
740
|
+
indexed: import_zod6.z.boolean().optional(),
|
|
741
|
+
searchable: import_zod6.z.boolean().optional(),
|
|
742
|
+
required: import_zod6.z.boolean().optional(),
|
|
743
|
+
readonly: import_zod6.z.boolean().optional(),
|
|
744
|
+
hidden: import_zod6.z.boolean().optional(),
|
|
745
|
+
width: import_zod6.z.enum(["half", "full", "fill"]).optional(),
|
|
746
|
+
sortOrder: import_zod6.z.number().int().optional(),
|
|
747
|
+
group: import_zod6.z.string().optional(),
|
|
748
|
+
options: import_zod6.z.record(import_zod6.z.unknown()).optional(),
|
|
749
|
+
defaultValue: import_zod6.z.unknown().optional()
|
|
750
|
+
});
|
|
751
|
+
function formatError2(err) {
|
|
752
|
+
if (err instanceof LumiBaseApiError) {
|
|
753
|
+
return err.errors.map((e) => `[${e.code}] ${e.message}`).join("; ");
|
|
754
|
+
}
|
|
755
|
+
return String(err);
|
|
756
|
+
}
|
|
757
|
+
function registerCollectionTools(server, client) {
|
|
758
|
+
server.registerTool(
|
|
759
|
+
"list_collections",
|
|
760
|
+
{
|
|
761
|
+
description: "List all collections in the LumiBase site.",
|
|
762
|
+
inputSchema: {}
|
|
763
|
+
},
|
|
764
|
+
async () => {
|
|
765
|
+
try {
|
|
766
|
+
const data = await client.get("/collections");
|
|
767
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
768
|
+
} catch (err) {
|
|
769
|
+
return { content: [{ type: "text", text: `Error: ${formatError2(err)}` }], isError: true };
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
);
|
|
773
|
+
server.registerTool(
|
|
774
|
+
"get_collection",
|
|
775
|
+
{
|
|
776
|
+
description: "Get a collection with its compiled schema (all fields, system fields, meta).",
|
|
777
|
+
inputSchema: { name: import_zod6.z.string().min(1) }
|
|
778
|
+
},
|
|
779
|
+
async ({ name }) => {
|
|
780
|
+
try {
|
|
781
|
+
const data = await client.get(`/collections/${name}/compiled`);
|
|
782
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
783
|
+
} catch (err) {
|
|
784
|
+
return { content: [{ type: "text", text: `Error: ${formatError2(err)}` }], isError: true };
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
);
|
|
788
|
+
server.registerTool(
|
|
789
|
+
"create_collection",
|
|
790
|
+
{
|
|
791
|
+
description: 'Create a new collection. Name must be lowercase snake_case (e.g. "blog_posts"). storageMode defaults to "jsonb" (recommended for most use-cases). primaryKeyType defaults to "nanoid".',
|
|
792
|
+
inputSchema: collectionInputSchema.shape
|
|
793
|
+
},
|
|
794
|
+
async (input) => {
|
|
795
|
+
try {
|
|
796
|
+
const data = await client.post("/collections", input);
|
|
797
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
798
|
+
} catch (err) {
|
|
799
|
+
return { content: [{ type: "text", text: `Error: ${formatError2(err)}` }], isError: true };
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
);
|
|
803
|
+
server.registerTool(
|
|
804
|
+
"update_collection",
|
|
805
|
+
{
|
|
806
|
+
description: "Update metadata on an existing collection (label, icon, note, accountability, etc.).",
|
|
807
|
+
inputSchema: {
|
|
808
|
+
name: import_zod6.z.string().min(1),
|
|
809
|
+
patch: collectionInputSchema.omit({ name: true }).partial()
|
|
810
|
+
}
|
|
811
|
+
},
|
|
812
|
+
async ({ name, patch }) => {
|
|
813
|
+
try {
|
|
814
|
+
const data = await client.patch(`/collections/${name}`, patch);
|
|
815
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
816
|
+
} catch (err) {
|
|
817
|
+
return { content: [{ type: "text", text: `Error: ${formatError2(err)}` }], isError: true };
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
);
|
|
821
|
+
server.registerTool(
|
|
822
|
+
"delete_collection",
|
|
823
|
+
{
|
|
824
|
+
description: "Delete a collection and all its items. DESTRUCTIVE \u2014 cannot be undone. You MUST pass confirm=true explicitly after warning the user.",
|
|
825
|
+
inputSchema: {
|
|
826
|
+
name: import_zod6.z.string().min(1),
|
|
827
|
+
confirm: import_zod6.z.literal(true).describe("Must be true to confirm destructive operation")
|
|
828
|
+
}
|
|
829
|
+
},
|
|
830
|
+
async ({ name, confirm: _ }) => {
|
|
831
|
+
try {
|
|
832
|
+
await client.delete(`/collections/${name}`);
|
|
833
|
+
return { content: [{ type: "text", text: `Collection "${name}" deleted.` }] };
|
|
834
|
+
} catch (err) {
|
|
835
|
+
return { content: [{ type: "text", text: `Error: ${formatError2(err)}` }], isError: true };
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
);
|
|
839
|
+
server.registerTool(
|
|
840
|
+
"diff_schema",
|
|
841
|
+
{
|
|
842
|
+
description: "Preview what would change if you applied a schema update. Returns added/modified/removed fields and any risky changes. Always call this before apply_schema to check for breaking changes.",
|
|
843
|
+
inputSchema: {
|
|
844
|
+
name: import_zod6.z.string().min(1),
|
|
845
|
+
fields: import_zod6.z.array(fieldInputSchema).optional(),
|
|
846
|
+
label: import_zod6.z.string().optional(),
|
|
847
|
+
note: import_zod6.z.string().optional()
|
|
848
|
+
}
|
|
849
|
+
},
|
|
850
|
+
async (input) => {
|
|
851
|
+
try {
|
|
852
|
+
const data = await client.post("/collections/diff", input);
|
|
853
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
854
|
+
} catch (err) {
|
|
855
|
+
return { content: [{ type: "text", text: `Error: ${formatError2(err)}` }], isError: true };
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
);
|
|
859
|
+
server.registerTool(
|
|
860
|
+
"apply_schema",
|
|
861
|
+
{
|
|
862
|
+
description: "Atomically apply a schema migration to a collection (add/update/remove fields and relations). Call diff_schema first to preview changes. Pass confirmRiskyChange=true on field inputs that have risky changes.",
|
|
863
|
+
inputSchema: {
|
|
864
|
+
name: import_zod6.z.string().min(1),
|
|
865
|
+
fields: import_zod6.z.array(
|
|
866
|
+
fieldInputSchema.extend({
|
|
867
|
+
renameFrom: import_zod6.z.string().optional(),
|
|
868
|
+
confirmRiskyChange: import_zod6.z.boolean().optional()
|
|
869
|
+
})
|
|
870
|
+
).optional(),
|
|
871
|
+
label: import_zod6.z.string().optional(),
|
|
872
|
+
note: import_zod6.z.string().optional(),
|
|
873
|
+
accountability: import_zod6.z.enum(["all", "activity", "none"]).optional(),
|
|
874
|
+
versioning: import_zod6.z.boolean().optional()
|
|
875
|
+
}
|
|
876
|
+
},
|
|
877
|
+
async (input) => {
|
|
878
|
+
try {
|
|
879
|
+
const { name, ...rest } = input;
|
|
880
|
+
const data = await client.put(`/collections/${name}/schema`, rest);
|
|
881
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
882
|
+
} catch (err) {
|
|
883
|
+
return { content: [{ type: "text", text: `Error: ${formatError2(err)}` }], isError: true };
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
// src/tools/content-config.ts
|
|
890
|
+
var import_zod7 = require("zod");
|
|
891
|
+
var presetSchema = import_zod7.z.object({
|
|
892
|
+
bookmark: import_zod7.z.string().nullable().optional(),
|
|
893
|
+
collection: import_zod7.z.string(),
|
|
894
|
+
userId: import_zod7.z.string().nullable().optional(),
|
|
895
|
+
roleId: import_zod7.z.string().nullable().optional(),
|
|
896
|
+
layout: import_zod7.z.string().optional(),
|
|
897
|
+
layoutQuery: import_zod7.z.record(import_zod7.z.unknown()).optional(),
|
|
898
|
+
layoutOptions: import_zod7.z.record(import_zod7.z.unknown()).optional(),
|
|
899
|
+
search: import_zod7.z.string().nullable().optional(),
|
|
900
|
+
filter: import_zod7.z.record(import_zod7.z.unknown()).optional(),
|
|
901
|
+
icon: import_zod7.z.string().nullable().optional(),
|
|
902
|
+
color: import_zod7.z.string().nullable().optional(),
|
|
903
|
+
refreshInterval: import_zod7.z.number().int().min(0).optional()
|
|
904
|
+
});
|
|
905
|
+
var translationSchema = import_zod7.z.object({
|
|
906
|
+
language: import_zod7.z.string(),
|
|
907
|
+
namespace: import_zod7.z.string(),
|
|
908
|
+
key: import_zod7.z.string(),
|
|
909
|
+
value: import_zod7.z.string(),
|
|
910
|
+
status: import_zod7.z.string().optional()
|
|
911
|
+
});
|
|
912
|
+
function registerContentConfigTools(server, client) {
|
|
913
|
+
registerCrud(server, client, {
|
|
914
|
+
basePath: "/presets",
|
|
915
|
+
resource: "preset",
|
|
916
|
+
namePrefix: "preset",
|
|
917
|
+
listQuery: { collection: import_zod7.z.string().optional() },
|
|
918
|
+
createSchema: presetSchema.shape,
|
|
919
|
+
updateSchema: presetSchema.partial().shape
|
|
920
|
+
});
|
|
921
|
+
registerCrud(server, client, {
|
|
922
|
+
basePath: "/translations",
|
|
923
|
+
resource: "translation",
|
|
924
|
+
namePrefix: "translation",
|
|
925
|
+
listQuery: {
|
|
926
|
+
namespace: import_zod7.z.string().optional(),
|
|
927
|
+
language: import_zod7.z.string().optional()
|
|
928
|
+
},
|
|
929
|
+
createSchema: translationSchema.shape,
|
|
930
|
+
updateSchema: translationSchema.partial().shape
|
|
931
|
+
});
|
|
932
|
+
server.registerTool(
|
|
933
|
+
"list_settings",
|
|
934
|
+
{
|
|
935
|
+
description: "List site settings, optionally filtered by scope.",
|
|
936
|
+
inputSchema: { scope: import_zod7.z.string().optional() }
|
|
937
|
+
},
|
|
938
|
+
async ({ scope }) => run(() => client.get(`/settings${scope ? `?scope=${encodeURIComponent(scope)}` : ""}`))
|
|
939
|
+
);
|
|
940
|
+
server.registerTool(
|
|
941
|
+
"get_setting",
|
|
942
|
+
{
|
|
943
|
+
description: "Get a single setting by key.",
|
|
944
|
+
inputSchema: { key: import_zod7.z.string().min(1) }
|
|
945
|
+
},
|
|
946
|
+
async ({ key }) => run(() => client.get(`/settings/${encodeURIComponent(key)}`))
|
|
947
|
+
);
|
|
948
|
+
server.registerTool(
|
|
949
|
+
"upsert_setting",
|
|
950
|
+
{
|
|
951
|
+
description: "Create or update a setting (upsert by key).",
|
|
952
|
+
inputSchema: {
|
|
953
|
+
key: import_zod7.z.string().min(1),
|
|
954
|
+
value: import_zod7.z.record(import_zod7.z.unknown()).describe("Arbitrary JSON value object for the setting."),
|
|
955
|
+
scope: import_zod7.z.string().optional()
|
|
956
|
+
}
|
|
957
|
+
},
|
|
958
|
+
async (input) => run(() => client.post("/settings", input))
|
|
959
|
+
);
|
|
960
|
+
server.registerTool(
|
|
961
|
+
"delete_setting",
|
|
962
|
+
{
|
|
963
|
+
description: "Delete a setting by key. DESTRUCTIVE \u2014 warn the user first and pass confirm=true.",
|
|
964
|
+
inputSchema: {
|
|
965
|
+
key: import_zod7.z.string().min(1),
|
|
966
|
+
confirm: import_zod7.z.literal(true).describe(confirmDescription)
|
|
967
|
+
}
|
|
968
|
+
},
|
|
969
|
+
async ({ key }) => run(async () => {
|
|
970
|
+
await client.delete(`/settings/${encodeURIComponent(key)}`);
|
|
971
|
+
return okText(`Setting "${key}" deleted.`);
|
|
972
|
+
})
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
// src/tools/extensions.ts
|
|
977
|
+
var import_zod8 = require("zod");
|
|
978
|
+
var EXTENSION_TYPES = ["interface", "display", "layout", "panel", "module", "hook", "endpoint"];
|
|
979
|
+
var extensionSchema = import_zod8.z.object({
|
|
980
|
+
key: import_zod8.z.string().regex(/^[a-z0-9_:-]+$/).optional(),
|
|
981
|
+
name: import_zod8.z.string().min(1),
|
|
982
|
+
version: import_zod8.z.string().min(1),
|
|
983
|
+
type: import_zod8.z.enum(EXTENSION_TYPES),
|
|
984
|
+
enabled: import_zod8.z.boolean().optional(),
|
|
985
|
+
bundleUrl: import_zod8.z.string().min(1).describe("https:, http:, or data:text/javascript bundle URL."),
|
|
986
|
+
manifest: import_zod8.z.record(import_zod8.z.string()).optional(),
|
|
987
|
+
capabilities: import_zod8.z.array(import_zod8.z.string()).optional()
|
|
988
|
+
});
|
|
989
|
+
function registerExtensionTools(server, client) {
|
|
990
|
+
server.registerTool(
|
|
991
|
+
"list_extensions",
|
|
992
|
+
{ description: "List extensions installed on the active site.", inputSchema: {} },
|
|
993
|
+
async () => run(() => client.get("/extensions"))
|
|
994
|
+
);
|
|
995
|
+
server.registerTool(
|
|
996
|
+
"install_extension",
|
|
997
|
+
{
|
|
998
|
+
description: "Install (register) an extension on the active site from a bundle URL.",
|
|
999
|
+
inputSchema: extensionSchema.shape
|
|
1000
|
+
},
|
|
1001
|
+
async (input) => run(() => client.post("/extensions", input))
|
|
1002
|
+
);
|
|
1003
|
+
server.registerTool(
|
|
1004
|
+
"update_extension",
|
|
1005
|
+
{
|
|
1006
|
+
description: "Update an installed extension (enable/disable, version, config). Partial PATCH.",
|
|
1007
|
+
inputSchema: { id: import_zod8.z.string().min(1), ...extensionSchema.partial().shape }
|
|
1008
|
+
},
|
|
1009
|
+
async ({ id, ...patch }) => run(() => client.patch(`/extensions/${id}`, patch))
|
|
1010
|
+
);
|
|
1011
|
+
server.registerTool(
|
|
1012
|
+
"uninstall_extension",
|
|
1013
|
+
{
|
|
1014
|
+
description: "Uninstall an extension from the site. DESTRUCTIVE \u2014 pass confirm=true.",
|
|
1015
|
+
inputSchema: { id: import_zod8.z.string().min(1), confirm: import_zod8.z.literal(true).describe(confirmDescription) }
|
|
1016
|
+
},
|
|
1017
|
+
async ({ id }) => run(async () => {
|
|
1018
|
+
await client.delete(`/extensions/${id}`);
|
|
1019
|
+
return okText(`Extension "${id}" uninstalled.`);
|
|
1020
|
+
})
|
|
1021
|
+
);
|
|
1022
|
+
server.registerTool(
|
|
1023
|
+
"list_marketplace_extensions",
|
|
1024
|
+
{
|
|
1025
|
+
description: "Browse the published extension marketplace.",
|
|
1026
|
+
inputSchema: {
|
|
1027
|
+
q: import_zod8.z.string().optional(),
|
|
1028
|
+
category: import_zod8.z.string().optional(),
|
|
1029
|
+
tags: import_zod8.z.string().optional().describe("Comma-separated tags."),
|
|
1030
|
+
sort: import_zod8.z.string().optional(),
|
|
1031
|
+
page: import_zod8.z.number().int().min(1).optional(),
|
|
1032
|
+
perPage: import_zod8.z.number().int().min(1).optional()
|
|
1033
|
+
}
|
|
1034
|
+
},
|
|
1035
|
+
async (args) => run(
|
|
1036
|
+
() => client.get(
|
|
1037
|
+
`/marketplace/extensions${buildQs(args)}`
|
|
1038
|
+
)
|
|
1039
|
+
)
|
|
1040
|
+
);
|
|
1041
|
+
server.registerTool(
|
|
1042
|
+
"get_marketplace_extension",
|
|
1043
|
+
{
|
|
1044
|
+
description: "Get a single marketplace extension by slug.",
|
|
1045
|
+
inputSchema: { slug: import_zod8.z.string().min(1) }
|
|
1046
|
+
},
|
|
1047
|
+
async ({ slug }) => run(() => client.get(`/marketplace/extensions/${slug}`))
|
|
1048
|
+
);
|
|
1049
|
+
server.registerTool(
|
|
1050
|
+
"list_marketplace_updates",
|
|
1051
|
+
{ description: "List available updates for installed marketplace extensions.", inputSchema: {} },
|
|
1052
|
+
async () => run(() => client.get("/marketplace/updates"))
|
|
1053
|
+
);
|
|
1054
|
+
server.registerTool(
|
|
1055
|
+
"install_marketplace_extension",
|
|
1056
|
+
{
|
|
1057
|
+
description: "Install a published marketplace extension onto the active site by slug.",
|
|
1058
|
+
inputSchema: { slug: import_zod8.z.string().min(1) }
|
|
1059
|
+
},
|
|
1060
|
+
async ({ slug }) => run(() => client.post(`/marketplace/extensions/${slug}/install`, {}))
|
|
1061
|
+
);
|
|
1062
|
+
server.registerTool(
|
|
1063
|
+
"publish_extension",
|
|
1064
|
+
{
|
|
1065
|
+
description: "Publish an extension to the marketplace (signs + marks it published).",
|
|
1066
|
+
inputSchema: {
|
|
1067
|
+
extensionId: import_zod8.z.string().min(1),
|
|
1068
|
+
marketplaceSlug: import_zod8.z.string().min(1),
|
|
1069
|
+
publisher: import_zod8.z.record(import_zod8.z.unknown()).optional(),
|
|
1070
|
+
signature: import_zod8.z.string().optional(),
|
|
1071
|
+
signatureAlg: import_zod8.z.string().optional(),
|
|
1072
|
+
publisherKeyId: import_zod8.z.string().optional(),
|
|
1073
|
+
bundleSha256: import_zod8.z.string().optional()
|
|
1074
|
+
}
|
|
1075
|
+
},
|
|
1076
|
+
async (input) => run(() => client.post("/marketplace/publish", input))
|
|
1077
|
+
);
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// src/tools/fields.ts
|
|
1081
|
+
var import_zod9 = require("zod");
|
|
1082
|
+
var namePattern = /^[a-z][a-z0-9_]{0,62}$/;
|
|
1083
|
+
var fieldInputSchema2 = import_zod9.z.object({
|
|
1084
|
+
type: import_zod9.z.string().min(1).describe(
|
|
1085
|
+
"Storage type: string, text, integer, bigInteger, float, decimal, boolean, date, dateTime, time, json, uuid, csv, hash, alias"
|
|
1086
|
+
),
|
|
1087
|
+
interface: import_zod9.z.string().min(1).describe(
|
|
1088
|
+
"UI widget: input, textarea, select, toggle, datetime, file, image, repeater, relation-m2o, relation-o2m, relation-m2m, code, markdown, wysiwyg, \u2026"
|
|
1089
|
+
),
|
|
1090
|
+
display: import_zod9.z.string().optional(),
|
|
1091
|
+
label: import_zod9.z.string().optional(),
|
|
1092
|
+
note: import_zod9.z.string().optional(),
|
|
1093
|
+
defaultValue: import_zod9.z.unknown().optional(),
|
|
1094
|
+
nullable: import_zod9.z.boolean().optional().default(true),
|
|
1095
|
+
unique: import_zod9.z.boolean().optional().default(false),
|
|
1096
|
+
indexed: import_zod9.z.boolean().optional().default(false),
|
|
1097
|
+
searchable: import_zod9.z.boolean().optional().default(false),
|
|
1098
|
+
length: import_zod9.z.number().int().positive().optional(),
|
|
1099
|
+
precision: import_zod9.z.number().int().positive().optional(),
|
|
1100
|
+
scale: import_zod9.z.number().int().min(0).optional(),
|
|
1101
|
+
special: import_zod9.z.array(import_zod9.z.string()).optional(),
|
|
1102
|
+
options: import_zod9.z.record(import_zod9.z.unknown()).optional(),
|
|
1103
|
+
displayOptions: import_zod9.z.record(import_zod9.z.unknown()).optional(),
|
|
1104
|
+
conditions: import_zod9.z.array(import_zod9.z.unknown()).optional(),
|
|
1105
|
+
required: import_zod9.z.boolean().optional().default(false),
|
|
1106
|
+
readonly: import_zod9.z.boolean().optional().default(false),
|
|
1107
|
+
hidden: import_zod9.z.boolean().optional().default(false),
|
|
1108
|
+
encrypted: import_zod9.z.boolean().optional().default(false),
|
|
1109
|
+
versioned: import_zod9.z.boolean().optional().default(false),
|
|
1110
|
+
width: import_zod9.z.enum(["half", "full", "fill"]).optional().default("full"),
|
|
1111
|
+
group: import_zod9.z.string().optional(),
|
|
1112
|
+
sortOrder: import_zod9.z.number().int().optional(),
|
|
1113
|
+
renameFrom: import_zod9.z.string().regex(namePattern).optional().describe("Previous field name if this is a rename operation"),
|
|
1114
|
+
confirmRiskyChange: import_zod9.z.boolean().optional().describe("Set true to confirm type-change or destructive migration")
|
|
1115
|
+
});
|
|
1116
|
+
function formatError3(err) {
|
|
1117
|
+
if (err instanceof LumiBaseApiError) {
|
|
1118
|
+
return err.errors.map((e) => `[${e.code}] ${e.message}`).join("; ");
|
|
1119
|
+
}
|
|
1120
|
+
return String(err);
|
|
1121
|
+
}
|
|
1122
|
+
function registerFieldTools(server, client) {
|
|
1123
|
+
server.registerTool(
|
|
1124
|
+
"list_fields",
|
|
1125
|
+
{
|
|
1126
|
+
description: "List all fields in a collection, including system fields.",
|
|
1127
|
+
inputSchema: {
|
|
1128
|
+
collection: import_zod9.z.string().min(1)
|
|
1129
|
+
}
|
|
1130
|
+
},
|
|
1131
|
+
async ({ collection }) => {
|
|
1132
|
+
try {
|
|
1133
|
+
const data = await client.get(`/collections/${collection}/fields`);
|
|
1134
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
1135
|
+
} catch (err) {
|
|
1136
|
+
return { content: [{ type: "text", text: `Error: ${formatError3(err)}` }], isError: true };
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
);
|
|
1140
|
+
server.registerTool(
|
|
1141
|
+
"upsert_field",
|
|
1142
|
+
{
|
|
1143
|
+
description: 'Create or update a field in a collection. field_name must be lowercase snake_case (e.g. "published_at"). Common types: string (varchar), text (longtext), integer, boolean, dateTime, json, uuid. Common interfaces: input, textarea, datetime, toggle, select, file, markdown.',
|
|
1144
|
+
inputSchema: {
|
|
1145
|
+
collection: import_zod9.z.string().min(1),
|
|
1146
|
+
field_name: import_zod9.z.string().regex(namePattern, "Must be lowercase snake_case, start with a letter").describe("Machine name of the field"),
|
|
1147
|
+
...fieldInputSchema2.shape
|
|
1148
|
+
}
|
|
1149
|
+
},
|
|
1150
|
+
async ({ collection, field_name, ...fieldInput }) => {
|
|
1151
|
+
try {
|
|
1152
|
+
const data = await client.put(
|
|
1153
|
+
`/collections/${collection}/fields/${field_name}`,
|
|
1154
|
+
fieldInput
|
|
1155
|
+
);
|
|
1156
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
1157
|
+
} catch (err) {
|
|
1158
|
+
return { content: [{ type: "text", text: `Error: ${formatError3(err)}` }], isError: true };
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
);
|
|
1162
|
+
server.registerTool(
|
|
1163
|
+
"delete_field",
|
|
1164
|
+
{
|
|
1165
|
+
description: "Delete a field from a collection. Data stored in this field will be lost. Pass confirm=true to confirm the destructive operation.",
|
|
1166
|
+
inputSchema: {
|
|
1167
|
+
collection: import_zod9.z.string().min(1),
|
|
1168
|
+
field_name: import_zod9.z.string().min(1),
|
|
1169
|
+
confirm: import_zod9.z.literal(true).describe("Must be true to confirm destructive operation"),
|
|
1170
|
+
force: import_zod9.z.boolean().optional().describe("Force deletion even if risky (foreign keys, etc.)")
|
|
1171
|
+
}
|
|
1172
|
+
},
|
|
1173
|
+
async ({ collection, field_name, force }) => {
|
|
1174
|
+
try {
|
|
1175
|
+
const qs = force ? "?force=true" : "";
|
|
1176
|
+
await client.delete(`/collections/${collection}/fields/${field_name}${qs}`);
|
|
1177
|
+
return {
|
|
1178
|
+
content: [{ type: "text", text: `Field "${field_name}" deleted from "${collection}".` }]
|
|
1179
|
+
};
|
|
1180
|
+
} catch (err) {
|
|
1181
|
+
return { content: [{ type: "text", text: `Error: ${formatError3(err)}` }], isError: true };
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
// src/tools/items.ts
|
|
1188
|
+
var import_zod10 = require("zod");
|
|
1189
|
+
function formatError4(err) {
|
|
1190
|
+
if (err instanceof LumiBaseApiError) {
|
|
1191
|
+
return err.errors.map((e) => `[${e.code}] ${e.message}`).join("; ");
|
|
1192
|
+
}
|
|
1193
|
+
return String(err);
|
|
1194
|
+
}
|
|
1195
|
+
function buildQs2(params) {
|
|
1196
|
+
const q = new URLSearchParams();
|
|
1197
|
+
for (const [k, v] of Object.entries(params)) {
|
|
1198
|
+
if (v !== void 0) q.set(k, String(v));
|
|
1199
|
+
}
|
|
1200
|
+
const s = q.toString();
|
|
1201
|
+
return s ? `?${s}` : "";
|
|
1202
|
+
}
|
|
1203
|
+
function registerItemTools(server, client) {
|
|
1204
|
+
server.registerTool(
|
|
1205
|
+
"list_items",
|
|
1206
|
+
{
|
|
1207
|
+
description: "List items from a collection with optional filtering, sorting, and pagination.",
|
|
1208
|
+
inputSchema: {
|
|
1209
|
+
collection: import_zod10.z.string().min(1),
|
|
1210
|
+
limit: import_zod10.z.number().int().min(1).max(200).optional().default(25),
|
|
1211
|
+
offset: import_zod10.z.number().int().min(0).optional().default(0),
|
|
1212
|
+
status: import_zod10.z.enum(["draft", "published", "archived"]).optional(),
|
|
1213
|
+
sort: import_zod10.z.string().optional().describe('Comma-separated field names; prefix with - for descending (e.g. "-created_at")'),
|
|
1214
|
+
fields: import_zod10.z.string().optional().describe('Comma-separated field names to return (e.g. "id,title,status")'),
|
|
1215
|
+
search: import_zod10.z.string().optional().describe("Full-text search across searchable fields")
|
|
1216
|
+
}
|
|
1217
|
+
},
|
|
1218
|
+
async ({ collection, ...params }) => {
|
|
1219
|
+
try {
|
|
1220
|
+
const qs = buildQs2(params);
|
|
1221
|
+
const data = await client.get(`/items/${collection}${qs}`);
|
|
1222
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
1223
|
+
} catch (err) {
|
|
1224
|
+
return { content: [{ type: "text", text: `Error: ${formatError4(err)}` }], isError: true };
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
);
|
|
1228
|
+
server.registerTool(
|
|
1229
|
+
"get_item",
|
|
1230
|
+
{
|
|
1231
|
+
description: "Get a single item by ID from a collection.",
|
|
1232
|
+
inputSchema: {
|
|
1233
|
+
collection: import_zod10.z.string().min(1),
|
|
1234
|
+
id: import_zod10.z.string().min(1),
|
|
1235
|
+
fields: import_zod10.z.string().optional().describe("Comma-separated field names to return")
|
|
1236
|
+
}
|
|
1237
|
+
},
|
|
1238
|
+
async ({ collection, id, fields }) => {
|
|
1239
|
+
try {
|
|
1240
|
+
const qs = buildQs2({ fields });
|
|
1241
|
+
const data = await client.get(`/items/${collection}/${id}${qs}`);
|
|
1242
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
1243
|
+
} catch (err) {
|
|
1244
|
+
return { content: [{ type: "text", text: `Error: ${formatError4(err)}` }], isError: true };
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
);
|
|
1248
|
+
server.registerTool(
|
|
1249
|
+
"create_item",
|
|
1250
|
+
{
|
|
1251
|
+
description: "Create a new item in a collection.",
|
|
1252
|
+
inputSchema: {
|
|
1253
|
+
collection: import_zod10.z.string().min(1),
|
|
1254
|
+
data: import_zod10.z.record(import_zod10.z.unknown()).describe("Field values for the new item"),
|
|
1255
|
+
status: import_zod10.z.enum(["draft", "published"]).optional().default("draft")
|
|
1256
|
+
}
|
|
1257
|
+
},
|
|
1258
|
+
async ({ collection, data: itemData, status }) => {
|
|
1259
|
+
try {
|
|
1260
|
+
const data = await client.post(`/items/${collection}`, {
|
|
1261
|
+
...itemData,
|
|
1262
|
+
status
|
|
1263
|
+
});
|
|
1264
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
1265
|
+
} catch (err) {
|
|
1266
|
+
return { content: [{ type: "text", text: `Error: ${formatError4(err)}` }], isError: true };
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
);
|
|
1270
|
+
server.registerTool(
|
|
1271
|
+
"update_item",
|
|
1272
|
+
{
|
|
1273
|
+
description: "Partially update an item (PATCH \u2014 only provided fields are changed).",
|
|
1274
|
+
inputSchema: {
|
|
1275
|
+
collection: import_zod10.z.string().min(1),
|
|
1276
|
+
id: import_zod10.z.string().min(1),
|
|
1277
|
+
data: import_zod10.z.record(import_zod10.z.unknown()).describe("Fields to update")
|
|
1278
|
+
}
|
|
1279
|
+
},
|
|
1280
|
+
async ({ collection, id, data: itemData }) => {
|
|
1281
|
+
try {
|
|
1282
|
+
const data = await client.patch(`/items/${collection}/${id}`, itemData);
|
|
1283
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
1284
|
+
} catch (err) {
|
|
1285
|
+
return { content: [{ type: "text", text: `Error: ${formatError4(err)}` }], isError: true };
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
);
|
|
1289
|
+
server.registerTool(
|
|
1290
|
+
"delete_item",
|
|
1291
|
+
{
|
|
1292
|
+
description: "Soft-delete an item (sets deleted_at, recoverable). Pass confirm=true.",
|
|
1293
|
+
inputSchema: {
|
|
1294
|
+
collection: import_zod10.z.string().min(1),
|
|
1295
|
+
id: import_zod10.z.string().min(1),
|
|
1296
|
+
confirm: import_zod10.z.literal(true).describe("Must be true to confirm deletion")
|
|
1297
|
+
}
|
|
1298
|
+
},
|
|
1299
|
+
async ({ collection, id }) => {
|
|
1300
|
+
try {
|
|
1301
|
+
await client.delete(`/items/${collection}/${id}`);
|
|
1302
|
+
return { content: [{ type: "text", text: `Item "${id}" deleted from "${collection}".` }] };
|
|
1303
|
+
} catch (err) {
|
|
1304
|
+
return { content: [{ type: "text", text: `Error: ${formatError4(err)}` }], isError: true };
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// src/tools/ops.ts
|
|
1311
|
+
var import_zod11 = require("zod");
|
|
1312
|
+
function registerOpsTools(server, client) {
|
|
1313
|
+
server.registerTool(
|
|
1314
|
+
"list_activity",
|
|
1315
|
+
{
|
|
1316
|
+
description: "List the site activity / audit trail (most recent first).",
|
|
1317
|
+
inputSchema: {
|
|
1318
|
+
limit: import_zod11.z.number().int().min(1).max(500).optional(),
|
|
1319
|
+
offset: import_zod11.z.number().int().min(0).optional()
|
|
1320
|
+
}
|
|
1321
|
+
},
|
|
1322
|
+
async (args) => run(
|
|
1323
|
+
() => client.get(
|
|
1324
|
+
`/activity${buildQs(args)}`
|
|
1325
|
+
)
|
|
1326
|
+
)
|
|
1327
|
+
);
|
|
1328
|
+
server.registerTool(
|
|
1329
|
+
"get_health",
|
|
1330
|
+
{ description: "Check the CMS health endpoint.", inputSchema: {} },
|
|
1331
|
+
async () => run(async () => okText(await client.getRootText("/health")))
|
|
1332
|
+
);
|
|
1333
|
+
server.registerTool(
|
|
1334
|
+
"get_metrics",
|
|
1335
|
+
{ description: "Fetch Prometheus metrics exposition text from the CMS.", inputSchema: {} },
|
|
1336
|
+
async () => run(async () => okText(await client.getRootText("/metrics")))
|
|
1337
|
+
);
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
// src/tools/permissions.ts
|
|
1341
|
+
var import_zod12 = require("zod");
|
|
1342
|
+
function registerPermissionTools(server, client) {
|
|
1343
|
+
server.registerTool(
|
|
1344
|
+
"get_my_permissions",
|
|
1345
|
+
{
|
|
1346
|
+
description: "Get the compiled permission bundle for the authenticated principal.",
|
|
1347
|
+
inputSchema: {}
|
|
1348
|
+
},
|
|
1349
|
+
async () => run(() => client.get("/permissions/me"))
|
|
1350
|
+
);
|
|
1351
|
+
server.registerTool(
|
|
1352
|
+
"check_permission",
|
|
1353
|
+
{
|
|
1354
|
+
description: "Evaluate whether the current principal may perform an action on a collection (optionally against a specific item), returning { allowed, reason, fields }.",
|
|
1355
|
+
inputSchema: {
|
|
1356
|
+
collection: import_zod12.z.string().min(1),
|
|
1357
|
+
action: import_zod12.z.enum(["create", "read", "update", "delete", "share"]),
|
|
1358
|
+
item: import_zod12.z.record(import_zod12.z.unknown()).optional().describe("Item payload to evaluate row-level rules against.")
|
|
1359
|
+
}
|
|
1360
|
+
},
|
|
1361
|
+
async (input) => run(() => client.post("/permissions/check", input))
|
|
1362
|
+
);
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
// src/tools/relations.ts
|
|
1366
|
+
var import_zod13 = require("zod");
|
|
1367
|
+
var relationInputSchema = {
|
|
1368
|
+
manyCollection: import_zod13.z.string().min(1).describe('Collection that holds the foreign key (the "many" side).'),
|
|
1369
|
+
manyField: import_zod13.z.string().min(1).describe("Field on manyCollection that stores the relation."),
|
|
1370
|
+
oneCollection: import_zod13.z.string().min(1).describe('Related collection (the "one" side).'),
|
|
1371
|
+
oneField: import_zod13.z.string().nullable().optional(),
|
|
1372
|
+
junctionCollection: import_zod13.z.string().nullable().optional().describe("Junction table for m2m relations."),
|
|
1373
|
+
type: import_zod13.z.enum(["m2o", "o2m", "m2m", "m2a"]).optional(),
|
|
1374
|
+
aliasField: import_zod13.z.string().nullable().optional(),
|
|
1375
|
+
relatedDisplayTemplate: import_zod13.z.string().nullable().optional(),
|
|
1376
|
+
junctionManyField: import_zod13.z.string().nullable().optional(),
|
|
1377
|
+
junctionOneField: import_zod13.z.string().nullable().optional(),
|
|
1378
|
+
sortField: import_zod13.z.string().nullable().optional(),
|
|
1379
|
+
onDelete: import_zod13.z.enum(["restrict", "cascade", "set null", "no action"]).optional(),
|
|
1380
|
+
meta: import_zod13.z.record(import_zod13.z.unknown()).optional()
|
|
1381
|
+
};
|
|
1382
|
+
function registerRelationTools(server, client) {
|
|
1383
|
+
server.registerTool(
|
|
1384
|
+
"list_relations",
|
|
1385
|
+
{ description: "List all relations configured in the schema.", inputSchema: {} },
|
|
1386
|
+
async () => run(() => client.get("/relations"))
|
|
1387
|
+
);
|
|
1388
|
+
server.registerTool(
|
|
1389
|
+
"create_relation",
|
|
1390
|
+
{
|
|
1391
|
+
description: "Create a relation between two collections (m2o, o2m, m2m, or m2a). Schema-changing operation.",
|
|
1392
|
+
inputSchema: relationInputSchema
|
|
1393
|
+
},
|
|
1394
|
+
async (input) => run(() => client.post("/relations", input))
|
|
1395
|
+
);
|
|
1396
|
+
server.registerTool(
|
|
1397
|
+
"delete_relation",
|
|
1398
|
+
{
|
|
1399
|
+
description: "Delete a relation by id. DESTRUCTIVE \u2014 warn the user first and pass confirm=true.",
|
|
1400
|
+
inputSchema: {
|
|
1401
|
+
id: import_zod13.z.string().min(1),
|
|
1402
|
+
confirm: import_zod13.z.literal(true).describe(confirmDescription)
|
|
1403
|
+
}
|
|
1404
|
+
},
|
|
1405
|
+
async ({ id }) => run(async () => {
|
|
1406
|
+
await client.delete(`/relations/${id}`);
|
|
1407
|
+
return okText(`Relation "${id}" deleted.`);
|
|
1408
|
+
})
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
// src/tools/search-media.ts
|
|
1413
|
+
var import_zod14 = require("zod");
|
|
1414
|
+
function registerSearchMediaTools(server, client) {
|
|
1415
|
+
server.registerTool(
|
|
1416
|
+
"search",
|
|
1417
|
+
{
|
|
1418
|
+
description: "Full-text search within a collection. Returns ranked hits from the search backend. The `collection` parameter is required.",
|
|
1419
|
+
inputSchema: {
|
|
1420
|
+
q: import_zod14.z.string().min(1).describe("Query string."),
|
|
1421
|
+
collection: import_zod14.z.string().min(1).describe("Collection to search."),
|
|
1422
|
+
filter: import_zod14.z.string().optional().describe("Backend filter expression."),
|
|
1423
|
+
sort: import_zod14.z.string().optional().describe("Comma-separated sort fields."),
|
|
1424
|
+
limit: import_zod14.z.number().int().min(1).max(200).optional(),
|
|
1425
|
+
offset: import_zod14.z.number().int().min(0).optional()
|
|
1426
|
+
}
|
|
1427
|
+
},
|
|
1428
|
+
async (args) => run(
|
|
1429
|
+
() => client.get(
|
|
1430
|
+
`/search${buildQs(args)}`
|
|
1431
|
+
)
|
|
1432
|
+
)
|
|
1433
|
+
);
|
|
1434
|
+
server.registerTool(
|
|
1435
|
+
"list_media",
|
|
1436
|
+
{
|
|
1437
|
+
description: "List media asset keys, optionally filtered by key prefix.",
|
|
1438
|
+
inputSchema: { prefix: import_zod14.z.string().optional() }
|
|
1439
|
+
},
|
|
1440
|
+
async ({ prefix }) => run(() => client.get(`/media${prefix ? `?prefix=${encodeURIComponent(prefix)}` : ""}`))
|
|
1441
|
+
);
|
|
1442
|
+
server.registerTool(
|
|
1443
|
+
"delete_media",
|
|
1444
|
+
{
|
|
1445
|
+
description: "Delete a media asset by key. DESTRUCTIVE \u2014 warn the user first and pass confirm=true.",
|
|
1446
|
+
inputSchema: {
|
|
1447
|
+
key: import_zod14.z.string().min(1).describe("Full storage key of the asset."),
|
|
1448
|
+
confirm: import_zod14.z.literal(true).describe(confirmDescription)
|
|
1449
|
+
}
|
|
1450
|
+
},
|
|
1451
|
+
async ({ key }) => run(async () => {
|
|
1452
|
+
await client.delete(`/media/${key}`);
|
|
1453
|
+
return okText(`Media asset "${key}" deleted.`);
|
|
1454
|
+
})
|
|
1455
|
+
);
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
// src/tools/translation-memory.ts
|
|
1459
|
+
var import_zod15 = require("zod");
|
|
1460
|
+
function registerTranslationMemoryTools(server, client) {
|
|
1461
|
+
server.registerTool(
|
|
1462
|
+
"list_tm",
|
|
1463
|
+
{
|
|
1464
|
+
description: "List translation-memory entries, optionally filtered by source/target language.",
|
|
1465
|
+
inputSchema: {
|
|
1466
|
+
source: import_zod15.z.string().optional().describe("Source language code."),
|
|
1467
|
+
target: import_zod15.z.string().optional().describe("Target language code.")
|
|
1468
|
+
}
|
|
1469
|
+
},
|
|
1470
|
+
async (args) => run(
|
|
1471
|
+
() => client.get(`/tm${buildQs(args)}`)
|
|
1472
|
+
)
|
|
1473
|
+
);
|
|
1474
|
+
server.registerTool(
|
|
1475
|
+
"upsert_tm",
|
|
1476
|
+
{
|
|
1477
|
+
description: "Add or update a translation-memory entry.",
|
|
1478
|
+
inputSchema: {
|
|
1479
|
+
sourceLang: import_zod15.z.string().min(2),
|
|
1480
|
+
targetLang: import_zod15.z.string().min(2),
|
|
1481
|
+
sourceText: import_zod15.z.string().min(1),
|
|
1482
|
+
targetText: import_zod15.z.string().min(1),
|
|
1483
|
+
context: import_zod15.z.string().optional(),
|
|
1484
|
+
quality: import_zod15.z.number().min(0).max(100).optional(),
|
|
1485
|
+
source: import_zod15.z.enum(["human", "mt", "imported"]).optional(),
|
|
1486
|
+
provider: import_zod15.z.string().optional()
|
|
1487
|
+
}
|
|
1488
|
+
},
|
|
1489
|
+
async (input) => run(() => client.post("/tm", input))
|
|
1490
|
+
);
|
|
1491
|
+
server.registerTool(
|
|
1492
|
+
"lookup_tm",
|
|
1493
|
+
{
|
|
1494
|
+
description: "Fuzzy-match a query string against translation memory for a language pair.",
|
|
1495
|
+
inputSchema: {
|
|
1496
|
+
query: import_zod15.z.string().min(1),
|
|
1497
|
+
sourceLang: import_zod15.z.string().min(2),
|
|
1498
|
+
targetLang: import_zod15.z.string().min(2),
|
|
1499
|
+
threshold: import_zod15.z.number().min(0).max(100).optional().describe("Minimum match score (default 75).")
|
|
1500
|
+
}
|
|
1501
|
+
},
|
|
1502
|
+
async (input) => run(() => client.post("/tm/lookup", input))
|
|
1503
|
+
);
|
|
1504
|
+
server.registerTool(
|
|
1505
|
+
"translate_text",
|
|
1506
|
+
{
|
|
1507
|
+
description: "Run the full translation pipeline (TM + glossary + MT provider) for a text.",
|
|
1508
|
+
inputSchema: {
|
|
1509
|
+
text: import_zod15.z.string().min(1),
|
|
1510
|
+
from: import_zod15.z.string().min(2),
|
|
1511
|
+
to: import_zod15.z.string().min(2),
|
|
1512
|
+
provider: import_zod15.z.string().optional()
|
|
1513
|
+
}
|
|
1514
|
+
},
|
|
1515
|
+
async (input) => run(() => client.post("/tm/translate", input))
|
|
1516
|
+
);
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
// src/tools/users-teams.ts
|
|
1520
|
+
var import_zod16 = require("zod");
|
|
1521
|
+
function registerUsersTeamsTools(server, client) {
|
|
1522
|
+
server.registerTool(
|
|
1523
|
+
"list_users",
|
|
1524
|
+
{ description: "List users belonging to the active site.", inputSchema: {} },
|
|
1525
|
+
async () => run(() => client.get("/users"))
|
|
1526
|
+
);
|
|
1527
|
+
server.registerTool(
|
|
1528
|
+
"get_user",
|
|
1529
|
+
{ description: "Get a single user in the active site by id.", inputSchema: { id: import_zod16.z.string().min(1) } },
|
|
1530
|
+
async ({ id }) => run(() => client.get(`/users/${id}`))
|
|
1531
|
+
);
|
|
1532
|
+
server.registerTool(
|
|
1533
|
+
"invite_user",
|
|
1534
|
+
{
|
|
1535
|
+
description: "Invite a user to the site by email, optionally assigning a role. Sends an invite email.",
|
|
1536
|
+
inputSchema: {
|
|
1537
|
+
email: import_zod16.z.string().email(),
|
|
1538
|
+
roleId: import_zod16.z.string().optional()
|
|
1539
|
+
}
|
|
1540
|
+
},
|
|
1541
|
+
async (input) => run(() => client.post("/users/invite", input))
|
|
1542
|
+
);
|
|
1543
|
+
server.registerTool(
|
|
1544
|
+
"update_user",
|
|
1545
|
+
{
|
|
1546
|
+
description: "Update a user's site membership (role and/or status).",
|
|
1547
|
+
inputSchema: {
|
|
1548
|
+
id: import_zod16.z.string().min(1),
|
|
1549
|
+
roleId: import_zod16.z.string().nullable().optional(),
|
|
1550
|
+
status: import_zod16.z.string().optional().describe("e.g. active, suspended.")
|
|
1551
|
+
}
|
|
1552
|
+
},
|
|
1553
|
+
async ({ id, ...patch }) => run(() => client.patch(`/users/${id}`, patch))
|
|
1554
|
+
);
|
|
1555
|
+
server.registerTool(
|
|
1556
|
+
"remove_user",
|
|
1557
|
+
{
|
|
1558
|
+
description: "Remove a user from the site. DESTRUCTIVE \u2014 pass confirm=true.",
|
|
1559
|
+
inputSchema: { id: import_zod16.z.string().min(1), confirm: import_zod16.z.literal(true).describe(confirmDescription) }
|
|
1560
|
+
},
|
|
1561
|
+
async ({ id }) => run(async () => {
|
|
1562
|
+
await client.delete(`/users/${id}`);
|
|
1563
|
+
return okText(`User "${id}" removed from the site.`);
|
|
1564
|
+
})
|
|
1565
|
+
);
|
|
1566
|
+
server.registerTool(
|
|
1567
|
+
"list_teams",
|
|
1568
|
+
{ description: "List teams in the active site.", inputSchema: {} },
|
|
1569
|
+
async () => run(() => client.get("/teams"))
|
|
1570
|
+
);
|
|
1571
|
+
server.registerTool(
|
|
1572
|
+
"get_team",
|
|
1573
|
+
{ description: "Get a single team by id.", inputSchema: { id: import_zod16.z.string().min(1) } },
|
|
1574
|
+
async ({ id }) => run(() => client.get(`/teams/${id}`))
|
|
1575
|
+
);
|
|
1576
|
+
server.registerTool(
|
|
1577
|
+
"create_team",
|
|
1578
|
+
{
|
|
1579
|
+
description: "Create a team.",
|
|
1580
|
+
inputSchema: { name: import_zod16.z.string().min(1).max(128), description: import_zod16.z.string().nullable().optional() }
|
|
1581
|
+
},
|
|
1582
|
+
async (input) => run(() => client.post("/teams", input))
|
|
1583
|
+
);
|
|
1584
|
+
server.registerTool(
|
|
1585
|
+
"update_team",
|
|
1586
|
+
{
|
|
1587
|
+
description: "Update a team (partial PATCH).",
|
|
1588
|
+
inputSchema: {
|
|
1589
|
+
id: import_zod16.z.string().min(1),
|
|
1590
|
+
name: import_zod16.z.string().min(1).max(128).optional(),
|
|
1591
|
+
description: import_zod16.z.string().nullable().optional()
|
|
1592
|
+
}
|
|
1593
|
+
},
|
|
1594
|
+
async ({ id, ...patch }) => run(() => client.patch(`/teams/${id}`, patch))
|
|
1595
|
+
);
|
|
1596
|
+
server.registerTool(
|
|
1597
|
+
"delete_team",
|
|
1598
|
+
{
|
|
1599
|
+
description: "Delete a team. DESTRUCTIVE \u2014 pass confirm=true.",
|
|
1600
|
+
inputSchema: { id: import_zod16.z.string().min(1), confirm: import_zod16.z.literal(true).describe(confirmDescription) }
|
|
1601
|
+
},
|
|
1602
|
+
async ({ id }) => run(async () => {
|
|
1603
|
+
await client.delete(`/teams/${id}`);
|
|
1604
|
+
return okText(`Team "${id}" deleted.`);
|
|
1605
|
+
})
|
|
1606
|
+
);
|
|
1607
|
+
server.registerTool(
|
|
1608
|
+
"list_team_members",
|
|
1609
|
+
{ description: "List members of a team.", inputSchema: { id: import_zod16.z.string().min(1).describe("Team id.") } },
|
|
1610
|
+
async ({ id }) => run(() => client.get(`/teams/${id}/members`))
|
|
1611
|
+
);
|
|
1612
|
+
server.registerTool(
|
|
1613
|
+
"add_team_member",
|
|
1614
|
+
{
|
|
1615
|
+
description: "Add a user to a team.",
|
|
1616
|
+
inputSchema: { id: import_zod16.z.string().min(1).describe("Team id."), userId: import_zod16.z.string().min(1) }
|
|
1617
|
+
},
|
|
1618
|
+
async ({ id, userId }) => run(() => client.post(`/teams/${id}/members`, { userId }))
|
|
1619
|
+
);
|
|
1620
|
+
server.registerTool(
|
|
1621
|
+
"remove_team_member",
|
|
1622
|
+
{
|
|
1623
|
+
description: "Remove a user from a team. DESTRUCTIVE \u2014 pass confirm=true.",
|
|
1624
|
+
inputSchema: {
|
|
1625
|
+
id: import_zod16.z.string().min(1).describe("Team id."),
|
|
1626
|
+
userId: import_zod16.z.string().min(1),
|
|
1627
|
+
confirm: import_zod16.z.literal(true).describe(confirmDescription)
|
|
1628
|
+
}
|
|
1629
|
+
},
|
|
1630
|
+
async ({ id, userId }) => run(async () => {
|
|
1631
|
+
await client.delete(`/teams/${id}/members/${userId}`);
|
|
1632
|
+
return okText(`User "${userId}" removed from team "${id}".`);
|
|
1633
|
+
})
|
|
1634
|
+
);
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
// src/tools/webhooks.ts
|
|
1638
|
+
var import_zod17 = require("zod");
|
|
1639
|
+
var webhookSchema = import_zod17.z.object({
|
|
1640
|
+
name: import_zod17.z.string().min(1).max(255),
|
|
1641
|
+
url: import_zod17.z.string().url(),
|
|
1642
|
+
actions: import_zod17.z.array(import_zod17.z.string()).optional().describe("Item events that trigger the webhook (e.g. create, update, delete)."),
|
|
1643
|
+
collections: import_zod17.z.array(import_zod17.z.string()).optional().describe("Collections to filter on (empty = all)."),
|
|
1644
|
+
headers: import_zod17.z.record(import_zod17.z.string()).optional(),
|
|
1645
|
+
status: import_zod17.z.enum(["active", "inactive"]).optional(),
|
|
1646
|
+
secret: import_zod17.z.string().nullable().optional()
|
|
1647
|
+
});
|
|
1648
|
+
function registerWebhookTools(server, client) {
|
|
1649
|
+
registerCrud(server, client, {
|
|
1650
|
+
basePath: "/webhooks",
|
|
1651
|
+
resource: "webhook",
|
|
1652
|
+
namePrefix: "webhook",
|
|
1653
|
+
createSchema: webhookSchema.shape,
|
|
1654
|
+
updateSchema: webhookSchema.partial().shape,
|
|
1655
|
+
// The webhooks route has no GET /:id; list returns full rows.
|
|
1656
|
+
enableGet: false
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
// src/tools/index.ts
|
|
1661
|
+
function registerAllTools(server, client) {
|
|
1662
|
+
registerCollectionTools(server, client);
|
|
1663
|
+
registerFieldTools(server, client);
|
|
1664
|
+
registerItemTools(server, client);
|
|
1665
|
+
registerRelationTools(server, client);
|
|
1666
|
+
registerContentConfigTools(server, client);
|
|
1667
|
+
registerSearchMediaTools(server, client);
|
|
1668
|
+
registerTranslationMemoryTools(server, client);
|
|
1669
|
+
registerPermissionTools(server, client);
|
|
1670
|
+
registerAccessTools(server, client);
|
|
1671
|
+
registerApiKeyTools(server, client);
|
|
1672
|
+
registerUsersTeamsTools(server, client);
|
|
1673
|
+
registerWebhookTools(server, client);
|
|
1674
|
+
registerAgentTools(server, client);
|
|
1675
|
+
registerOpsTools(server, client);
|
|
1676
|
+
registerAdminTools(server, client);
|
|
1677
|
+
registerExtensionTools(server, client);
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
// src/index.ts
|
|
1681
|
+
async function main() {
|
|
1682
|
+
const config = configFromEnv();
|
|
1683
|
+
const client = new LumiBaseClient(config);
|
|
1684
|
+
const server = new import_mcp.McpServer({
|
|
1685
|
+
name: "lumibase",
|
|
1686
|
+
version: "0.9.0"
|
|
1687
|
+
});
|
|
1688
|
+
registerAllTools(server, client);
|
|
1689
|
+
const transport = new import_stdio.StdioServerTransport();
|
|
1690
|
+
await server.connect(transport);
|
|
1691
|
+
}
|
|
1692
|
+
main().catch((err) => {
|
|
1693
|
+
console.error("[lumibase-mcp] Fatal:", err);
|
|
1694
|
+
process.exit(1);
|
|
1695
|
+
});
|