@openfairygui/mcp 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +519 -106
- package/dist/index.d.mts +520 -107
- package/dist/index.mjs +1 -1
- package/dist/{stdio-48jCJzS3.mjs → stdio-HOHWH0x4.mjs} +460 -122
- package/dist/{stdio-9ewjcCag.cjs → stdio-N6Yxacus.cjs} +482 -121
- package/dist/stdio.cjs +1 -1
- package/dist/stdio.mjs +1 -1
- package/package.json +7 -4
- package/src/server.ts +5 -1
- package/src/stdio.ts +6 -1
- package/src/tool-definitions.ts +105 -10
- package/src/tool-handler.ts +52 -10
|
@@ -1,8 +1,33 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
//#endregion
|
|
1
23
|
let _modelcontextprotocol_sdk_server_mcp_js = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
2
24
|
let _openfairygui_backend_node = require("@openfairygui/backend/node");
|
|
3
25
|
let node_module = require("node:module");
|
|
26
|
+
let _openfairygui_backend = require("@openfairygui/backend");
|
|
4
27
|
let zod = require("zod");
|
|
5
28
|
let _modelcontextprotocol_sdk_server_stdio_js = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
29
|
+
let node_path = require("node:path");
|
|
30
|
+
node_path = __toESM(node_path);
|
|
6
31
|
let node_url = require("node:url");
|
|
7
32
|
//#region src/prompt-definitions.ts
|
|
8
33
|
const OPENFAIRYGUI_BACKEND_PROMPT_NAMES = [
|
|
@@ -144,114 +169,6 @@ function registerOpenFairyGuiBackendResources(server, runtime) {
|
|
|
144
169
|
})));
|
|
145
170
|
}
|
|
146
171
|
//#endregion
|
|
147
|
-
//#region src/tool-handler.ts
|
|
148
|
-
function jsonResult(payload, isError = false) {
|
|
149
|
-
return {
|
|
150
|
-
content: [{
|
|
151
|
-
type: "text",
|
|
152
|
-
text: JSON.stringify(payload, null, 2)
|
|
153
|
-
}],
|
|
154
|
-
structuredContent: { backendResult: payload },
|
|
155
|
-
isError
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
function isBackendFailure(value) {
|
|
159
|
-
return typeof value === "object" && value !== null && "ok" in value && value.ok === false;
|
|
160
|
-
}
|
|
161
|
-
async function callOpenFairyGuiBackendTool(runtime, name, input) {
|
|
162
|
-
let result;
|
|
163
|
-
switch (name) {
|
|
164
|
-
case "openfairygui_backend_get_capabilities":
|
|
165
|
-
result = runtime.getCapabilities();
|
|
166
|
-
break;
|
|
167
|
-
case "openfairygui_backend_open_session":
|
|
168
|
-
result = await runtime.openSession({ projectPath: String(input.projectPath) });
|
|
169
|
-
break;
|
|
170
|
-
case "openfairygui_backend_open_project_session":
|
|
171
|
-
result = runtime.openProjectSession({
|
|
172
|
-
project: input.project,
|
|
173
|
-
sessionId: input.sessionId === void 0 ? void 0 : String(input.sessionId),
|
|
174
|
-
canonicalProjectPath: input.canonicalProjectPath === void 0 ? void 0 : String(input.canonicalProjectPath),
|
|
175
|
-
canonicalPathKey: input.canonicalPathKey === void 0 ? void 0 : String(input.canonicalPathKey)
|
|
176
|
-
});
|
|
177
|
-
break;
|
|
178
|
-
case "openfairygui_backend_get_session":
|
|
179
|
-
result = runtime.getSession({ sessionId: String(input.sessionId) });
|
|
180
|
-
break;
|
|
181
|
-
case "openfairygui_backend_get_project_outline":
|
|
182
|
-
result = runtime.getProjectOutline({ sessionId: String(input.sessionId) });
|
|
183
|
-
break;
|
|
184
|
-
case "openfairygui_backend_validate_session":
|
|
185
|
-
result = runtime.validateSession({ sessionId: String(input.sessionId) });
|
|
186
|
-
break;
|
|
187
|
-
case "openfairygui_backend_apply_transaction":
|
|
188
|
-
result = await runtime.applyTransaction({
|
|
189
|
-
sessionId: String(input.sessionId),
|
|
190
|
-
expectedRevision: Number(input.expectedRevision),
|
|
191
|
-
operations: input.operations
|
|
192
|
-
});
|
|
193
|
-
break;
|
|
194
|
-
case "openfairygui_backend_save_session":
|
|
195
|
-
result = await runtime.saveSession({
|
|
196
|
-
sessionId: String(input.sessionId),
|
|
197
|
-
expectedRevision: input.expectedRevision === void 0 ? void 0 : Number(input.expectedRevision),
|
|
198
|
-
targetPath: input.targetPath === void 0 ? void 0 : String(input.targetPath),
|
|
199
|
-
force: input.force === void 0 ? void 0 : Boolean(input.force),
|
|
200
|
-
mode: input.mode
|
|
201
|
-
});
|
|
202
|
-
break;
|
|
203
|
-
case "openfairygui_backend_materialize_session":
|
|
204
|
-
result = await runtime.materializeSession({
|
|
205
|
-
sessionId: String(input.sessionId),
|
|
206
|
-
expectedRevision: input.expectedRevision === void 0 ? void 0 : Number(input.expectedRevision),
|
|
207
|
-
mode: input.mode,
|
|
208
|
-
reason: input.reason === void 0 ? void 0 : String(input.reason)
|
|
209
|
-
});
|
|
210
|
-
break;
|
|
211
|
-
case "openfairygui_backend_close_session":
|
|
212
|
-
result = await runtime.closeSession({ sessionId: String(input.sessionId) });
|
|
213
|
-
break;
|
|
214
|
-
case "openfairygui_backend_get_events":
|
|
215
|
-
result = runtime.getEvents({
|
|
216
|
-
sessionId: String(input.sessionId),
|
|
217
|
-
after: input.after === void 0 ? void 0 : String(input.after),
|
|
218
|
-
limit: input.limit === void 0 ? void 0 : Number(input.limit)
|
|
219
|
-
});
|
|
220
|
-
break;
|
|
221
|
-
case "openfairygui_backend_get_job":
|
|
222
|
-
result = runtime.getJob({
|
|
223
|
-
sessionId: String(input.sessionId),
|
|
224
|
-
jobId: String(input.jobId)
|
|
225
|
-
});
|
|
226
|
-
break;
|
|
227
|
-
case "openfairygui_backend_list_jobs":
|
|
228
|
-
result = runtime.listJobs({
|
|
229
|
-
sessionId: String(input.sessionId),
|
|
230
|
-
status: input.status,
|
|
231
|
-
kind: input.kind,
|
|
232
|
-
limit: input.limit === void 0 ? void 0 : Number(input.limit)
|
|
233
|
-
});
|
|
234
|
-
break;
|
|
235
|
-
case "openfairygui_backend_cancel_job":
|
|
236
|
-
result = runtime.cancelJob({
|
|
237
|
-
sessionId: String(input.sessionId),
|
|
238
|
-
jobId: String(input.jobId)
|
|
239
|
-
});
|
|
240
|
-
break;
|
|
241
|
-
case "openfairygui_backend_get_cache_snapshot":
|
|
242
|
-
result = runtime.getCacheSnapshot({ sessionId: String(input.sessionId) });
|
|
243
|
-
break;
|
|
244
|
-
case "openfairygui_backend_refresh_cache":
|
|
245
|
-
result = runtime.refreshCache({
|
|
246
|
-
sessionId: String(input.sessionId),
|
|
247
|
-
reason: input.reason
|
|
248
|
-
});
|
|
249
|
-
break;
|
|
250
|
-
default: throw new Error(`Unknown OpenFairyGUI backend MCP tool: ${name}`);
|
|
251
|
-
}
|
|
252
|
-
return jsonResult(result, isBackendFailure(result));
|
|
253
|
-
}
|
|
254
|
-
//#endregion
|
|
255
172
|
//#region src/tool-definitions.ts
|
|
256
173
|
const OPENFAIRYGUI_BACKEND_TOOL_PREFIX = "openfairygui_backend_";
|
|
257
174
|
const OPENFAIRYGUI_BACKEND_TOOL_NAMES = [
|
|
@@ -276,12 +193,316 @@ const sessionId = zod.z.string().min(1);
|
|
|
276
193
|
const jobId = zod.z.string().min(1);
|
|
277
194
|
const expectedRevision = zod.z.number().int().nonnegative();
|
|
278
195
|
const limit = zod.z.number().int().nonnegative().optional();
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
196
|
+
const identifier = zod.z.string().min(1).max(256);
|
|
197
|
+
function isOpenFairyGuiMcpPayloadWithinBudget(root) {
|
|
198
|
+
const pending = [{
|
|
199
|
+
value: root,
|
|
200
|
+
depth: 0
|
|
201
|
+
}];
|
|
202
|
+
let nodes = 0;
|
|
203
|
+
while (pending.length > 0) {
|
|
204
|
+
const { value, depth } = pending.pop();
|
|
205
|
+
nodes += 1;
|
|
206
|
+
if (nodes > 1e5 || depth > 32) return false;
|
|
207
|
+
if (value === null || typeof value === "boolean") continue;
|
|
208
|
+
if (typeof value === "number") {
|
|
209
|
+
if (!Number.isFinite(value)) return false;
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
if (typeof value === "string") {
|
|
213
|
+
if (value.length > 1e6) return false;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (value instanceof Uint8Array) {
|
|
217
|
+
if (value.byteLength > 8 * 1024 * 1024) return false;
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
if (Array.isArray(value)) {
|
|
221
|
+
if (value.length > 1e4) return false;
|
|
222
|
+
for (const child of value) pending.push({
|
|
223
|
+
value: child,
|
|
224
|
+
depth: depth + 1
|
|
225
|
+
});
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (typeof value !== "object") return false;
|
|
229
|
+
const entries = Object.entries(value);
|
|
230
|
+
if (entries.length > 1e4 || entries.some(([key]) => key.length > 256)) return false;
|
|
231
|
+
for (const [, child] of entries) pending.push({
|
|
232
|
+
value: child,
|
|
233
|
+
depth: depth + 1
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
const boundedPayload = zod.z.json();
|
|
239
|
+
const bytes = zod.z.array(zod.z.number().int().min(0).max(255)).max(8 * 1024 * 1024);
|
|
240
|
+
const packageSelector = zod.z.object({ packageId: identifier });
|
|
241
|
+
const resourceSelector = zod.z.object({
|
|
242
|
+
packageId: identifier,
|
|
243
|
+
resourceId: identifier
|
|
244
|
+
});
|
|
245
|
+
const componentSelector = zod.z.object({
|
|
246
|
+
packageId: identifier,
|
|
247
|
+
componentResourceId: identifier
|
|
248
|
+
});
|
|
249
|
+
const displayNodeSelector = componentSelector.extend({ displayNodeId: identifier });
|
|
250
|
+
const controllerSelector = componentSelector.extend({ controllerName: identifier });
|
|
251
|
+
const transitionSelector = componentSelector.extend({ transitionName: identifier });
|
|
252
|
+
const folderSelector = packageSelector.extend({
|
|
253
|
+
branch: zod.z.string().max(256).optional(),
|
|
254
|
+
path: zod.z.string().min(1).max(4096)
|
|
255
|
+
});
|
|
256
|
+
const operationBase = { opId: identifier.optional() };
|
|
257
|
+
const operation = zod.z.discriminatedUnion("kind", [
|
|
258
|
+
zod.z.object({
|
|
259
|
+
...operationBase,
|
|
260
|
+
kind: zod.z.literal("updateProjectSettings"),
|
|
261
|
+
settings: boundedPayload
|
|
262
|
+
}),
|
|
263
|
+
zod.z.object({
|
|
264
|
+
...operationBase,
|
|
265
|
+
kind: zod.z.literal("updatePackageSettings"),
|
|
266
|
+
selector: packageSelector,
|
|
267
|
+
settings: boundedPayload
|
|
268
|
+
}),
|
|
269
|
+
zod.z.object({
|
|
270
|
+
...operationBase,
|
|
271
|
+
kind: zod.z.literal("renameResource"),
|
|
272
|
+
selector: resourceSelector,
|
|
273
|
+
newName: identifier
|
|
274
|
+
}),
|
|
275
|
+
zod.z.object({
|
|
276
|
+
...operationBase,
|
|
277
|
+
kind: zod.z.literal("moveResource"),
|
|
278
|
+
selector: resourceSelector,
|
|
279
|
+
toPath: zod.z.string().max(4096)
|
|
280
|
+
}),
|
|
281
|
+
zod.z.object({
|
|
282
|
+
...operationBase,
|
|
283
|
+
kind: zod.z.literal("setResourceFavorite"),
|
|
284
|
+
selector: resourceSelector,
|
|
285
|
+
favorite: zod.z.boolean()
|
|
286
|
+
}),
|
|
287
|
+
zod.z.object({
|
|
288
|
+
...operationBase,
|
|
289
|
+
kind: zod.z.literal("setResourceFolderFavorite"),
|
|
290
|
+
selector: folderSelector,
|
|
291
|
+
favorite: zod.z.boolean()
|
|
292
|
+
}),
|
|
293
|
+
zod.z.object({
|
|
294
|
+
...operationBase,
|
|
295
|
+
kind: zod.z.literal("setResourceFolderAtlas"),
|
|
296
|
+
selector: folderSelector,
|
|
297
|
+
atlas: zod.z.string().max(32)
|
|
298
|
+
}),
|
|
299
|
+
zod.z.object({
|
|
300
|
+
...operationBase,
|
|
301
|
+
kind: zod.z.literal("setResourceExported"),
|
|
302
|
+
selector: resourceSelector,
|
|
303
|
+
exported: zod.z.boolean()
|
|
304
|
+
}),
|
|
305
|
+
zod.z.object({
|
|
306
|
+
...operationBase,
|
|
307
|
+
kind: zod.z.literal("addResourceFolder"),
|
|
308
|
+
selector: packageSelector,
|
|
309
|
+
path: zod.z.string().max(4096),
|
|
310
|
+
branch: zod.z.string().max(256).optional(),
|
|
311
|
+
favorite: zod.z.boolean().optional(),
|
|
312
|
+
atlas: zod.z.string().max(32).optional()
|
|
313
|
+
}),
|
|
314
|
+
zod.z.object({
|
|
315
|
+
...operationBase,
|
|
316
|
+
kind: zod.z.literal("renameResourceFolder"),
|
|
317
|
+
selector: folderSelector,
|
|
318
|
+
newName: identifier
|
|
319
|
+
}),
|
|
320
|
+
zod.z.object({
|
|
321
|
+
...operationBase,
|
|
322
|
+
kind: zod.z.literal("moveResourceFolder"),
|
|
323
|
+
selector: folderSelector,
|
|
324
|
+
toPath: zod.z.string().max(4096)
|
|
325
|
+
}),
|
|
326
|
+
zod.z.object({
|
|
327
|
+
...operationBase,
|
|
328
|
+
kind: zod.z.literal("removeResourceFolder"),
|
|
329
|
+
selector: folderSelector
|
|
330
|
+
}),
|
|
331
|
+
zod.z.object({
|
|
332
|
+
...operationBase,
|
|
333
|
+
kind: zod.z.literal("setImageResourceProps"),
|
|
334
|
+
selector: resourceSelector,
|
|
335
|
+
props: boundedPayload
|
|
336
|
+
}),
|
|
337
|
+
zod.z.object({
|
|
338
|
+
...operationBase,
|
|
339
|
+
kind: zod.z.literal("addResource"),
|
|
340
|
+
selector: packageSelector,
|
|
341
|
+
resource: boundedPayload,
|
|
342
|
+
atIndex: zod.z.number().int().nonnegative().optional()
|
|
343
|
+
}),
|
|
344
|
+
zod.z.object({
|
|
345
|
+
...operationBase,
|
|
346
|
+
kind: zod.z.literal("addBranch"),
|
|
347
|
+
branch: identifier
|
|
348
|
+
}),
|
|
349
|
+
zod.z.object({
|
|
350
|
+
...operationBase,
|
|
351
|
+
kind: zod.z.literal("renameBranch"),
|
|
352
|
+
selector: zod.z.object({ branch: identifier }),
|
|
353
|
+
newName: identifier
|
|
354
|
+
}),
|
|
355
|
+
zod.z.object({
|
|
356
|
+
...operationBase,
|
|
357
|
+
kind: zod.z.literal("removeBranch"),
|
|
358
|
+
selector: zod.z.object({ branch: identifier })
|
|
359
|
+
}),
|
|
360
|
+
zod.z.object({
|
|
361
|
+
...operationBase,
|
|
362
|
+
kind: zod.z.literal("addPackage"),
|
|
363
|
+
package: boundedPayload,
|
|
364
|
+
atIndex: zod.z.number().int().nonnegative()
|
|
365
|
+
}),
|
|
366
|
+
zod.z.object({
|
|
367
|
+
...operationBase,
|
|
368
|
+
kind: zod.z.literal("renamePackage"),
|
|
369
|
+
selector: packageSelector,
|
|
370
|
+
newName: identifier
|
|
371
|
+
}),
|
|
372
|
+
zod.z.object({
|
|
373
|
+
...operationBase,
|
|
374
|
+
kind: zod.z.literal("removePackage"),
|
|
375
|
+
selector: packageSelector
|
|
376
|
+
}),
|
|
377
|
+
zod.z.object({
|
|
378
|
+
...operationBase,
|
|
379
|
+
kind: zod.z.literal("addComponent"),
|
|
380
|
+
selector: packageSelector,
|
|
381
|
+
component: boundedPayload,
|
|
382
|
+
atIndex: zod.z.number().int().nonnegative()
|
|
383
|
+
}),
|
|
384
|
+
zod.z.object({
|
|
385
|
+
...operationBase,
|
|
386
|
+
kind: zod.z.literal("removeComponent"),
|
|
387
|
+
selector: componentSelector
|
|
388
|
+
}),
|
|
389
|
+
zod.z.object({
|
|
390
|
+
...operationBase,
|
|
391
|
+
kind: zod.z.literal("moveComponent"),
|
|
392
|
+
selector: componentSelector,
|
|
393
|
+
toPackageId: identifier,
|
|
394
|
+
toIndex: zod.z.number().int().nonnegative()
|
|
395
|
+
}),
|
|
396
|
+
zod.z.object({
|
|
397
|
+
...operationBase,
|
|
398
|
+
kind: zod.z.literal("replaceResourceBytes"),
|
|
399
|
+
selector: resourceSelector,
|
|
400
|
+
sourceBytes: bytes
|
|
401
|
+
}),
|
|
402
|
+
zod.z.object({
|
|
403
|
+
...operationBase,
|
|
404
|
+
kind: zod.z.literal("removeResource"),
|
|
405
|
+
selector: resourceSelector
|
|
406
|
+
}),
|
|
407
|
+
zod.z.object({
|
|
408
|
+
...operationBase,
|
|
409
|
+
kind: zod.z.literal("setDisplayNodeProps"),
|
|
410
|
+
selector: displayNodeSelector,
|
|
411
|
+
props: boundedPayload
|
|
412
|
+
}),
|
|
413
|
+
zod.z.object({
|
|
414
|
+
...operationBase,
|
|
415
|
+
kind: zod.z.literal("setComponentProps"),
|
|
416
|
+
selector: componentSelector,
|
|
417
|
+
props: boundedPayload
|
|
418
|
+
}),
|
|
419
|
+
zod.z.object({
|
|
420
|
+
...operationBase,
|
|
421
|
+
kind: zod.z.literal("attachDisplayNode"),
|
|
422
|
+
selector: componentSelector,
|
|
423
|
+
atIndex: zod.z.number().int().nonnegative(),
|
|
424
|
+
node: boundedPayload
|
|
425
|
+
}),
|
|
426
|
+
zod.z.object({
|
|
427
|
+
...operationBase,
|
|
428
|
+
kind: zod.z.literal("detachDisplayNode"),
|
|
429
|
+
selector: displayNodeSelector
|
|
430
|
+
}),
|
|
431
|
+
...["addController", "updateController"].map((kind) => zod.z.object({
|
|
432
|
+
...operationBase,
|
|
433
|
+
kind: zod.z.literal(kind),
|
|
434
|
+
selector: controllerSelector,
|
|
435
|
+
controller: boundedPayload
|
|
436
|
+
})),
|
|
437
|
+
zod.z.object({
|
|
438
|
+
...operationBase,
|
|
439
|
+
kind: zod.z.literal("removeController"),
|
|
440
|
+
selector: controllerSelector
|
|
441
|
+
}),
|
|
442
|
+
...["addTransition", "updateTransition"].map((kind) => zod.z.object({
|
|
443
|
+
...operationBase,
|
|
444
|
+
kind: zod.z.literal(kind),
|
|
445
|
+
selector: transitionSelector,
|
|
446
|
+
transition: boundedPayload
|
|
447
|
+
})),
|
|
448
|
+
zod.z.object({
|
|
449
|
+
...operationBase,
|
|
450
|
+
kind: zod.z.literal("removeTransition"),
|
|
451
|
+
selector: transitionSelector
|
|
452
|
+
}),
|
|
453
|
+
...[
|
|
454
|
+
"addLookGear",
|
|
455
|
+
"updateLookGear",
|
|
456
|
+
"addGear",
|
|
457
|
+
"updateGear"
|
|
458
|
+
].map((kind) => zod.z.object({
|
|
459
|
+
...operationBase,
|
|
460
|
+
kind: zod.z.literal(kind),
|
|
461
|
+
selector: displayNodeSelector.extend({
|
|
462
|
+
kind: identifier,
|
|
463
|
+
controllerName: identifier
|
|
464
|
+
}),
|
|
465
|
+
gear: boundedPayload
|
|
466
|
+
})),
|
|
467
|
+
...["removeLookGear", "removeGear"].map((kind) => zod.z.object({
|
|
468
|
+
...operationBase,
|
|
469
|
+
kind: zod.z.literal(kind),
|
|
470
|
+
selector: displayNodeSelector.extend({
|
|
471
|
+
kind: identifier,
|
|
472
|
+
controllerName: identifier
|
|
473
|
+
})
|
|
474
|
+
}))
|
|
475
|
+
]);
|
|
476
|
+
const project = zod.z.object({
|
|
477
|
+
projectId: identifier,
|
|
478
|
+
projectType: zod.z.number().int(),
|
|
479
|
+
version: zod.z.string().max(256),
|
|
480
|
+
branches: zod.z.array(zod.z.string().max(256)).max(256),
|
|
481
|
+
settings: boundedPayload,
|
|
482
|
+
packages: zod.z.array(zod.z.object({
|
|
483
|
+
id: identifier,
|
|
484
|
+
name: identifier,
|
|
485
|
+
compressPNG: zod.z.boolean().nullable(),
|
|
486
|
+
jpegQuality: zod.z.number().finite().nullable(),
|
|
487
|
+
publish: boundedPayload.nullable(),
|
|
488
|
+
branchNames: zod.z.array(zod.z.string().max(256)).max(256),
|
|
489
|
+
folders: zod.z.array(boundedPayload).max(1e4),
|
|
490
|
+
resources: zod.z.array(boundedPayload).max(1e5)
|
|
491
|
+
})).max(1e3)
|
|
492
|
+
});
|
|
493
|
+
const OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA = zod.z.object({ backendResult: zod.z.discriminatedUnion("ok", [zod.z.object({
|
|
494
|
+
ok: zod.z.literal(true),
|
|
495
|
+
data: boundedPayload,
|
|
496
|
+
meta: boundedPayload
|
|
497
|
+
}), zod.z.object({
|
|
498
|
+
ok: zod.z.literal(false),
|
|
499
|
+
error: zod.z.object({
|
|
500
|
+
code: identifier,
|
|
501
|
+
message: zod.z.string().max(1e6)
|
|
502
|
+
}).passthrough(),
|
|
503
|
+
meta: boundedPayload,
|
|
504
|
+
session: boundedPayload.optional()
|
|
505
|
+
})]) });
|
|
285
506
|
const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
286
507
|
{
|
|
287
508
|
name: "openfairygui_backend_get_capabilities",
|
|
@@ -315,7 +536,7 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
315
536
|
title: "Open Project Session",
|
|
316
537
|
description: "Open a browser-safe backend session from an already loaded UAM project without filesystem access.",
|
|
317
538
|
inputSchema: zod.z.object({
|
|
318
|
-
project
|
|
539
|
+
project,
|
|
319
540
|
sessionId: zod.z.string().min(1).optional(),
|
|
320
541
|
canonicalProjectPath: zod.z.string().min(1).optional(),
|
|
321
542
|
canonicalPathKey: zod.z.string().min(1).optional()
|
|
@@ -370,11 +591,11 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
370
591
|
name: "openfairygui_backend_apply_transaction",
|
|
371
592
|
backendMethod: "applyTransaction",
|
|
372
593
|
title: "Apply UAM Transaction",
|
|
373
|
-
description: "Apply a
|
|
594
|
+
description: "Apply a bounded, revision-checked UAM operation batch using the Core transaction discriminants.",
|
|
374
595
|
inputSchema: zod.z.object({
|
|
375
596
|
sessionId,
|
|
376
597
|
expectedRevision,
|
|
377
|
-
operations: zod.z.array(
|
|
598
|
+
operations: zod.z.array(operation).min(1).max(1e3)
|
|
378
599
|
}),
|
|
379
600
|
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
380
601
|
annotations: {
|
|
@@ -388,7 +609,7 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
388
609
|
name: "openfairygui_backend_save_session",
|
|
389
610
|
backendMethod: "saveSession",
|
|
390
611
|
title: "Save Backend Session",
|
|
391
|
-
description: "Write the current backend session
|
|
612
|
+
description: "Write the current backend session through its coordinated save path; Node uses an atomic staged directory swap.",
|
|
392
613
|
inputSchema: zod.z.object({
|
|
393
614
|
sessionId,
|
|
394
615
|
expectedRevision: expectedRevision.optional(),
|
|
@@ -546,10 +767,149 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
546
767
|
}
|
|
547
768
|
];
|
|
548
769
|
//#endregion
|
|
770
|
+
//#region src/tool-handler.ts
|
|
771
|
+
function jsonResult(payload, isError = false) {
|
|
772
|
+
const text = JSON.stringify(payload, null, 2);
|
|
773
|
+
const wirePayload = JSON.parse(text);
|
|
774
|
+
return {
|
|
775
|
+
content: [{
|
|
776
|
+
type: "text",
|
|
777
|
+
text
|
|
778
|
+
}],
|
|
779
|
+
structuredContent: { backendResult: wirePayload },
|
|
780
|
+
isError
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
function isBackendFailure(value) {
|
|
784
|
+
return typeof value === "object" && value !== null && "ok" in value && value.ok === false;
|
|
785
|
+
}
|
|
786
|
+
function unhandledBackendFailure(startedAt) {
|
|
787
|
+
return {
|
|
788
|
+
ok: false,
|
|
789
|
+
meta: {
|
|
790
|
+
requestId: crypto.randomUUID(),
|
|
791
|
+
durationMs: Math.max(0, Date.now() - startedAt),
|
|
792
|
+
warnings: [],
|
|
793
|
+
diagnostics: [],
|
|
794
|
+
stage: "runtime",
|
|
795
|
+
contractVersion: _openfairygui_backend.BACKEND_CONTRACT_VERSION,
|
|
796
|
+
capabilitySchemaVersion: _openfairygui_backend.BACKEND_CAPABILITY_SCHEMA_VERSION
|
|
797
|
+
},
|
|
798
|
+
error: {
|
|
799
|
+
code: "backend_unhandled_error",
|
|
800
|
+
message: "Backend tool execution failed."
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
async function callOpenFairyGuiBackendTool(runtime, name, input) {
|
|
805
|
+
if (!isOpenFairyGuiMcpPayloadWithinBudget(input)) throw new RangeError("MCP input exceeds the depth, node, key, string, or byte budget.");
|
|
806
|
+
const startedAt = Date.now();
|
|
807
|
+
let result;
|
|
808
|
+
try {
|
|
809
|
+
switch (name) {
|
|
810
|
+
case "openfairygui_backend_get_capabilities":
|
|
811
|
+
result = runtime.getCapabilities();
|
|
812
|
+
break;
|
|
813
|
+
case "openfairygui_backend_open_session":
|
|
814
|
+
result = await runtime.openSession({ projectPath: String(input.projectPath) });
|
|
815
|
+
break;
|
|
816
|
+
case "openfairygui_backend_open_project_session":
|
|
817
|
+
result = runtime.openProjectSession({
|
|
818
|
+
project: input.project,
|
|
819
|
+
sessionId: input.sessionId === void 0 ? void 0 : String(input.sessionId),
|
|
820
|
+
canonicalProjectPath: input.canonicalProjectPath === void 0 ? void 0 : String(input.canonicalProjectPath),
|
|
821
|
+
canonicalPathKey: input.canonicalPathKey === void 0 ? void 0 : String(input.canonicalPathKey)
|
|
822
|
+
});
|
|
823
|
+
break;
|
|
824
|
+
case "openfairygui_backend_get_session":
|
|
825
|
+
result = runtime.getSession({ sessionId: String(input.sessionId) });
|
|
826
|
+
break;
|
|
827
|
+
case "openfairygui_backend_get_project_outline":
|
|
828
|
+
result = runtime.getProjectOutline({ sessionId: String(input.sessionId) });
|
|
829
|
+
break;
|
|
830
|
+
case "openfairygui_backend_validate_session":
|
|
831
|
+
result = runtime.validateSession({ sessionId: String(input.sessionId) });
|
|
832
|
+
break;
|
|
833
|
+
case "openfairygui_backend_apply_transaction": {
|
|
834
|
+
const operations = input.operations.map((operation) => operation.kind === "replaceResourceBytes" ? {
|
|
835
|
+
...operation,
|
|
836
|
+
sourceBytes: new Uint8Array(operation.sourceBytes)
|
|
837
|
+
} : operation);
|
|
838
|
+
result = await runtime.applyTransaction({
|
|
839
|
+
sessionId: String(input.sessionId),
|
|
840
|
+
expectedRevision: Number(input.expectedRevision),
|
|
841
|
+
operations
|
|
842
|
+
});
|
|
843
|
+
break;
|
|
844
|
+
}
|
|
845
|
+
case "openfairygui_backend_save_session":
|
|
846
|
+
result = await runtime.saveSession({
|
|
847
|
+
sessionId: String(input.sessionId),
|
|
848
|
+
expectedRevision: input.expectedRevision === void 0 ? void 0 : Number(input.expectedRevision),
|
|
849
|
+
targetPath: input.targetPath === void 0 ? void 0 : String(input.targetPath),
|
|
850
|
+
force: input.force === void 0 ? void 0 : Boolean(input.force),
|
|
851
|
+
mode: input.mode
|
|
852
|
+
});
|
|
853
|
+
break;
|
|
854
|
+
case "openfairygui_backend_materialize_session":
|
|
855
|
+
result = await runtime.materializeSession({
|
|
856
|
+
sessionId: String(input.sessionId),
|
|
857
|
+
expectedRevision: input.expectedRevision === void 0 ? void 0 : Number(input.expectedRevision),
|
|
858
|
+
mode: input.mode,
|
|
859
|
+
reason: input.reason === void 0 ? void 0 : String(input.reason)
|
|
860
|
+
});
|
|
861
|
+
break;
|
|
862
|
+
case "openfairygui_backend_close_session":
|
|
863
|
+
result = await runtime.closeSession({ sessionId: String(input.sessionId) });
|
|
864
|
+
break;
|
|
865
|
+
case "openfairygui_backend_get_events":
|
|
866
|
+
result = runtime.getEvents({
|
|
867
|
+
sessionId: String(input.sessionId),
|
|
868
|
+
after: input.after === void 0 ? void 0 : String(input.after),
|
|
869
|
+
limit: input.limit === void 0 ? void 0 : Number(input.limit)
|
|
870
|
+
});
|
|
871
|
+
break;
|
|
872
|
+
case "openfairygui_backend_get_job":
|
|
873
|
+
result = runtime.getJob({
|
|
874
|
+
sessionId: String(input.sessionId),
|
|
875
|
+
jobId: String(input.jobId)
|
|
876
|
+
});
|
|
877
|
+
break;
|
|
878
|
+
case "openfairygui_backend_list_jobs":
|
|
879
|
+
result = runtime.listJobs({
|
|
880
|
+
sessionId: String(input.sessionId),
|
|
881
|
+
status: input.status,
|
|
882
|
+
kind: input.kind,
|
|
883
|
+
limit: input.limit === void 0 ? void 0 : Number(input.limit)
|
|
884
|
+
});
|
|
885
|
+
break;
|
|
886
|
+
case "openfairygui_backend_cancel_job":
|
|
887
|
+
result = runtime.cancelJob({
|
|
888
|
+
sessionId: String(input.sessionId),
|
|
889
|
+
jobId: String(input.jobId)
|
|
890
|
+
});
|
|
891
|
+
break;
|
|
892
|
+
case "openfairygui_backend_get_cache_snapshot":
|
|
893
|
+
result = runtime.getCacheSnapshot({ sessionId: String(input.sessionId) });
|
|
894
|
+
break;
|
|
895
|
+
case "openfairygui_backend_refresh_cache":
|
|
896
|
+
result = runtime.refreshCache({
|
|
897
|
+
sessionId: String(input.sessionId),
|
|
898
|
+
reason: input.reason
|
|
899
|
+
});
|
|
900
|
+
break;
|
|
901
|
+
default: throw new Error(`Unknown OpenFairyGUI backend MCP tool: ${name}`);
|
|
902
|
+
}
|
|
903
|
+
} catch {
|
|
904
|
+
return jsonResult(unhandledBackendFailure(startedAt), true);
|
|
905
|
+
}
|
|
906
|
+
return jsonResult(result, isBackendFailure(result));
|
|
907
|
+
}
|
|
908
|
+
//#endregion
|
|
549
909
|
//#region src/server.ts
|
|
550
910
|
const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
|
|
551
911
|
function getInjectedPackageVersion() {
|
|
552
|
-
const version = "0.3.
|
|
912
|
+
const version = "0.3.1";
|
|
553
913
|
return typeof version === "string" && true ? version : null;
|
|
554
914
|
}
|
|
555
915
|
function readPackageVersion() {
|
|
@@ -563,7 +923,7 @@ function readPackageVersion() {
|
|
|
563
923
|
}
|
|
564
924
|
const PACKAGE_VERSION = readPackageVersion();
|
|
565
925
|
function createOpenFairyGuiMcpServer(options = {}) {
|
|
566
|
-
const runtime = options.runtime ?? (0, _openfairygui_backend_node.createNodeBackendRuntime)();
|
|
926
|
+
const runtime = options.runtime ?? (0, _openfairygui_backend_node.createNodeBackendRuntime)({ allowedProjectRoots: options.allowedProjectRoots ?? [process.cwd()] });
|
|
567
927
|
const server = new _modelcontextprotocol_sdk_server_mcp_js.McpServer({
|
|
568
928
|
name: options.name ?? "openfairygui-mcp",
|
|
569
929
|
version: options.version ?? PACKAGE_VERSION
|
|
@@ -586,7 +946,8 @@ function createOpenFairyGuiMcpServer(options = {}) {
|
|
|
586
946
|
//#endregion
|
|
587
947
|
//#region src/stdio.ts
|
|
588
948
|
async function connectOpenFairyGuiMcpStdio() {
|
|
589
|
-
|
|
949
|
+
const configuredRoots = process.env.OPENFAIRYGUI_ALLOWED_PROJECT_ROOTS?.split(node_path.default.delimiter).map((value) => value.trim()).filter(Boolean);
|
|
950
|
+
await createOpenFairyGuiMcpServer({ allowedProjectRoots: configuredRoots }).connect(new _modelcontextprotocol_sdk_server_stdio_js.StdioServerTransport());
|
|
590
951
|
}
|
|
591
952
|
if (process.argv[1] && require("url").pathToFileURL(__filename).href === (0, node_url.pathToFileURL)(process.argv[1]).href) connectOpenFairyGuiMcpStdio().catch((error) => {
|
|
592
953
|
console.error(error instanceof Error ? error.stack ?? error.message : String(error));
|
package/dist/stdio.cjs
CHANGED
package/dist/stdio.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as connectOpenFairyGuiMcpStdio } from "./stdio-
|
|
1
|
+
import { t as connectOpenFairyGuiMcpStdio } from "./stdio-HOHWH0x4.mjs";
|
|
2
2
|
export { connectOpenFairyGuiMcpStdio };
|