@openfairygui/mcp 0.3.1 → 0.4.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/README.md +5 -1
- package/dist/index.cjs +26 -2
- package/dist/index.d.cts +41 -640
- package/dist/index.d.mts +42 -641
- package/dist/index.mjs +2 -2
- package/dist/{stdio-HOHWH0x4.mjs → stdio-9ka7bvOr.mjs} +211 -528
- package/dist/{stdio-N6Yxacus.cjs → stdio-B0OU-oZC.cjs} +214 -531
- package/dist/stdio.cjs +1 -1
- package/dist/stdio.mjs +1 -1
- package/package.json +4 -4
- package/src/contract-schema.ts +29 -0
- package/src/index.ts +6 -1
- package/src/prompt-definitions.ts +5 -0
- package/src/resource-definitions.ts +59 -0
- package/src/server.ts +22 -7
- package/src/tool-definitions.ts +17 -306
- package/src/tool-handler.ts +16 -133
- package/src/tool-metadata.ts +157 -0
|
@@ -21,10 +21,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
}) : target, mod));
|
|
22
22
|
//#endregion
|
|
23
23
|
let _modelcontextprotocol_sdk_server_mcp_js = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
24
|
+
let _modelcontextprotocol_sdk_types_js = require("@modelcontextprotocol/sdk/types.js");
|
|
24
25
|
let _openfairygui_backend_node = require("@openfairygui/backend/node");
|
|
25
26
|
let node_module = require("node:module");
|
|
26
|
-
let _openfairygui_backend = require("@openfairygui/backend");
|
|
27
27
|
let zod = require("zod");
|
|
28
|
+
let _openfairygui_backend = require("@openfairygui/backend");
|
|
29
|
+
let _openfairygui_backend_docs = require("@openfairygui/backend/docs");
|
|
28
30
|
let _modelcontextprotocol_sdk_server_stdio_js = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
29
31
|
let node_path = require("node:path");
|
|
30
32
|
node_path = __toESM(node_path);
|
|
@@ -76,6 +78,11 @@ const OPENFAIRYGUI_BACKEND_PROMPT_DEFINITIONS = [
|
|
|
76
78
|
description: "Guide a client through backend-owned revision checks without inventing operation grammar.",
|
|
77
79
|
text: [
|
|
78
80
|
"Use openfairygui_backend_get_session to read the current revision before mutation.",
|
|
81
|
+
"Use openfairygui_backend_get_project_outline for identities, then openfairygui_backend_query_entity for current properties at the returned revision.",
|
|
82
|
+
"For settings edits, query target {kind:\"project\"} or {kind:\"package\",selector:{packageId}}; copy entity.properties.settings, change the requested fields, and submit the complete settings to updateProjectSettings or updatePackageSettings.",
|
|
83
|
+
"Read openfairygui://contracts/operations and openfairygui://contracts/operations/{kind} for the current operation names and exact JSON parameters.",
|
|
84
|
+
"Call openfairygui_backend_preflight_transaction with the queried revision and planned operations to execute and discard an isolated preview; inspect the backend diagnostics.",
|
|
85
|
+
"A successful preview does not reserve a revision or guarantee save. Apply the same batch with expectedRevision set to the preview baseRevision; refresh properties and re-plan on stale revision.",
|
|
79
86
|
"Call openfairygui_backend_apply_transaction with sessionId, expectedRevision, and backend/UAM-owned operations.",
|
|
80
87
|
"If the backend returns a stale revision error, refresh the session snapshot and re-plan against the new revision.",
|
|
81
88
|
"Do not invent selector grammar, transaction grammar, or operation payload semantics at the MCP layer."
|
|
@@ -119,6 +126,32 @@ function registerOpenFairyGuiBackendPrompts(server) {
|
|
|
119
126
|
}, () => promptResult(definition.text));
|
|
120
127
|
}
|
|
121
128
|
//#endregion
|
|
129
|
+
//#region src/contract-schema.ts
|
|
130
|
+
const CONTRACT_SNAPSHOT = (0, _openfairygui_backend_docs.getInstalledContractSnapshot)();
|
|
131
|
+
function contractObjectSchema(schema) {
|
|
132
|
+
const result = zod.z.fromJSONSchema({
|
|
133
|
+
...schema,
|
|
134
|
+
$defs: CONTRACT_SNAPSHOT.$defs
|
|
135
|
+
});
|
|
136
|
+
if (!(result instanceof zod.z.ZodObject)) throw new TypeError("Tool contract must be an object");
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
/** Decode only generated Uint8Array locations; arbitrary JSON metadata is not rewritten. */
|
|
140
|
+
function decodeToolBytes(input, paths) {
|
|
141
|
+
if (!paths.length) return input;
|
|
142
|
+
const result = structuredClone(input);
|
|
143
|
+
function visit(value, parts) {
|
|
144
|
+
if (!parts.length) return value === null ? value : Uint8Array.from(value);
|
|
145
|
+
if (!value || typeof value !== "object") return value;
|
|
146
|
+
const [key, ...rest] = parts;
|
|
147
|
+
const record = value;
|
|
148
|
+
for (const name of key === "*" ? Object.keys(record) : [key]) if (Object.hasOwn(record, name)) record[name] = visit(record[name], rest);
|
|
149
|
+
return value;
|
|
150
|
+
}
|
|
151
|
+
for (const parts of paths) visit(result, parts);
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
122
155
|
//#region src/resource-definitions.ts
|
|
123
156
|
const JSON_MIME_TYPE = "application/json";
|
|
124
157
|
function firstVariable(value) {
|
|
@@ -133,12 +166,69 @@ function jsonResource(uri, backendResult) {
|
|
|
133
166
|
}
|
|
134
167
|
const OPENFAIRYGUI_BACKEND_CAPABILITIES_RESOURCE_URI = "openfairygui://backend/capabilities";
|
|
135
168
|
const OPENFAIRYGUI_BACKEND_RESOURCE_TEMPLATES = [
|
|
169
|
+
"openfairygui://docs/methods/{method}",
|
|
170
|
+
"openfairygui://docs/cli/{command}",
|
|
171
|
+
_openfairygui_backend.BACKEND_DIAGNOSTIC_TEMPLATE,
|
|
172
|
+
_openfairygui_backend_docs.OPENFAIRYGUI_OPERATION_SCHEMA_TEMPLATE,
|
|
136
173
|
"openfairygui://backend/session/{sessionId}",
|
|
137
174
|
"openfairygui://backend/session/{sessionId}/outline",
|
|
138
175
|
"openfairygui://backend/cache/{sessionId}",
|
|
139
176
|
"openfairygui://backend/job/{sessionId}/{jobId}"
|
|
140
177
|
];
|
|
141
178
|
function registerOpenFairyGuiBackendResources(server, runtime) {
|
|
179
|
+
server.registerResource("openfairygui_docs_index", _openfairygui_backend_docs.OPENFAIRYGUI_DOCS_INDEX_URI, {
|
|
180
|
+
title: "Installed Documentation",
|
|
181
|
+
description: "Offline documentation IDs, URIs, installed package version and contract digest shared with the CLI.",
|
|
182
|
+
mimeType: JSON_MIME_TYPE
|
|
183
|
+
}, (uri) => jsonResource(uri, (0, _openfairygui_backend_docs.getInstalledDocumentationIndex)()));
|
|
184
|
+
function installedDocument(uri, id) {
|
|
185
|
+
const document = (0, _openfairygui_backend_docs.readInstalledDocumentation)(id);
|
|
186
|
+
return { contents: [{
|
|
187
|
+
uri: uri.toString(),
|
|
188
|
+
mimeType: document.mimeType,
|
|
189
|
+
text: document.text
|
|
190
|
+
}] };
|
|
191
|
+
}
|
|
192
|
+
for (const id of [
|
|
193
|
+
"workflow",
|
|
194
|
+
"restore-limits",
|
|
195
|
+
"skill",
|
|
196
|
+
"contracts"
|
|
197
|
+
]) server.registerResource(`openfairygui_docs_${id}`, `openfairygui://docs/${id}`, {
|
|
198
|
+
title: `Installed ${id}`,
|
|
199
|
+
description: "Read the installed-version corpus without repository or network access.",
|
|
200
|
+
mimeType: id === "contracts" ? JSON_MIME_TYPE : "text/markdown"
|
|
201
|
+
}, (uri) => installedDocument(uri, id));
|
|
202
|
+
server.registerResource("openfairygui_docs_method", new _modelcontextprotocol_sdk_server_mcp_js.ResourceTemplate("openfairygui://docs/methods/{method}", { list: void 0 }), {
|
|
203
|
+
title: "Installed Method Contract",
|
|
204
|
+
description: "Read self-contained Backend/MCP wire input/output schemas and metadata.",
|
|
205
|
+
mimeType: JSON_MIME_TYPE
|
|
206
|
+
}, (uri, variables) => installedDocument(uri, `methods/${firstVariable(variables.method)}`));
|
|
207
|
+
server.registerResource("openfairygui_diagnostic_catalog", _openfairygui_backend.BACKEND_DIAGNOSTICS_URI, {
|
|
208
|
+
title: "Diagnostic Recovery Catalog",
|
|
209
|
+
description: "Complete formal diagnostic ownership and recovery guidance; never automatic repair.",
|
|
210
|
+
mimeType: JSON_MIME_TYPE
|
|
211
|
+
}, (uri) => jsonResource(uri, (0, _openfairygui_backend.getBackendDiagnosticCatalog)()));
|
|
212
|
+
server.registerResource("openfairygui_docs_cli", new _modelcontextprotocol_sdk_server_mcp_js.ResourceTemplate("openfairygui://docs/cli/{command}", { list: void 0 }), {
|
|
213
|
+
title: "Installed CLI Output Contract",
|
|
214
|
+
description: "Read a generated, self-contained CLI JSON envelope schema.",
|
|
215
|
+
mimeType: JSON_MIME_TYPE
|
|
216
|
+
}, (uri, variables) => installedDocument(uri, `cli/${decodeURIComponent(firstVariable(variables.command))}`));
|
|
217
|
+
server.registerResource("openfairygui_diagnostic_guide", new _modelcontextprotocol_sdk_server_mcp_js.ResourceTemplate(_openfairygui_backend.BACKEND_DIAGNOSTIC_TEMPLATE, { list: void 0 }), {
|
|
218
|
+
title: "Diagnostic Recovery Guide",
|
|
219
|
+
description: "Read the recovery boundary for one stable diagnostic code.",
|
|
220
|
+
mimeType: JSON_MIME_TYPE
|
|
221
|
+
}, (uri, variables) => jsonResource(uri, (0, _openfairygui_backend.getBackendDiagnosticGuide)(firstVariable(variables.code))));
|
|
222
|
+
server.registerResource("openfairygui_operation_catalog", _openfairygui_backend_docs.OPENFAIRYGUI_OPERATION_CATALOG_URI, {
|
|
223
|
+
title: "UAM Operation Catalog",
|
|
224
|
+
description: "Discover current operations and their generated JSON schemas.",
|
|
225
|
+
mimeType: JSON_MIME_TYPE
|
|
226
|
+
}, (uri) => jsonResource(uri, (0, _openfairygui_backend_docs.getOpenFairyGuiOperationCatalog)()));
|
|
227
|
+
server.registerResource("openfairygui_operation_schema", new _modelcontextprotocol_sdk_server_mcp_js.ResourceTemplate(_openfairygui_backend_docs.OPENFAIRYGUI_OPERATION_SCHEMA_TEMPLATE, { list: void 0 }), {
|
|
228
|
+
title: "UAM Operation Schema",
|
|
229
|
+
description: "Read the precise Core-derived JSON wire schema for one operation. Structure is not semantic preflight.",
|
|
230
|
+
mimeType: JSON_MIME_TYPE
|
|
231
|
+
}, (uri, variables) => jsonResource(uri, (0, _openfairygui_backend_docs.getOpenFairyGuiOperationSchema)(firstVariable(variables.kind))));
|
|
142
232
|
server.registerResource("openfairygui_backend_capabilities", OPENFAIRYGUI_BACKEND_CAPABILITIES_RESOURCE_URI, {
|
|
143
233
|
title: "OpenFairyGUI Backend Capabilities",
|
|
144
234
|
description: "Read the backend capability and version envelope as JSON.",
|
|
@@ -169,348 +259,13 @@ function registerOpenFairyGuiBackendResources(server, runtime) {
|
|
|
169
259
|
})));
|
|
170
260
|
}
|
|
171
261
|
//#endregion
|
|
172
|
-
//#region src/tool-
|
|
173
|
-
const
|
|
174
|
-
const OPENFAIRYGUI_BACKEND_TOOL_NAMES = [
|
|
175
|
-
"openfairygui_backend_get_capabilities",
|
|
176
|
-
"openfairygui_backend_open_session",
|
|
177
|
-
"openfairygui_backend_open_project_session",
|
|
178
|
-
"openfairygui_backend_get_session",
|
|
179
|
-
"openfairygui_backend_get_project_outline",
|
|
180
|
-
"openfairygui_backend_validate_session",
|
|
181
|
-
"openfairygui_backend_apply_transaction",
|
|
182
|
-
"openfairygui_backend_save_session",
|
|
183
|
-
"openfairygui_backend_materialize_session",
|
|
184
|
-
"openfairygui_backend_close_session",
|
|
185
|
-
"openfairygui_backend_get_events",
|
|
186
|
-
"openfairygui_backend_get_job",
|
|
187
|
-
"openfairygui_backend_list_jobs",
|
|
188
|
-
"openfairygui_backend_cancel_job",
|
|
189
|
-
"openfairygui_backend_get_cache_snapshot",
|
|
190
|
-
"openfairygui_backend_refresh_cache"
|
|
191
|
-
];
|
|
192
|
-
const sessionId = zod.z.string().min(1);
|
|
193
|
-
const jobId = zod.z.string().min(1);
|
|
194
|
-
const expectedRevision = zod.z.number().int().nonnegative();
|
|
195
|
-
const limit = zod.z.number().int().nonnegative().optional();
|
|
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
|
-
})]) });
|
|
506
|
-
const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
262
|
+
//#region src/tool-metadata.ts
|
|
263
|
+
const OPENFAIRYGUI_BACKEND_TOOL_METADATA = [
|
|
507
264
|
{
|
|
508
265
|
name: "openfairygui_backend_get_capabilities",
|
|
509
266
|
backendMethod: "getCapabilities",
|
|
510
267
|
title: "Get Backend Capabilities",
|
|
511
268
|
description: "Return the OpenFairyGUI backend capability, version, and service-plane snapshot.",
|
|
512
|
-
inputSchema: zod.z.object({}),
|
|
513
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
514
269
|
annotations: {
|
|
515
270
|
readOnlyHint: true,
|
|
516
271
|
idempotentHint: true,
|
|
@@ -522,8 +277,6 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
522
277
|
backendMethod: "openSession",
|
|
523
278
|
title: "Open Backend Session",
|
|
524
279
|
description: "Open a FairyGUI project through BackendRuntime and acquire its backend-local session lock.",
|
|
525
|
-
inputSchema: zod.z.object({ projectPath: zod.z.string().min(1) }),
|
|
526
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
527
280
|
annotations: {
|
|
528
281
|
readOnlyHint: false,
|
|
529
282
|
idempotentHint: false,
|
|
@@ -535,13 +288,6 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
535
288
|
backendMethod: "openProjectSession",
|
|
536
289
|
title: "Open Project Session",
|
|
537
290
|
description: "Open a browser-safe backend session from an already loaded UAM project without filesystem access.",
|
|
538
|
-
inputSchema: zod.z.object({
|
|
539
|
-
project,
|
|
540
|
-
sessionId: zod.z.string().min(1).optional(),
|
|
541
|
-
canonicalProjectPath: zod.z.string().min(1).optional(),
|
|
542
|
-
canonicalPathKey: zod.z.string().min(1).optional()
|
|
543
|
-
}),
|
|
544
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
545
291
|
annotations: {
|
|
546
292
|
readOnlyHint: false,
|
|
547
293
|
idempotentHint: false,
|
|
@@ -553,8 +299,6 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
553
299
|
backendMethod: "getSession",
|
|
554
300
|
title: "Get Backend Session",
|
|
555
301
|
description: "Return a backend session snapshot by session id.",
|
|
556
|
-
inputSchema: zod.z.object({ sessionId }),
|
|
557
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
558
302
|
annotations: {
|
|
559
303
|
readOnlyHint: true,
|
|
560
304
|
idempotentHint: true,
|
|
@@ -566,8 +310,17 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
566
310
|
backendMethod: "getProjectOutline",
|
|
567
311
|
title: "Get Project Outline",
|
|
568
312
|
description: "Return a revision-bound project/package/resource/component identity outline without source bytes or full property payloads.",
|
|
569
|
-
|
|
570
|
-
|
|
313
|
+
annotations: {
|
|
314
|
+
readOnlyHint: true,
|
|
315
|
+
idempotentHint: true,
|
|
316
|
+
openWorldHint: false
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
name: "openfairygui_backend_query_entity",
|
|
321
|
+
backendMethod: "queryEntity",
|
|
322
|
+
title: "Query Entity Properties",
|
|
323
|
+
description: "Read revision-bound project/package settings, resource, component-property, display-node, controller (including pages/actions), or transition (including items) snapshots. Project queries use only kind; other queries use formal selectors. Settings snapshots include the complete settings payload for updateProjectSettings/updatePackageSettings. No source bytes; fixed projection with explicit response limits.",
|
|
571
324
|
annotations: {
|
|
572
325
|
readOnlyHint: true,
|
|
573
326
|
idempotentHint: true,
|
|
@@ -579,8 +332,17 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
579
332
|
backendMethod: "validateSession",
|
|
580
333
|
title: "Validate Project Session",
|
|
581
334
|
description: "Validate the current session project structure, references, paths, and available source bytes without writing files.",
|
|
582
|
-
|
|
583
|
-
|
|
335
|
+
annotations: {
|
|
336
|
+
readOnlyHint: true,
|
|
337
|
+
idempotentHint: true,
|
|
338
|
+
openWorldHint: false
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: "openfairygui_backend_preflight_transaction",
|
|
343
|
+
backendMethod: "preflightTransaction",
|
|
344
|
+
title: "Preview UAM Transaction",
|
|
345
|
+
description: "Execute a revision-checked operation batch on an isolated project snapshot and discard the result. Returns the base revision and Core diagnostics; does not write, reserve a revision, or guarantee a later apply/save.",
|
|
584
346
|
annotations: {
|
|
585
347
|
readOnlyHint: true,
|
|
586
348
|
idempotentHint: true,
|
|
@@ -592,12 +354,6 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
592
354
|
backendMethod: "applyTransaction",
|
|
593
355
|
title: "Apply UAM Transaction",
|
|
594
356
|
description: "Apply a bounded, revision-checked UAM operation batch using the Core transaction discriminants.",
|
|
595
|
-
inputSchema: zod.z.object({
|
|
596
|
-
sessionId,
|
|
597
|
-
expectedRevision,
|
|
598
|
-
operations: zod.z.array(operation).min(1).max(1e3)
|
|
599
|
-
}),
|
|
600
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
601
357
|
annotations: {
|
|
602
358
|
readOnlyHint: false,
|
|
603
359
|
destructiveHint: true,
|
|
@@ -610,14 +366,6 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
610
366
|
backendMethod: "saveSession",
|
|
611
367
|
title: "Save Backend Session",
|
|
612
368
|
description: "Write the current backend session through its coordinated save path; Node uses an atomic staged directory swap.",
|
|
613
|
-
inputSchema: zod.z.object({
|
|
614
|
-
sessionId,
|
|
615
|
-
expectedRevision: expectedRevision.optional(),
|
|
616
|
-
targetPath: zod.z.string().min(1).optional(),
|
|
617
|
-
force: zod.z.boolean().optional(),
|
|
618
|
-
mode: zod.z.literal("materializeCleanSession").optional()
|
|
619
|
-
}),
|
|
620
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
621
369
|
annotations: {
|
|
622
370
|
readOnlyHint: false,
|
|
623
371
|
destructiveHint: true,
|
|
@@ -630,13 +378,6 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
630
378
|
backendMethod: "materializeSession",
|
|
631
379
|
title: "Materialize Backend Session",
|
|
632
380
|
description: "Force materialize the current backend session project through the configured project storage without requiring a dirty edit revision.",
|
|
633
|
-
inputSchema: zod.z.object({
|
|
634
|
-
sessionId,
|
|
635
|
-
expectedRevision: expectedRevision.optional(),
|
|
636
|
-
mode: zod.z.literal("fullProject").optional(),
|
|
637
|
-
reason: zod.z.string().min(1).optional()
|
|
638
|
-
}),
|
|
639
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
640
381
|
annotations: {
|
|
641
382
|
readOnlyHint: false,
|
|
642
383
|
destructiveHint: true,
|
|
@@ -649,8 +390,6 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
649
390
|
backendMethod: "closeSession",
|
|
650
391
|
title: "Close Backend Session",
|
|
651
392
|
description: "Close a backend session and release its backend-local session lock.",
|
|
652
|
-
inputSchema: zod.z.object({ sessionId }),
|
|
653
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
654
393
|
annotations: {
|
|
655
394
|
readOnlyHint: false,
|
|
656
395
|
idempotentHint: false,
|
|
@@ -662,12 +401,6 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
662
401
|
backendMethod: "getEvents",
|
|
663
402
|
title: "Get Runtime Events",
|
|
664
403
|
description: "Poll backend runtime events for a session using the backend P2 event cursor contract.",
|
|
665
|
-
inputSchema: zod.z.object({
|
|
666
|
-
sessionId,
|
|
667
|
-
after: zod.z.string().optional(),
|
|
668
|
-
limit
|
|
669
|
-
}),
|
|
670
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
671
404
|
annotations: {
|
|
672
405
|
readOnlyHint: true,
|
|
673
406
|
idempotentHint: true,
|
|
@@ -679,11 +412,6 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
679
412
|
backendMethod: "getJob",
|
|
680
413
|
title: "Get Runtime Job",
|
|
681
414
|
description: "Return a backend runtime job snapshot by session and backend-local job id.",
|
|
682
|
-
inputSchema: zod.z.object({
|
|
683
|
-
sessionId,
|
|
684
|
-
jobId
|
|
685
|
-
}),
|
|
686
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
687
415
|
annotations: {
|
|
688
416
|
readOnlyHint: true,
|
|
689
417
|
idempotentHint: true,
|
|
@@ -695,21 +423,6 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
695
423
|
backendMethod: "listJobs",
|
|
696
424
|
title: "List Runtime Jobs",
|
|
697
425
|
description: "List backend runtime jobs for a session with backend P2 status/kind filters.",
|
|
698
|
-
inputSchema: zod.z.object({
|
|
699
|
-
sessionId,
|
|
700
|
-
status: zod.z.enum([
|
|
701
|
-
"queued",
|
|
702
|
-
"running",
|
|
703
|
-
"completed",
|
|
704
|
-
"failed",
|
|
705
|
-
"cancelled",
|
|
706
|
-
"active",
|
|
707
|
-
"terminal"
|
|
708
|
-
]).optional(),
|
|
709
|
-
kind: zod.z.literal("cache.refresh").optional(),
|
|
710
|
-
limit
|
|
711
|
-
}),
|
|
712
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
713
426
|
annotations: {
|
|
714
427
|
readOnlyHint: true,
|
|
715
428
|
idempotentHint: true,
|
|
@@ -721,11 +434,6 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
721
434
|
backendMethod: "cancelJob",
|
|
722
435
|
title: "Cancel Runtime Job",
|
|
723
436
|
description: "Request cooperative cancellation for a backend runtime job.",
|
|
724
|
-
inputSchema: zod.z.object({
|
|
725
|
-
sessionId,
|
|
726
|
-
jobId
|
|
727
|
-
}),
|
|
728
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
729
437
|
annotations: {
|
|
730
438
|
readOnlyHint: false,
|
|
731
439
|
idempotentHint: false,
|
|
@@ -737,8 +445,6 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
737
445
|
backendMethod: "getCacheSnapshot",
|
|
738
446
|
title: "Get Cache Snapshot",
|
|
739
447
|
description: "Return the backend P2 derived read-only cache snapshot for a session.",
|
|
740
|
-
inputSchema: zod.z.object({ sessionId }),
|
|
741
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
742
448
|
annotations: {
|
|
743
449
|
readOnlyHint: true,
|
|
744
450
|
idempotentHint: true,
|
|
@@ -750,15 +456,6 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
750
456
|
backendMethod: "refreshCache",
|
|
751
457
|
title: "Refresh Cache",
|
|
752
458
|
description: "Create a backend P2 cache.refresh job for the session cache snapshot.",
|
|
753
|
-
inputSchema: zod.z.object({
|
|
754
|
-
sessionId,
|
|
755
|
-
reason: zod.z.enum([
|
|
756
|
-
"manual",
|
|
757
|
-
"session_open",
|
|
758
|
-
"after_save"
|
|
759
|
-
]).optional()
|
|
760
|
-
}),
|
|
761
|
-
outputSchema: OPENFAIRYGUI_BACKEND_TOOL_OUTPUT_SCHEMA,
|
|
762
459
|
annotations: {
|
|
763
460
|
readOnlyHint: false,
|
|
764
461
|
idempotentHint: false,
|
|
@@ -767,9 +464,62 @@ const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = [
|
|
|
767
464
|
}
|
|
768
465
|
];
|
|
769
466
|
//#endregion
|
|
467
|
+
//#region src/tool-definitions.ts
|
|
468
|
+
const OPENFAIRYGUI_BACKEND_TOOL_PREFIX = "openfairygui_backend_";
|
|
469
|
+
const OPENFAIRYGUI_BACKEND_TOOL_NAMES = OPENFAIRYGUI_BACKEND_TOOL_METADATA.map((entry) => entry.name);
|
|
470
|
+
function isOpenFairyGuiMcpPayloadWithinBudget(root) {
|
|
471
|
+
const pending = [{
|
|
472
|
+
value: root,
|
|
473
|
+
depth: 0
|
|
474
|
+
}];
|
|
475
|
+
let nodes = 0;
|
|
476
|
+
while (pending.length > 0) {
|
|
477
|
+
const { value, depth } = pending.pop();
|
|
478
|
+
nodes += 1;
|
|
479
|
+
if (nodes > 1e5 || depth > 32) return false;
|
|
480
|
+
if (value === null || typeof value === "boolean") continue;
|
|
481
|
+
if (typeof value === "number") {
|
|
482
|
+
if (!Number.isFinite(value)) return false;
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
if (typeof value === "string") {
|
|
486
|
+
if (value.length > 1e6) return false;
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
if (value instanceof Uint8Array) {
|
|
490
|
+
if (value.byteLength > 8 * 1024 * 1024) return false;
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
if (Array.isArray(value)) {
|
|
494
|
+
if (value.length > 1e4) return false;
|
|
495
|
+
for (const child of value) pending.push({
|
|
496
|
+
value: child,
|
|
497
|
+
depth: depth + 1
|
|
498
|
+
});
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
if (typeof value !== "object") return false;
|
|
502
|
+
const entries = Object.entries(value);
|
|
503
|
+
if (entries.length > 1e4 || entries.some(([key]) => key.length > 256)) return false;
|
|
504
|
+
for (const [, child] of entries) pending.push({
|
|
505
|
+
value: child,
|
|
506
|
+
depth: depth + 1
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
return true;
|
|
510
|
+
}
|
|
511
|
+
const OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS = OPENFAIRYGUI_BACKEND_TOOL_METADATA.map((metadata) => {
|
|
512
|
+
const contract = CONTRACT_SNAPSHOT.tools[metadata.backendMethod];
|
|
513
|
+
return {
|
|
514
|
+
...metadata,
|
|
515
|
+
inputSchema: contractObjectSchema(contract.input),
|
|
516
|
+
outputSchema: contractObjectSchema(contract.output)
|
|
517
|
+
};
|
|
518
|
+
});
|
|
519
|
+
//#endregion
|
|
770
520
|
//#region src/tool-handler.ts
|
|
771
521
|
function jsonResult(payload, isError = false) {
|
|
772
|
-
const text = JSON.stringify(payload,
|
|
522
|
+
const text = JSON.stringify(payload, (_key, value) => value instanceof Uint8Array ? [...value] : value, 2);
|
|
773
523
|
const wirePayload = JSON.parse(text);
|
|
774
524
|
return {
|
|
775
525
|
content: [{
|
|
@@ -803,113 +553,24 @@ function unhandledBackendFailure(startedAt) {
|
|
|
803
553
|
}
|
|
804
554
|
async function callOpenFairyGuiBackendTool(runtime, name, input) {
|
|
805
555
|
if (!isOpenFairyGuiMcpPayloadWithinBudget(input)) throw new RangeError("MCP input exceeds the depth, node, key, string, or byte budget.");
|
|
556
|
+
const definition = OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS.find((entry) => entry.name === name);
|
|
557
|
+
if (!definition) throw new RangeError(`Unknown OpenFairyGUI backend MCP tool: ${name}`);
|
|
558
|
+
const decoded = decodeToolBytes(definition.inputSchema.parse(input), CONTRACT_SNAPSHOT.tools[definition.backendMethod].bytePaths);
|
|
806
559
|
const startedAt = Date.now();
|
|
807
|
-
let result;
|
|
808
560
|
try {
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
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
|
-
}
|
|
561
|
+
const result = await Reflect.apply(runtime[definition.backendMethod], runtime, definition.backendMethod === "getCapabilities" ? [] : [decoded]);
|
|
562
|
+
const response = jsonResult(result, isBackendFailure(result));
|
|
563
|
+
definition.outputSchema.parse(response.structuredContent);
|
|
564
|
+
return response;
|
|
903
565
|
} catch {
|
|
904
566
|
return jsonResult(unhandledBackendFailure(startedAt), true);
|
|
905
567
|
}
|
|
906
|
-
return jsonResult(result, isBackendFailure(result));
|
|
907
568
|
}
|
|
908
569
|
//#endregion
|
|
909
570
|
//#region src/server.ts
|
|
910
571
|
const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
|
|
911
572
|
function getInjectedPackageVersion() {
|
|
912
|
-
const version = "0.
|
|
573
|
+
const version = "0.4.0";
|
|
913
574
|
return typeof version === "string" && true ? version : null;
|
|
914
575
|
}
|
|
915
576
|
function readPackageVersion() {
|
|
@@ -928,17 +589,39 @@ function createOpenFairyGuiMcpServer(options = {}) {
|
|
|
928
589
|
name: options.name ?? "openfairygui-mcp",
|
|
929
590
|
version: options.version ?? PACKAGE_VERSION
|
|
930
591
|
});
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
592
|
+
const tools = [];
|
|
593
|
+
for (const definition of OPENFAIRYGUI_BACKEND_TOOL_DEFINITIONS) {
|
|
594
|
+
const metadata = {
|
|
595
|
+
name: definition.name,
|
|
596
|
+
title: definition.title,
|
|
597
|
+
description: definition.description,
|
|
598
|
+
annotations: definition.annotations,
|
|
599
|
+
_meta: {
|
|
600
|
+
"openfairygui/backendMethod": definition.backendMethod,
|
|
601
|
+
"openfairygui/adapter": "thin-backend-p2",
|
|
602
|
+
"openfairygui/contractDigest": CONTRACT_SNAPSHOT.digest
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
server.registerTool(definition.name, {
|
|
606
|
+
...metadata,
|
|
607
|
+
inputSchema: definition.inputSchema,
|
|
608
|
+
outputSchema: definition.outputSchema
|
|
609
|
+
}, async (args) => callOpenFairyGuiBackendTool(runtime, definition.name, args));
|
|
610
|
+
tools.push(_modelcontextprotocol_sdk_types_js.ToolSchema.parse({
|
|
611
|
+
...metadata,
|
|
612
|
+
inputSchema: zod.z.toJSONSchema(definition.inputSchema, {
|
|
613
|
+
target: "draft-07",
|
|
614
|
+
io: "input",
|
|
615
|
+
reused: "ref"
|
|
616
|
+
}),
|
|
617
|
+
outputSchema: zod.z.toJSONSchema(definition.outputSchema, {
|
|
618
|
+
target: "draft-07",
|
|
619
|
+
io: "output",
|
|
620
|
+
reused: "ref"
|
|
621
|
+
})
|
|
622
|
+
}));
|
|
623
|
+
}
|
|
624
|
+
server.server.setRequestHandler(_modelcontextprotocol_sdk_types_js.ListToolsRequestSchema, () => ({ tools: structuredClone(tools) }));
|
|
942
625
|
registerOpenFairyGuiBackendResources(server, runtime);
|
|
943
626
|
registerOpenFairyGuiBackendPrompts(server);
|
|
944
627
|
return server;
|
|
@@ -990,16 +673,16 @@ Object.defineProperty(exports, "OPENFAIRYGUI_BACKEND_TOOL_NAMES", {
|
|
|
990
673
|
return OPENFAIRYGUI_BACKEND_TOOL_NAMES;
|
|
991
674
|
}
|
|
992
675
|
});
|
|
993
|
-
Object.defineProperty(exports, "
|
|
676
|
+
Object.defineProperty(exports, "OPENFAIRYGUI_BACKEND_TOOL_PREFIX", {
|
|
994
677
|
enumerable: true,
|
|
995
678
|
get: function() {
|
|
996
|
-
return
|
|
679
|
+
return OPENFAIRYGUI_BACKEND_TOOL_PREFIX;
|
|
997
680
|
}
|
|
998
681
|
});
|
|
999
|
-
Object.defineProperty(exports, "
|
|
682
|
+
Object.defineProperty(exports, "__toESM", {
|
|
1000
683
|
enumerable: true,
|
|
1001
684
|
get: function() {
|
|
1002
|
-
return
|
|
685
|
+
return __toESM;
|
|
1003
686
|
}
|
|
1004
687
|
});
|
|
1005
688
|
Object.defineProperty(exports, "callOpenFairyGuiBackendTool", {
|