unreal-engine-mcp-server 0.3.1 → 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 (144) 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 +22 -7
  5. package/dist/index.js +137 -46
  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.d.ts +3 -2
  11. package/dist/resources/assets.js +117 -109
  12. package/dist/resources/levels.d.ts +21 -3
  13. package/dist/resources/levels.js +31 -56
  14. package/dist/tools/actors.d.ts +3 -14
  15. package/dist/tools/actors.js +246 -302
  16. package/dist/tools/animation.d.ts +57 -102
  17. package/dist/tools/animation.js +429 -450
  18. package/dist/tools/assets.d.ts +13 -2
  19. package/dist/tools/assets.js +58 -46
  20. package/dist/tools/audio.d.ts +22 -13
  21. package/dist/tools/audio.js +467 -121
  22. package/dist/tools/blueprint.d.ts +32 -13
  23. package/dist/tools/blueprint.js +699 -448
  24. package/dist/tools/build_environment_advanced.d.ts +0 -1
  25. package/dist/tools/build_environment_advanced.js +236 -87
  26. package/dist/tools/consolidated-tool-definitions.d.ts +232 -15
  27. package/dist/tools/consolidated-tool-definitions.js +124 -255
  28. package/dist/tools/consolidated-tool-handlers.js +749 -766
  29. package/dist/tools/debug.d.ts +72 -10
  30. package/dist/tools/debug.js +170 -36
  31. package/dist/tools/editor.d.ts +9 -2
  32. package/dist/tools/editor.js +30 -44
  33. package/dist/tools/foliage.d.ts +34 -15
  34. package/dist/tools/foliage.js +97 -107
  35. package/dist/tools/introspection.js +19 -21
  36. package/dist/tools/landscape.d.ts +1 -2
  37. package/dist/tools/landscape.js +311 -168
  38. package/dist/tools/level.d.ts +3 -28
  39. package/dist/tools/level.js +642 -192
  40. package/dist/tools/lighting.d.ts +14 -3
  41. package/dist/tools/lighting.js +236 -123
  42. package/dist/tools/materials.d.ts +25 -7
  43. package/dist/tools/materials.js +102 -79
  44. package/dist/tools/niagara.d.ts +10 -12
  45. package/dist/tools/niagara.js +74 -94
  46. package/dist/tools/performance.d.ts +12 -4
  47. package/dist/tools/performance.js +38 -79
  48. package/dist/tools/physics.d.ts +34 -10
  49. package/dist/tools/physics.js +364 -292
  50. package/dist/tools/rc.js +98 -24
  51. package/dist/tools/sequence.d.ts +1 -0
  52. package/dist/tools/sequence.js +146 -24
  53. package/dist/tools/ui.d.ts +31 -4
  54. package/dist/tools/ui.js +83 -66
  55. package/dist/tools/visual.d.ts +11 -0
  56. package/dist/tools/visual.js +245 -30
  57. package/dist/types/tool-types.d.ts +0 -6
  58. package/dist/types/tool-types.js +1 -8
  59. package/dist/unreal-bridge.d.ts +32 -2
  60. package/dist/unreal-bridge.js +621 -127
  61. package/dist/utils/elicitation.d.ts +57 -0
  62. package/dist/utils/elicitation.js +104 -0
  63. package/dist/utils/error-handler.d.ts +0 -33
  64. package/dist/utils/error-handler.js +4 -111
  65. package/dist/utils/http.d.ts +2 -22
  66. package/dist/utils/http.js +12 -75
  67. package/dist/utils/normalize.d.ts +4 -4
  68. package/dist/utils/normalize.js +15 -7
  69. package/dist/utils/python-output.d.ts +18 -0
  70. package/dist/utils/python-output.js +290 -0
  71. package/dist/utils/python.d.ts +2 -0
  72. package/dist/utils/python.js +4 -0
  73. package/dist/utils/response-validator.d.ts +6 -1
  74. package/dist/utils/response-validator.js +66 -13
  75. package/dist/utils/result-helpers.d.ts +27 -0
  76. package/dist/utils/result-helpers.js +147 -0
  77. package/dist/utils/safe-json.d.ts +0 -2
  78. package/dist/utils/safe-json.js +0 -43
  79. package/dist/utils/validation.d.ts +16 -0
  80. package/dist/utils/validation.js +70 -7
  81. package/mcp-config-example.json +2 -2
  82. package/package.json +11 -10
  83. package/server.json +37 -14
  84. package/src/index.ts +146 -50
  85. package/src/prompts/index.ts +211 -13
  86. package/src/resources/actors.ts +59 -44
  87. package/src/resources/assets.ts +123 -102
  88. package/src/resources/levels.ts +37 -47
  89. package/src/tools/actors.ts +269 -313
  90. package/src/tools/animation.ts +556 -539
  91. package/src/tools/assets.ts +59 -45
  92. package/src/tools/audio.ts +507 -113
  93. package/src/tools/blueprint.ts +778 -462
  94. package/src/tools/build_environment_advanced.ts +312 -106
  95. package/src/tools/consolidated-tool-definitions.ts +136 -267
  96. package/src/tools/consolidated-tool-handlers.ts +871 -795
  97. package/src/tools/debug.ts +179 -38
  98. package/src/tools/editor.ts +35 -37
  99. package/src/tools/foliage.ts +110 -104
  100. package/src/tools/introspection.ts +24 -22
  101. package/src/tools/landscape.ts +334 -181
  102. package/src/tools/level.ts +683 -182
  103. package/src/tools/lighting.ts +244 -123
  104. package/src/tools/materials.ts +114 -83
  105. package/src/tools/niagara.ts +87 -81
  106. package/src/tools/performance.ts +49 -88
  107. package/src/tools/physics.ts +393 -299
  108. package/src/tools/rc.ts +103 -25
  109. package/src/tools/sequence.ts +157 -30
  110. package/src/tools/ui.ts +101 -70
  111. package/src/tools/visual.ts +250 -29
  112. package/src/types/tool-types.ts +0 -9
  113. package/src/unreal-bridge.ts +658 -140
  114. package/src/utils/elicitation.ts +129 -0
  115. package/src/utils/error-handler.ts +4 -159
  116. package/src/utils/http.ts +16 -115
  117. package/src/utils/normalize.ts +20 -10
  118. package/src/utils/python-output.ts +351 -0
  119. package/src/utils/python.ts +3 -0
  120. package/src/utils/response-validator.ts +68 -17
  121. package/src/utils/result-helpers.ts +193 -0
  122. package/src/utils/safe-json.ts +0 -50
  123. package/src/utils/validation.ts +94 -7
  124. package/tests/run-unreal-tool-tests.mjs +720 -0
  125. package/tsconfig.json +2 -2
  126. package/dist/python-utils.d.ts +0 -29
  127. package/dist/python-utils.js +0 -54
  128. package/dist/tools/tool-definitions.d.ts +0 -4919
  129. package/dist/tools/tool-definitions.js +0 -1065
  130. package/dist/tools/tool-handlers.d.ts +0 -47
  131. package/dist/tools/tool-handlers.js +0 -863
  132. package/dist/types/index.d.ts +0 -323
  133. package/dist/types/index.js +0 -28
  134. package/dist/utils/cache-manager.d.ts +0 -64
  135. package/dist/utils/cache-manager.js +0 -176
  136. package/dist/utils/errors.d.ts +0 -133
  137. package/dist/utils/errors.js +0 -256
  138. package/src/python/editor_compat.py +0 -181
  139. package/src/python-utils.ts +0 -57
  140. package/src/tools/tool-definitions.ts +0 -1081
  141. package/src/tools/tool-handlers.ts +0 -973
  142. package/src/types/index.ts +0 -414
  143. package/src/utils/cache-manager.ts +0 -213
  144. package/src/utils/errors.ts +0 -312
@@ -2,6 +2,8 @@
2
2
  * Validation and sanitization utilities for Unreal Engine assets
3
3
  */
4
4
 
5
+ import { toRotTuple, toVec3Tuple } from './normalize.js';
6
+
5
7
  /**
6
8
  * Maximum path length allowed in Unreal Engine
7
9
  */
@@ -78,13 +80,27 @@ export function sanitizePath(path: string): string {
78
80
  return '/Game';
79
81
  }
80
82
 
83
+ // Normalize slashes
84
+ path = path.replace(/\\/g, '/');
85
+
81
86
  // Ensure path starts with /
82
87
  if (!path.startsWith('/')) {
83
88
  path = `/${path}`;
84
89
  }
85
90
 
86
91
  // Split path into segments and sanitize each
87
- const segments = path.split('/').filter(s => s.length > 0);
92
+ let segments = path.split('/').filter(s => s.length > 0);
93
+
94
+ if (segments.length === 0) {
95
+ return '/Game';
96
+ }
97
+
98
+ // Ensure the first segment is a valid root (Game, Engine, Script, Temp)
99
+ const ROOTS = new Set(['Game', 'Engine', 'Script', 'Temp']);
100
+ if (!ROOTS.has(segments[0])) {
101
+ segments = ['Game', ...segments];
102
+ }
103
+
88
104
  const sanitizedSegments = segments.map(segment => {
89
105
  // Don't sanitize Game, Engine, or other root folders
90
106
  if (['Game', 'Engine', 'Script', 'Temp'].includes(segment)) {
@@ -174,10 +190,14 @@ export function resolveSkeletalMeshPath(input: string): string | null {
174
190
 
175
191
  // Common skeleton to mesh mappings
176
192
  const skeletonToMeshMap: { [key: string]: string } = {
177
- '/Game/Mannequin/Character/Mesh/UE4_Mannequin_Skeleton': '/Game/Characters/Mannequins/Meshes/SKM_Manny',
178
- '/Game/Characters/Mannequins/Meshes/SK_Mannequin': '/Game/Characters/Mannequins/Meshes/SKM_Manny',
179
- '/Game/Mannequin/Character/Mesh/SK_Mannequin': '/Game/Characters/Mannequins/Meshes/SKM_Manny',
180
- '/Game/Characters/Mannequin_UE4/Meshes/UE4_Mannequin_Skeleton': '/Game/Characters/Mannequins/Meshes/SKM_Quinn',
193
+ '/Game/Mannequin/Character/Mesh/UE4_Mannequin_Skeleton': '/Game/Characters/Mannequins/Meshes/SKM_Manny_Simple',
194
+ '/Game/Characters/Mannequins/Meshes/SK_Mannequin': '/Game/Characters/Mannequins/Meshes/SKM_Manny_Simple',
195
+ '/Game/Mannequin/Character/Mesh/SK_Mannequin': '/Game/Characters/Mannequins/Meshes/SKM_Manny_Simple',
196
+ '/Game/Characters/Mannequin_UE4/Meshes/UE4_Mannequin_Skeleton': '/Game/Characters/Mannequins/Meshes/SKM_Quinn_Simple',
197
+ '/Game/Characters/Mannequins/Skeletons/UE5_Mannequin_Skeleton': '/Game/Characters/Mannequins/Meshes/SKM_Manny_Simple',
198
+ '/Game/Characters/Mannequins/Skeletons/UE5_Female_Mannequin_Skeleton': '/Game/Characters/Mannequins/Meshes/SKM_Quinn_Simple',
199
+ '/Game/Characters/Mannequins/Skeletons/UE5_Manny_Skeleton': '/Game/Characters/Mannequins/Meshes/SKM_Manny_Simple',
200
+ '/Game/Characters/Mannequins/Skeletons/UE5_Quinn_Skeleton': '/Game/Characters/Mannequins/Meshes/SKM_Quinn_Simple'
181
201
  };
182
202
 
183
203
  // Check if this is a known skeleton path
@@ -189,8 +209,19 @@ export function resolveSkeletalMeshPath(input: string): string | null {
189
209
  if (input.includes('_Skeleton')) {
190
210
  // Try common replacements
191
211
  let meshPath = input.replace('_Skeleton', '');
192
- meshPath = meshPath.replace('/SK_', '/SKM_');
193
- meshPath = meshPath.replace('UE4_Mannequin', 'SKM_Manny');
212
+ // Mapping for replacements
213
+ const replacements: { [key: string]: string } = {
214
+ '/SK_': '/SKM_',
215
+ 'UE4_Mannequin': 'SKM_Manny',
216
+ 'UE5_Mannequin': 'SKM_Manny',
217
+ 'UE5_Manny': 'SKM_Manny',
218
+ 'UE5_Quinn': 'SKM_Quinn'
219
+ };
220
+ // Apply all replacements using regex
221
+ meshPath = meshPath.replace(
222
+ new RegExp(Object.keys(replacements).join('|'), 'g'),
223
+ match => replacements[match]
224
+ );
194
225
  return meshPath;
195
226
  }
196
227
 
@@ -210,3 +241,59 @@ export function resolveSkeletalMeshPath(input: string): string | null {
210
241
  export async function concurrencyDelay(ms: number = 100): Promise<void> {
211
242
  return new Promise(resolve => setTimeout(resolve, ms));
212
243
  }
244
+
245
+ /**
246
+ * Ensure the provided value is a finite number within optional bounds.
247
+ * @throws if the value is not a finite number or violates bounds
248
+ */
249
+ export function validateNumber(
250
+ value: unknown,
251
+ label: string,
252
+ {
253
+ min,
254
+ max,
255
+ allowZero = true
256
+ }: { min?: number; max?: number; allowZero?: boolean } = {}
257
+ ): number {
258
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
259
+ throw new Error(`Invalid ${label}: expected a finite number`);
260
+ }
261
+
262
+ if (!allowZero && value === 0) {
263
+ throw new Error(`Invalid ${label}: zero is not allowed`);
264
+ }
265
+
266
+ if (typeof min === 'number' && value < min) {
267
+ throw new Error(`Invalid ${label}: must be >= ${min}`);
268
+ }
269
+
270
+ if (typeof max === 'number' && value > max) {
271
+ throw new Error(`Invalid ${label}: must be <= ${max}`);
272
+ }
273
+
274
+ return value;
275
+ }
276
+
277
+ /**
278
+ * Validate an array (tuple) of finite numbers, preserving the original shape.
279
+ * @throws if the tuple has the wrong length or contains invalid values
280
+ */
281
+ export function ensureVector3(value: unknown, label: string): [number, number, number] {
282
+ const tuple = toVec3Tuple(value);
283
+ if (!tuple) {
284
+ throw new Error(`Invalid ${label}: expected an object with x,y,z or an array of 3 numbers`);
285
+ }
286
+ return tuple;
287
+ }
288
+
289
+ export function ensureColorRGB(value: unknown, label: string): [number, number, number] {
290
+ return ensureVector3(value, label);
291
+ }
292
+
293
+ export function ensureRotation(value: unknown, label: string): [number, number, number] {
294
+ const tuple = toRotTuple(value);
295
+ if (!tuple) {
296
+ throw new Error(`Invalid ${label}: expected an object with pitch,yaw,roll or an array of 3 numbers`);
297
+ }
298
+ return tuple;
299
+ }