blueprint-extractor-mcp 1.5.0 → 1.6.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.
Files changed (2) hide show
  1. package/dist/index.js +155 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { compactBlueprint } from './compactor.js';
7
7
  const client = new UEClient();
8
8
  const server = new McpServer({
9
9
  name: 'blueprint-extractor',
10
- version: '1.5.0',
10
+ version: '1.6.0',
11
11
  });
12
12
  // Shared scope enum with detailed descriptions
13
13
  const scopeEnum = z.enum([
@@ -326,6 +326,160 @@ RETURNS: JSON array of objects with path, name, and class for each asset (and su
326
326
  return { content: [{ type: 'text', text: `Error: ${e instanceof Error ? e.message : String(e)}` }], isError: true };
327
327
  }
328
328
  });
329
+ // Recursive schema for widget tree nodes (used by build_widget_tree)
330
+ const WidgetNodeSchema = z.lazy(() => z.object({
331
+ class: z.string().describe('Widget class name (e.g. CanvasPanel, TextBlock, CommonButtonBase, VerticalBox)'),
332
+ name: z.string().describe('Widget instance name (used for BindWidget matching)'),
333
+ is_variable: z.boolean().default(false).describe('Mark as variable for BindWidget access from C++'),
334
+ slot: z.record(z.string(), z.unknown()).optional().describe('Slot properties (type depends on parent panel)'),
335
+ properties: z.record(z.string(), z.unknown()).optional().describe('Widget UPROPERTY values to set'),
336
+ children: z.array(WidgetNodeSchema).optional().describe('Child widgets (only valid for panel widgets)'),
337
+ }));
338
+ // Tool 8: create_widget_blueprint
339
+ server.registerTool('create_widget_blueprint', {
340
+ title: 'Create Widget Blueprint',
341
+ description: `Create a new UE5 WidgetBlueprint asset with a specified parent class.
342
+
343
+ USAGE: Provide the content path where the asset should be created and optionally a parent class.
344
+ Default parent is UserWidget. For CommonUI widgets use CommonActivatableWidget, CommonButtonBase, etc.
345
+
346
+ RETURNS: JSON with success status, asset path, and parent class name.`,
347
+ inputSchema: {
348
+ asset_path: z.string().describe('UE content path for the new WidgetBlueprint (e.g. /Game/UI/WBP_MyWidget)'),
349
+ parent_class: z.string().default('UserWidget').describe('Parent class name (e.g. UserWidget, CommonActivatableWidget, CommonButtonBase)'),
350
+ },
351
+ annotations: {
352
+ title: 'Create Widget Blueprint',
353
+ readOnlyHint: false,
354
+ destructiveHint: false,
355
+ idempotentHint: true,
356
+ openWorldHint: false,
357
+ },
358
+ }, async ({ asset_path, parent_class }) => {
359
+ try {
360
+ const result = await client.callSubsystem('CreateWidgetBlueprint', {
361
+ AssetPath: asset_path,
362
+ ParentClass: parent_class,
363
+ });
364
+ const parsed = JSON.parse(result);
365
+ if (parsed.error) {
366
+ return { content: [{ type: 'text', text: `Error: ${parsed.error}` }], isError: true };
367
+ }
368
+ return { content: [{ type: 'text', text: JSON.stringify(parsed, null, 2) }] };
369
+ }
370
+ catch (e) {
371
+ return { content: [{ type: 'text', text: `Error: ${e instanceof Error ? e.message : String(e)}` }], isError: true };
372
+ }
373
+ });
374
+ // Tool 9: build_widget_tree
375
+ server.registerTool('build_widget_tree', {
376
+ title: 'Build Widget Tree',
377
+ description: `Build or replace the entire widget hierarchy of an existing WidgetBlueprint from a JSON tree description.
378
+
379
+ WARNING: This REPLACES the existing widget tree — all current widgets will be removed.
380
+
381
+ USAGE: Provide the asset path and a root_widget object describing the full tree recursively.
382
+ Each widget node has: class, name, is_variable, slot (optional), properties (optional), children (optional).
383
+
384
+ RETURNS: JSON with success status, widget count, and any errors.`,
385
+ inputSchema: {
386
+ asset_path: z.string().describe('UE content path to an existing WidgetBlueprint'),
387
+ root_widget: WidgetNodeSchema.describe('Root widget of the tree hierarchy'),
388
+ },
389
+ annotations: {
390
+ title: 'Build Widget Tree',
391
+ readOnlyHint: false,
392
+ destructiveHint: true,
393
+ idempotentHint: true,
394
+ openWorldHint: false,
395
+ },
396
+ }, async ({ asset_path, root_widget }) => {
397
+ try {
398
+ const result = await client.callSubsystem('BuildWidgetTree', {
399
+ AssetPath: asset_path,
400
+ WidgetTreeJson: JSON.stringify(root_widget),
401
+ });
402
+ const parsed = JSON.parse(result);
403
+ if (parsed.error) {
404
+ return { content: [{ type: 'text', text: `Error: ${parsed.error}` }], isError: true };
405
+ }
406
+ return { content: [{ type: 'text', text: JSON.stringify(parsed, null, 2) }] };
407
+ }
408
+ catch (e) {
409
+ return { content: [{ type: 'text', text: `Error: ${e instanceof Error ? e.message : String(e)}` }], isError: true };
410
+ }
411
+ });
412
+ // Tool 10: modify_widget
413
+ server.registerTool('modify_widget', {
414
+ title: 'Modify Widget',
415
+ description: `Modify properties and/or slot configuration of an existing widget within a WidgetBlueprint.
416
+
417
+ USAGE: Specify the asset path, widget name, and the properties/slot values to change.
418
+ Only specified properties are modified — others remain unchanged.
419
+
420
+ RETURNS: JSON with success status, widget name, class, and any errors.`,
421
+ inputSchema: {
422
+ asset_path: z.string().describe('UE content path to the WidgetBlueprint'),
423
+ widget_name: z.string().describe('Name of the widget to modify (as shown in the widget tree)'),
424
+ properties: z.record(z.string(), z.unknown()).optional().describe('Widget UPROPERTY values to set'),
425
+ slot: z.record(z.string(), z.unknown()).optional().describe('Slot properties to set'),
426
+ },
427
+ annotations: {
428
+ title: 'Modify Widget',
429
+ readOnlyHint: false,
430
+ destructiveHint: false,
431
+ idempotentHint: true,
432
+ openWorldHint: false,
433
+ },
434
+ }, async ({ asset_path, widget_name, properties, slot }) => {
435
+ try {
436
+ const result = await client.callSubsystem('ModifyWidget', {
437
+ AssetPath: asset_path,
438
+ WidgetName: widget_name,
439
+ PropertiesJson: JSON.stringify(properties ?? {}),
440
+ SlotJson: JSON.stringify(slot ?? {}),
441
+ });
442
+ const parsed = JSON.parse(result);
443
+ if (parsed.error) {
444
+ return { content: [{ type: 'text', text: `Error: ${parsed.error}` }], isError: true };
445
+ }
446
+ return { content: [{ type: 'text', text: JSON.stringify(parsed, null, 2) }] };
447
+ }
448
+ catch (e) {
449
+ return { content: [{ type: 'text', text: `Error: ${e instanceof Error ? e.message : String(e)}` }], isError: true };
450
+ }
451
+ });
452
+ // Tool 11: compile_widget_blueprint
453
+ server.registerTool('compile_widget_blueprint', {
454
+ title: 'Compile Widget Blueprint',
455
+ description: `Compile a WidgetBlueprint and return any errors or warnings.
456
+
457
+ USAGE: Call after building or modifying a widget tree to verify compilation.
458
+
459
+ RETURNS: JSON with success status, compilation status, error count, warning count, and error details.`,
460
+ inputSchema: {
461
+ asset_path: z.string().describe('UE content path to the WidgetBlueprint to compile'),
462
+ },
463
+ annotations: {
464
+ title: 'Compile Widget Blueprint',
465
+ readOnlyHint: false,
466
+ destructiveHint: false,
467
+ idempotentHint: true,
468
+ openWorldHint: false,
469
+ },
470
+ }, async ({ asset_path }) => {
471
+ try {
472
+ const result = await client.callSubsystem('CompileWidgetBlueprint', { AssetPath: asset_path });
473
+ const parsed = JSON.parse(result);
474
+ if (parsed.error) {
475
+ return { content: [{ type: 'text', text: `Error: ${parsed.error}` }], isError: true };
476
+ }
477
+ return { content: [{ type: 'text', text: JSON.stringify(parsed, null, 2) }] };
478
+ }
479
+ catch (e) {
480
+ return { content: [{ type: 'text', text: `Error: ${e instanceof Error ? e.message : String(e)}` }], isError: true };
481
+ }
482
+ });
329
483
  // Start server
330
484
  async function main() {
331
485
  const transport = new StdioServerTransport();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blueprint-extractor-mcp",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "MCP server for UE5 BlueprintExtractor plugin",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",