@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.
@@ -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 OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA = zod.z.object({ backendResult: zod.z.object({
280
- ok: zod.z.boolean(),
281
- data: zod.z.unknown().optional(),
282
- error: zod.z.unknown().optional(),
283
- meta: zod.z.unknown().optional()
284
- }).passthrough() });
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: zod.z.unknown(),
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 backend revision-checked UAM operation batch without redefining selector or operation grammar.",
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(zod.z.unknown())
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 back through the backend coordinated non-atomic save path.",
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.0";
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
- await createOpenFairyGuiMcpServer().connect(new _modelcontextprotocol_sdk_server_stdio_js.StdioServerTransport());
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
@@ -1,3 +1,3 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_stdio = require("./stdio-9ewjcCag.cjs");
2
+ const require_stdio = require("./stdio-N6Yxacus.cjs");
3
3
  exports.connectOpenFairyGuiMcpStdio = require_stdio.connectOpenFairyGuiMcpStdio;
package/dist/stdio.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as connectOpenFairyGuiMcpStdio } from "./stdio-48jCJzS3.mjs";
1
+ import { t as connectOpenFairyGuiMcpStdio } from "./stdio-HOHWH0x4.mjs";
2
2
  export { connectOpenFairyGuiMcpStdio };