unreal-engine-mcp-server 0.4.0 → 0.4.3

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 (135) hide show
  1. package/.env.production +1 -1
  2. package/.github/copilot-instructions.md +45 -0
  3. package/.github/workflows/publish-mcp.yml +1 -1
  4. package/README.md +21 -5
  5. package/dist/index.js +124 -31
  6. package/dist/prompts/index.d.ts +10 -3
  7. package/dist/prompts/index.js +186 -7
  8. package/dist/resources/actors.d.ts +19 -1
  9. package/dist/resources/actors.js +55 -64
  10. package/dist/resources/assets.js +46 -62
  11. package/dist/resources/levels.d.ts +21 -3
  12. package/dist/resources/levels.js +29 -54
  13. package/dist/tools/actors.d.ts +3 -14
  14. package/dist/tools/actors.js +246 -302
  15. package/dist/tools/animation.d.ts +57 -102
  16. package/dist/tools/animation.js +429 -450
  17. package/dist/tools/assets.d.ts +13 -2
  18. package/dist/tools/assets.js +52 -44
  19. package/dist/tools/audio.d.ts +22 -13
  20. package/dist/tools/audio.js +467 -121
  21. package/dist/tools/blueprint.d.ts +32 -13
  22. package/dist/tools/blueprint.js +699 -448
  23. package/dist/tools/build_environment_advanced.d.ts +0 -1
  24. package/dist/tools/build_environment_advanced.js +190 -45
  25. package/dist/tools/consolidated-tool-definitions.js +78 -252
  26. package/dist/tools/consolidated-tool-handlers.js +506 -133
  27. package/dist/tools/debug.d.ts +72 -10
  28. package/dist/tools/debug.js +167 -31
  29. package/dist/tools/editor.d.ts +9 -2
  30. package/dist/tools/editor.js +30 -44
  31. package/dist/tools/foliage.d.ts +34 -15
  32. package/dist/tools/foliage.js +97 -107
  33. package/dist/tools/introspection.js +19 -21
  34. package/dist/tools/landscape.d.ts +1 -2
  35. package/dist/tools/landscape.js +311 -168
  36. package/dist/tools/level.d.ts +3 -28
  37. package/dist/tools/level.js +642 -192
  38. package/dist/tools/lighting.d.ts +14 -3
  39. package/dist/tools/lighting.js +236 -123
  40. package/dist/tools/materials.d.ts +25 -7
  41. package/dist/tools/materials.js +102 -79
  42. package/dist/tools/niagara.d.ts +10 -12
  43. package/dist/tools/niagara.js +74 -94
  44. package/dist/tools/performance.d.ts +12 -4
  45. package/dist/tools/performance.js +38 -79
  46. package/dist/tools/physics.d.ts +34 -10
  47. package/dist/tools/physics.js +364 -292
  48. package/dist/tools/rc.js +97 -23
  49. package/dist/tools/sequence.d.ts +1 -0
  50. package/dist/tools/sequence.js +125 -22
  51. package/dist/tools/ui.d.ts +31 -4
  52. package/dist/tools/ui.js +83 -66
  53. package/dist/tools/visual.d.ts +11 -0
  54. package/dist/tools/visual.js +245 -30
  55. package/dist/types/tool-types.d.ts +0 -6
  56. package/dist/types/tool-types.js +1 -8
  57. package/dist/unreal-bridge.d.ts +32 -2
  58. package/dist/unreal-bridge.js +621 -127
  59. package/dist/utils/elicitation.d.ts +57 -0
  60. package/dist/utils/elicitation.js +104 -0
  61. package/dist/utils/error-handler.d.ts +0 -33
  62. package/dist/utils/error-handler.js +4 -111
  63. package/dist/utils/http.d.ts +2 -22
  64. package/dist/utils/http.js +12 -75
  65. package/dist/utils/normalize.d.ts +4 -4
  66. package/dist/utils/normalize.js +15 -7
  67. package/dist/utils/python-output.d.ts +18 -0
  68. package/dist/utils/python-output.js +290 -0
  69. package/dist/utils/python.d.ts +2 -0
  70. package/dist/utils/python.js +4 -0
  71. package/dist/utils/response-validator.js +28 -2
  72. package/dist/utils/result-helpers.d.ts +27 -0
  73. package/dist/utils/result-helpers.js +147 -0
  74. package/dist/utils/safe-json.d.ts +0 -2
  75. package/dist/utils/safe-json.js +0 -43
  76. package/dist/utils/validation.d.ts +16 -0
  77. package/dist/utils/validation.js +70 -7
  78. package/mcp-config-example.json +2 -2
  79. package/package.json +10 -9
  80. package/server.json +37 -14
  81. package/src/index.ts +130 -33
  82. package/src/prompts/index.ts +211 -13
  83. package/src/resources/actors.ts +59 -44
  84. package/src/resources/assets.ts +48 -51
  85. package/src/resources/levels.ts +35 -45
  86. package/src/tools/actors.ts +269 -313
  87. package/src/tools/animation.ts +556 -539
  88. package/src/tools/assets.ts +53 -43
  89. package/src/tools/audio.ts +507 -113
  90. package/src/tools/blueprint.ts +778 -462
  91. package/src/tools/build_environment_advanced.ts +266 -64
  92. package/src/tools/consolidated-tool-definitions.ts +90 -264
  93. package/src/tools/consolidated-tool-handlers.ts +630 -121
  94. package/src/tools/debug.ts +176 -33
  95. package/src/tools/editor.ts +35 -37
  96. package/src/tools/foliage.ts +110 -104
  97. package/src/tools/introspection.ts +24 -22
  98. package/src/tools/landscape.ts +334 -181
  99. package/src/tools/level.ts +683 -182
  100. package/src/tools/lighting.ts +244 -123
  101. package/src/tools/materials.ts +114 -83
  102. package/src/tools/niagara.ts +87 -81
  103. package/src/tools/performance.ts +49 -88
  104. package/src/tools/physics.ts +393 -299
  105. package/src/tools/rc.ts +102 -24
  106. package/src/tools/sequence.ts +136 -28
  107. package/src/tools/ui.ts +101 -70
  108. package/src/tools/visual.ts +250 -29
  109. package/src/types/tool-types.ts +0 -9
  110. package/src/unreal-bridge.ts +658 -140
  111. package/src/utils/elicitation.ts +129 -0
  112. package/src/utils/error-handler.ts +4 -159
  113. package/src/utils/http.ts +16 -115
  114. package/src/utils/normalize.ts +20 -10
  115. package/src/utils/python-output.ts +351 -0
  116. package/src/utils/python.ts +3 -0
  117. package/src/utils/response-validator.ts +25 -2
  118. package/src/utils/result-helpers.ts +193 -0
  119. package/src/utils/safe-json.ts +0 -50
  120. package/src/utils/validation.ts +94 -7
  121. package/tests/run-unreal-tool-tests.mjs +720 -0
  122. package/tsconfig.json +2 -2
  123. package/dist/python-utils.d.ts +0 -29
  124. package/dist/python-utils.js +0 -54
  125. package/dist/types/index.d.ts +0 -323
  126. package/dist/types/index.js +0 -28
  127. package/dist/utils/cache-manager.d.ts +0 -64
  128. package/dist/utils/cache-manager.js +0 -176
  129. package/dist/utils/errors.d.ts +0 -133
  130. package/dist/utils/errors.js +0 -256
  131. package/src/python/editor_compat.py +0 -181
  132. package/src/python-utils.ts +0 -57
  133. package/src/types/index.ts +0 -414
  134. package/src/utils/cache-manager.ts +0 -213
  135. package/src/utils/errors.ts +0 -312
@@ -61,6 +61,5 @@ export declare class BuildEnvironmentAdvanced {
61
61
  minScale?: number;
62
62
  maxScale?: number;
63
63
  }): Promise<any>;
64
- private parseResponse;
65
64
  }
66
65
  //# sourceMappingURL=build_environment_advanced.d.ts.map
@@ -1,3 +1,4 @@
1
+ import { interpretStandardResult, coerceBoolean, coerceNumber, coerceString, coerceStringArray } from '../utils/result-helpers.js';
1
2
  /**
2
3
  * Advanced Build Environment Tools
3
4
  * Implements procedural terrain and foliage using documented Unreal Engine Python APIs
@@ -129,17 +130,69 @@ except Exception as e:
129
130
  print(f"RESULT:{json.dumps(result)}")
130
131
  `.trim();
131
132
  const response = await this.bridge.executePython(pythonScript);
132
- const output = this.parseResponse(response);
133
- const match = output.match(/RESULT:({.*})/);
134
- if (match) {
135
- try {
136
- return JSON.parse(match[1]);
133
+ const interpreted = interpretStandardResult(response, {
134
+ successMessage: `Created procedural terrain '${params.name}'`,
135
+ failureMessage: `Failed to create procedural terrain '${params.name}'`
136
+ });
137
+ if (!interpreted.success) {
138
+ const failure = {
139
+ success: false,
140
+ error: interpreted.error ?? interpreted.message,
141
+ message: interpreted.message
142
+ };
143
+ if (interpreted.warnings) {
144
+ failure.warnings = interpreted.warnings;
137
145
  }
138
- catch (_e) {
139
- return { success: false, error: 'Failed to parse result', details: output };
146
+ if (interpreted.details) {
147
+ failure.details = interpreted.details;
140
148
  }
149
+ if (interpreted.payload && Object.keys(interpreted.payload).length > 0) {
150
+ failure.payload = interpreted.payload;
151
+ }
152
+ return failure;
153
+ }
154
+ const payload = { ...interpreted.payload };
155
+ const actorName = coerceString(payload.actor_name) ?? coerceString(payload.actorName);
156
+ const vertices = coerceNumber(payload.vertices);
157
+ const triangles = coerceNumber(payload.triangles);
158
+ const subdivisions = coerceNumber(payload.subdivisions);
159
+ const sizeArray = Array.isArray(payload.size)
160
+ ? payload.size.map(entry => {
161
+ if (typeof entry === 'number' && Number.isFinite(entry)) {
162
+ return entry;
163
+ }
164
+ if (typeof entry === 'string') {
165
+ const parsed = Number(entry);
166
+ return Number.isFinite(parsed) ? parsed : undefined;
167
+ }
168
+ return undefined;
169
+ }).filter((entry) => typeof entry === 'number')
170
+ : undefined;
171
+ payload.success = true;
172
+ payload.message = interpreted.message;
173
+ if (actorName) {
174
+ payload.actor_name = actorName;
175
+ payload.actorName = actorName;
176
+ }
177
+ if (typeof vertices === 'number') {
178
+ payload.vertices = vertices;
179
+ }
180
+ if (typeof triangles === 'number') {
181
+ payload.triangles = triangles;
182
+ }
183
+ if (typeof subdivisions === 'number') {
184
+ payload.subdivisions = subdivisions;
185
+ }
186
+ if (sizeArray && sizeArray.length === 2) {
187
+ payload.size = sizeArray;
188
+ }
189
+ if (interpreted.warnings) {
190
+ payload.warnings = interpreted.warnings;
191
+ }
192
+ if (interpreted.details) {
193
+ payload.details = interpreted.details;
141
194
  }
142
- return { success: false, error: 'No result found', output };
195
+ return payload;
143
196
  }
144
197
  /**
145
198
  * Create procedural foliage using ProceduralFoliageSpawner
@@ -282,17 +335,64 @@ except Exception as e:
282
335
  print(f"RESULT:{json.dumps(result)}")
283
336
  `.trim();
284
337
  const response = await this.bridge.executePython(pythonScript);
285
- const output = this.parseResponse(response);
286
- const match = output.match(/RESULT:({.*})/);
287
- if (match) {
288
- try {
289
- return JSON.parse(match[1]);
338
+ const interpreted = interpretStandardResult(response, {
339
+ successMessage: `Created procedural foliage volume '${params.name}'`,
340
+ failureMessage: `Failed to create procedural foliage volume '${params.name}'`
341
+ });
342
+ if (!interpreted.success) {
343
+ const failure = {
344
+ success: false,
345
+ error: interpreted.error ?? interpreted.message,
346
+ message: interpreted.message
347
+ };
348
+ if (interpreted.warnings) {
349
+ failure.warnings = interpreted.warnings;
290
350
  }
291
- catch (_e) {
292
- return { success: false, error: 'Failed to parse result', details: output };
351
+ if (interpreted.details) {
352
+ failure.details = interpreted.details;
293
353
  }
354
+ if (interpreted.payload && Object.keys(interpreted.payload).length > 0) {
355
+ failure.payload = interpreted.payload;
356
+ }
357
+ return failure;
358
+ }
359
+ const payload = { ...interpreted.payload };
360
+ const volumeActor = coerceString(payload.volume_actor) ?? coerceString(payload.volumeActor);
361
+ const spawnerPath = coerceString(payload.spawner_path) ?? coerceString(payload.spawnerPath);
362
+ const foliageCount = coerceNumber(payload.foliage_types_count) ?? coerceNumber(payload.foliageTypesCount);
363
+ const resimulated = coerceBoolean(payload.resimulated);
364
+ const note = coerceString(payload.note);
365
+ const messages = coerceStringArray(payload.messages);
366
+ payload.success = true;
367
+ payload.message = interpreted.message;
368
+ if (volumeActor) {
369
+ payload.volume_actor = volumeActor;
370
+ payload.volumeActor = volumeActor;
371
+ }
372
+ if (spawnerPath) {
373
+ payload.spawner_path = spawnerPath;
374
+ payload.spawnerPath = spawnerPath;
375
+ }
376
+ if (typeof foliageCount === 'number') {
377
+ payload.foliage_types_count = foliageCount;
378
+ payload.foliageTypesCount = foliageCount;
379
+ }
380
+ if (typeof resimulated === 'boolean') {
381
+ payload.resimulated = resimulated;
382
+ }
383
+ if (note) {
384
+ payload.note = note;
385
+ }
386
+ if (messages && messages.length > 0) {
387
+ payload.messages = messages;
294
388
  }
295
- return { success: false, error: 'No result found', output };
389
+ if (interpreted.warnings) {
390
+ payload.warnings = interpreted.warnings;
391
+ }
392
+ if (interpreted.details) {
393
+ payload.details = interpreted.details;
394
+ }
395
+ return payload;
296
396
  }
297
397
  /**
298
398
  * Add foliage instances using InstancedFoliageActor
@@ -356,17 +456,43 @@ except Exception as e:
356
456
  print(f"RESULT:{json.dumps(result)}")
357
457
  `.trim();
358
458
  const response = await this.bridge.executePython(pythonScript);
359
- const output = this.parseResponse(response);
360
- const match = output.match(/RESULT:({.*})/);
361
- if (match) {
362
- try {
363
- return JSON.parse(match[1]);
459
+ const interpreted = interpretStandardResult(response, {
460
+ successMessage: 'Foliage instances added',
461
+ failureMessage: 'Failed to add foliage instances'
462
+ });
463
+ if (!interpreted.success) {
464
+ const failure = {
465
+ success: false,
466
+ error: interpreted.error ?? interpreted.message,
467
+ message: interpreted.message
468
+ };
469
+ if (interpreted.warnings) {
470
+ failure.warnings = interpreted.warnings;
364
471
  }
365
- catch (_e) {
366
- return { success: false, error: 'Failed to parse result', details: output };
472
+ if (interpreted.details) {
473
+ failure.details = interpreted.details;
367
474
  }
475
+ if (interpreted.payload && Object.keys(interpreted.payload).length > 0) {
476
+ failure.payload = interpreted.payload;
477
+ }
478
+ return failure;
479
+ }
480
+ const payload = { ...interpreted.payload };
481
+ const count = coerceNumber(payload.instances_count) ?? coerceNumber(payload.instancesCount);
482
+ const message = coerceString(payload.message) ?? interpreted.message;
483
+ payload.success = true;
484
+ payload.message = message;
485
+ if (typeof count === 'number') {
486
+ payload.instances_count = count;
487
+ payload.instancesCount = count;
368
488
  }
369
- return { success: false, error: 'No result found', output };
489
+ if (interpreted.warnings) {
490
+ payload.warnings = interpreted.warnings;
491
+ }
492
+ if (interpreted.details) {
493
+ payload.details = interpreted.details;
494
+ }
495
+ return payload;
370
496
  }
371
497
  /**
372
498
  * Create landscape grass type for automatic foliage on landscape
@@ -458,31 +584,50 @@ except Exception as e:
458
584
  print(f"RESULT:{json.dumps(result)}")
459
585
  `.trim();
460
586
  const response = await this.bridge.executePython(pythonScript);
461
- const output = this.parseResponse(response);
462
- const match = output.match(/RESULT:({.*})/);
463
- if (match) {
464
- try {
465
- return JSON.parse(match[1]);
587
+ const interpreted = interpretStandardResult(response, {
588
+ successMessage: `Created landscape grass type '${params.name}'`,
589
+ failureMessage: `Failed to create landscape grass type '${params.name}'`
590
+ });
591
+ if (!interpreted.success) {
592
+ const failure = {
593
+ success: false,
594
+ error: interpreted.error ?? interpreted.message,
595
+ message: interpreted.message
596
+ };
597
+ if (interpreted.warnings) {
598
+ failure.warnings = interpreted.warnings;
466
599
  }
467
- catch (_e) {
468
- return { success: false, error: 'Failed to parse result', details: output };
600
+ if (interpreted.details) {
601
+ failure.details = interpreted.details;
469
602
  }
470
- }
471
- return { success: false, error: 'No result found', output };
472
- }
473
- parseResponse(response) {
474
- if (response && typeof response === 'object') {
475
- if (response.LogOutput && Array.isArray(response.LogOutput)) {
476
- return response.LogOutput.map((log) => log.Output || '').join('');
477
- }
478
- else if (response.CommandResult) {
479
- return response.CommandResult;
480
- }
481
- else if (response.ReturnValue) {
482
- return JSON.stringify(response);
603
+ if (interpreted.payload && Object.keys(interpreted.payload).length > 0) {
604
+ failure.payload = interpreted.payload;
483
605
  }
606
+ return failure;
607
+ }
608
+ const payload = { ...interpreted.payload };
609
+ const assetPath = coerceString(payload.asset_path) ?? coerceString(payload.assetPath);
610
+ const note = coerceString(payload.note);
611
+ const messages = coerceStringArray(payload.messages);
612
+ payload.success = true;
613
+ payload.message = interpreted.message;
614
+ if (assetPath) {
615
+ payload.asset_path = assetPath;
616
+ payload.assetPath = assetPath;
617
+ }
618
+ if (note) {
619
+ payload.note = note;
620
+ }
621
+ if (messages && messages.length > 0) {
622
+ payload.messages = messages;
623
+ }
624
+ if (interpreted.warnings) {
625
+ payload.warnings = interpreted.warnings;
626
+ }
627
+ if (interpreted.details) {
628
+ payload.details = interpreted.details;
484
629
  }
485
- return typeof response === 'string' ? response : JSON.stringify(response);
630
+ return payload;
486
631
  }
487
632
  }
488
633
  //# sourceMappingURL=build_environment_advanced.js.map