unreal-engine-mcp-server 0.2.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.
Files changed (155) hide show
  1. package/.dockerignore +57 -0
  2. package/.env.production +25 -0
  3. package/.eslintrc.json +54 -0
  4. package/.github/workflows/publish-mcp.yml +75 -0
  5. package/Dockerfile +54 -0
  6. package/LICENSE +21 -0
  7. package/Public/icon.png +0 -0
  8. package/README.md +209 -0
  9. package/claude_desktop_config_example.json +13 -0
  10. package/dist/cli.d.ts +3 -0
  11. package/dist/cli.js +7 -0
  12. package/dist/index.d.ts +31 -0
  13. package/dist/index.js +484 -0
  14. package/dist/prompts/index.d.ts +14 -0
  15. package/dist/prompts/index.js +38 -0
  16. package/dist/python-utils.d.ts +29 -0
  17. package/dist/python-utils.js +54 -0
  18. package/dist/resources/actors.d.ts +13 -0
  19. package/dist/resources/actors.js +83 -0
  20. package/dist/resources/assets.d.ts +23 -0
  21. package/dist/resources/assets.js +245 -0
  22. package/dist/resources/levels.d.ts +17 -0
  23. package/dist/resources/levels.js +94 -0
  24. package/dist/tools/actors.d.ts +51 -0
  25. package/dist/tools/actors.js +459 -0
  26. package/dist/tools/animation.d.ts +196 -0
  27. package/dist/tools/animation.js +579 -0
  28. package/dist/tools/assets.d.ts +21 -0
  29. package/dist/tools/assets.js +304 -0
  30. package/dist/tools/audio.d.ts +170 -0
  31. package/dist/tools/audio.js +416 -0
  32. package/dist/tools/blueprint.d.ts +144 -0
  33. package/dist/tools/blueprint.js +652 -0
  34. package/dist/tools/build_environment_advanced.d.ts +66 -0
  35. package/dist/tools/build_environment_advanced.js +484 -0
  36. package/dist/tools/consolidated-tool-definitions.d.ts +2598 -0
  37. package/dist/tools/consolidated-tool-definitions.js +607 -0
  38. package/dist/tools/consolidated-tool-handlers.d.ts +2 -0
  39. package/dist/tools/consolidated-tool-handlers.js +1050 -0
  40. package/dist/tools/debug.d.ts +185 -0
  41. package/dist/tools/debug.js +265 -0
  42. package/dist/tools/editor.d.ts +88 -0
  43. package/dist/tools/editor.js +365 -0
  44. package/dist/tools/engine.d.ts +30 -0
  45. package/dist/tools/engine.js +36 -0
  46. package/dist/tools/foliage.d.ts +155 -0
  47. package/dist/tools/foliage.js +525 -0
  48. package/dist/tools/introspection.d.ts +98 -0
  49. package/dist/tools/introspection.js +683 -0
  50. package/dist/tools/landscape.d.ts +158 -0
  51. package/dist/tools/landscape.js +375 -0
  52. package/dist/tools/level.d.ts +110 -0
  53. package/dist/tools/level.js +362 -0
  54. package/dist/tools/lighting.d.ts +159 -0
  55. package/dist/tools/lighting.js +1179 -0
  56. package/dist/tools/materials.d.ts +34 -0
  57. package/dist/tools/materials.js +146 -0
  58. package/dist/tools/niagara.d.ts +145 -0
  59. package/dist/tools/niagara.js +289 -0
  60. package/dist/tools/performance.d.ts +163 -0
  61. package/dist/tools/performance.js +412 -0
  62. package/dist/tools/physics.d.ts +189 -0
  63. package/dist/tools/physics.js +784 -0
  64. package/dist/tools/rc.d.ts +110 -0
  65. package/dist/tools/rc.js +363 -0
  66. package/dist/tools/sequence.d.ts +112 -0
  67. package/dist/tools/sequence.js +675 -0
  68. package/dist/tools/tool-definitions.d.ts +4919 -0
  69. package/dist/tools/tool-definitions.js +891 -0
  70. package/dist/tools/tool-handlers.d.ts +47 -0
  71. package/dist/tools/tool-handlers.js +830 -0
  72. package/dist/tools/ui.d.ts +171 -0
  73. package/dist/tools/ui.js +337 -0
  74. package/dist/tools/visual.d.ts +29 -0
  75. package/dist/tools/visual.js +67 -0
  76. package/dist/types/env.d.ts +10 -0
  77. package/dist/types/env.js +18 -0
  78. package/dist/types/index.d.ts +323 -0
  79. package/dist/types/index.js +28 -0
  80. package/dist/types/tool-types.d.ts +274 -0
  81. package/dist/types/tool-types.js +13 -0
  82. package/dist/unreal-bridge.d.ts +126 -0
  83. package/dist/unreal-bridge.js +992 -0
  84. package/dist/utils/cache-manager.d.ts +64 -0
  85. package/dist/utils/cache-manager.js +176 -0
  86. package/dist/utils/error-handler.d.ts +66 -0
  87. package/dist/utils/error-handler.js +243 -0
  88. package/dist/utils/errors.d.ts +133 -0
  89. package/dist/utils/errors.js +256 -0
  90. package/dist/utils/http.d.ts +26 -0
  91. package/dist/utils/http.js +135 -0
  92. package/dist/utils/logger.d.ts +12 -0
  93. package/dist/utils/logger.js +32 -0
  94. package/dist/utils/normalize.d.ts +17 -0
  95. package/dist/utils/normalize.js +49 -0
  96. package/dist/utils/response-validator.d.ts +34 -0
  97. package/dist/utils/response-validator.js +121 -0
  98. package/dist/utils/safe-json.d.ts +4 -0
  99. package/dist/utils/safe-json.js +97 -0
  100. package/dist/utils/stdio-redirect.d.ts +2 -0
  101. package/dist/utils/stdio-redirect.js +20 -0
  102. package/dist/utils/validation.d.ts +50 -0
  103. package/dist/utils/validation.js +173 -0
  104. package/mcp-config-example.json +14 -0
  105. package/package.json +63 -0
  106. package/server.json +60 -0
  107. package/src/cli.ts +7 -0
  108. package/src/index.ts +543 -0
  109. package/src/prompts/index.ts +51 -0
  110. package/src/python/editor_compat.py +181 -0
  111. package/src/python-utils.ts +57 -0
  112. package/src/resources/actors.ts +92 -0
  113. package/src/resources/assets.ts +251 -0
  114. package/src/resources/levels.ts +83 -0
  115. package/src/tools/actors.ts +480 -0
  116. package/src/tools/animation.ts +713 -0
  117. package/src/tools/assets.ts +305 -0
  118. package/src/tools/audio.ts +548 -0
  119. package/src/tools/blueprint.ts +736 -0
  120. package/src/tools/build_environment_advanced.ts +526 -0
  121. package/src/tools/consolidated-tool-definitions.ts +619 -0
  122. package/src/tools/consolidated-tool-handlers.ts +1093 -0
  123. package/src/tools/debug.ts +368 -0
  124. package/src/tools/editor.ts +360 -0
  125. package/src/tools/engine.ts +32 -0
  126. package/src/tools/foliage.ts +652 -0
  127. package/src/tools/introspection.ts +778 -0
  128. package/src/tools/landscape.ts +523 -0
  129. package/src/tools/level.ts +410 -0
  130. package/src/tools/lighting.ts +1316 -0
  131. package/src/tools/materials.ts +148 -0
  132. package/src/tools/niagara.ts +312 -0
  133. package/src/tools/performance.ts +549 -0
  134. package/src/tools/physics.ts +924 -0
  135. package/src/tools/rc.ts +437 -0
  136. package/src/tools/sequence.ts +791 -0
  137. package/src/tools/tool-definitions.ts +907 -0
  138. package/src/tools/tool-handlers.ts +941 -0
  139. package/src/tools/ui.ts +499 -0
  140. package/src/tools/visual.ts +60 -0
  141. package/src/types/env.ts +27 -0
  142. package/src/types/index.ts +414 -0
  143. package/src/types/tool-types.ts +343 -0
  144. package/src/unreal-bridge.ts +1118 -0
  145. package/src/utils/cache-manager.ts +213 -0
  146. package/src/utils/error-handler.ts +320 -0
  147. package/src/utils/errors.ts +312 -0
  148. package/src/utils/http.ts +184 -0
  149. package/src/utils/logger.ts +30 -0
  150. package/src/utils/normalize.ts +54 -0
  151. package/src/utils/response-validator.ts +145 -0
  152. package/src/utils/safe-json.ts +112 -0
  153. package/src/utils/stdio-redirect.ts +18 -0
  154. package/src/utils/validation.ts +212 -0
  155. package/tsconfig.json +33 -0
package/dist/index.js ADDED
@@ -0,0 +1,484 @@
1
+ import 'dotenv/config';
2
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { Logger } from './utils/logger.js';
5
+ import { UnrealBridge } from './unreal-bridge.js';
6
+ import { AssetResources } from './resources/assets.js';
7
+ import { ActorResources } from './resources/actors.js';
8
+ import { LevelResources } from './resources/levels.js';
9
+ import { ActorTools } from './tools/actors.js';
10
+ import { AssetTools } from './tools/assets.js';
11
+ import { EditorTools } from './tools/editor.js';
12
+ import { MaterialTools } from './tools/materials.js';
13
+ import { AnimationTools } from './tools/animation.js';
14
+ import { PhysicsTools } from './tools/physics.js';
15
+ import { NiagaraTools } from './tools/niagara.js';
16
+ import { BlueprintTools } from './tools/blueprint.js';
17
+ import { LevelTools } from './tools/level.js';
18
+ import { LightingTools } from './tools/lighting.js';
19
+ import { LandscapeTools } from './tools/landscape.js';
20
+ import { FoliageTools } from './tools/foliage.js';
21
+ import { DebugVisualizationTools } from './tools/debug.js';
22
+ import { PerformanceTools } from './tools/performance.js';
23
+ import { AudioTools } from './tools/audio.js';
24
+ import { UITools } from './tools/ui.js';
25
+ import { RcTools } from './tools/rc.js';
26
+ import { SequenceTools } from './tools/sequence.js';
27
+ import { IntrospectionTools } from './tools/introspection.js';
28
+ import { VisualTools } from './tools/visual.js';
29
+ import { EngineTools } from './tools/engine.js';
30
+ import { toolDefinitions } from './tools/tool-definitions.js';
31
+ import { handleToolCall } from './tools/tool-handlers.js';
32
+ import { consolidatedToolDefinitions } from './tools/consolidated-tool-definitions.js';
33
+ import { handleConsolidatedToolCall } from './tools/consolidated-tool-handlers.js';
34
+ import { prompts } from './prompts/index.js';
35
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema } from '@modelcontextprotocol/sdk/types.js';
36
+ import { responseValidator } from './utils/response-validator.js';
37
+ import { ErrorHandler } from './utils/error-handler.js';
38
+ import { routeStdoutLogsToStderr } from './utils/stdio-redirect.js';
39
+ import { cleanObject } from './utils/safe-json.js';
40
+ const log = new Logger('UE-MCP');
41
+ // Ensure stdout remains JSON-only for MCP by routing logs to stderr unless opted out.
42
+ routeStdoutLogsToStderr();
43
+ const metrics = {
44
+ totalRequests: 0,
45
+ successfulRequests: 0,
46
+ failedRequests: 0,
47
+ averageResponseTime: 0,
48
+ responseTimes: [],
49
+ connectionStatus: 'disconnected',
50
+ lastHealthCheck: new Date(),
51
+ uptime: Date.now(),
52
+ recentErrors: []
53
+ };
54
+ // Configuration
55
+ const CONFIG = {
56
+ // Tool mode: true = consolidated (10 tools), false = individual (36+ tools)
57
+ USE_CONSOLIDATED_TOOLS: process.env.USE_CONSOLIDATED_TOOLS !== 'false',
58
+ // Connection retry settings
59
+ MAX_RETRY_ATTEMPTS: 3,
60
+ RETRY_DELAY_MS: 2000,
61
+ // Server info
62
+ SERVER_NAME: 'unreal-engine-mcp',
63
+ SERVER_VERSION: '0.2.1',
64
+ // Monitoring
65
+ HEALTH_CHECK_INTERVAL_MS: 30000 // 30 seconds
66
+ };
67
+ // Helper function to track performance
68
+ function trackPerformance(startTime, success) {
69
+ const responseTime = Date.now() - startTime;
70
+ metrics.totalRequests++;
71
+ if (success) {
72
+ metrics.successfulRequests++;
73
+ }
74
+ else {
75
+ metrics.failedRequests++;
76
+ }
77
+ // Keep last 100 response times for average calculation
78
+ metrics.responseTimes.push(responseTime);
79
+ if (metrics.responseTimes.length > 100) {
80
+ metrics.responseTimes.shift();
81
+ }
82
+ // Calculate average
83
+ metrics.averageResponseTime = metrics.responseTimes.reduce((a, b) => a + b, 0) / metrics.responseTimes.length;
84
+ }
85
+ // Health check function
86
+ async function performHealthCheck(bridge) {
87
+ try {
88
+ // Use a safe echo command that doesn't affect any settings
89
+ await bridge.executeConsoleCommand('echo MCP Server Health Check');
90
+ metrics.connectionStatus = 'connected';
91
+ metrics.lastHealthCheck = new Date();
92
+ return true;
93
+ }
94
+ catch (err1) {
95
+ // Fallback: minimal Python ping (if Python plugin is enabled)
96
+ try {
97
+ await bridge.executePython("import sys; sys.stdout.write('OK')");
98
+ metrics.connectionStatus = 'connected';
99
+ metrics.lastHealthCheck = new Date();
100
+ return true;
101
+ }
102
+ catch (err2) {
103
+ metrics.connectionStatus = 'error';
104
+ metrics.lastHealthCheck = new Date();
105
+ log.warn('Health check failed (console and python):', err1, err2);
106
+ return false;
107
+ }
108
+ }
109
+ }
110
+ export async function createServer() {
111
+ const bridge = new UnrealBridge();
112
+ // Initialize response validation with schemas
113
+ log.info('Initializing response validation...');
114
+ const toolDefs = CONFIG.USE_CONSOLIDATED_TOOLS ? consolidatedToolDefinitions : toolDefinitions;
115
+ toolDefs.forEach((tool) => {
116
+ if (tool.outputSchema) {
117
+ responseValidator.registerSchema(tool.name, tool.outputSchema);
118
+ }
119
+ });
120
+ log.info(`Registered ${responseValidator.getStats().totalSchemas} output schemas for validation`);
121
+ // Connect to UE5 Remote Control with retries and timeout
122
+ const connected = await bridge.tryConnect(CONFIG.MAX_RETRY_ATTEMPTS, 5000, // 5 second timeout per attempt
123
+ CONFIG.RETRY_DELAY_MS);
124
+ if (connected) {
125
+ metrics.connectionStatus = 'connected';
126
+ log.info('Successfully connected to Unreal Engine');
127
+ }
128
+ else {
129
+ log.warn('Could not connect to Unreal Engine after retries');
130
+ log.info('Server will start anyway - connection will be retried periodically');
131
+ log.info('Make sure Unreal Engine is running with Remote Control enabled');
132
+ metrics.connectionStatus = 'disconnected';
133
+ // Schedule automatic reconnection attempts
134
+ setInterval(async () => {
135
+ if (!bridge.isConnected) {
136
+ log.info('Attempting to reconnect to Unreal Engine...');
137
+ const reconnected = await bridge.tryConnect(1, 5000, 0); // Single attempt
138
+ if (reconnected) {
139
+ log.info('Reconnected to Unreal Engine successfully');
140
+ metrics.connectionStatus = 'connected';
141
+ }
142
+ }
143
+ }, 10000); // Try every 10 seconds
144
+ }
145
+ // Start periodic health checks
146
+ setInterval(() => {
147
+ performHealthCheck(bridge);
148
+ }, CONFIG.HEALTH_CHECK_INTERVAL_MS);
149
+ // Resources
150
+ const assetResources = new AssetResources(bridge);
151
+ const actorResources = new ActorResources(bridge);
152
+ const levelResources = new LevelResources(bridge);
153
+ // Tools
154
+ const actorTools = new ActorTools(bridge);
155
+ const assetTools = new AssetTools(bridge);
156
+ const editorTools = new EditorTools(bridge);
157
+ const materialTools = new MaterialTools(bridge);
158
+ const animationTools = new AnimationTools(bridge);
159
+ const physicsTools = new PhysicsTools(bridge);
160
+ const niagaraTools = new NiagaraTools(bridge);
161
+ const blueprintTools = new BlueprintTools(bridge);
162
+ const levelTools = new LevelTools(bridge);
163
+ const lightingTools = new LightingTools(bridge);
164
+ const landscapeTools = new LandscapeTools(bridge);
165
+ const foliageTools = new FoliageTools(bridge);
166
+ const debugTools = new DebugVisualizationTools(bridge);
167
+ const performanceTools = new PerformanceTools(bridge);
168
+ const audioTools = new AudioTools(bridge);
169
+ const uiTools = new UITools(bridge);
170
+ const rcTools = new RcTools(bridge);
171
+ const sequenceTools = new SequenceTools(bridge);
172
+ const introspectionTools = new IntrospectionTools(bridge);
173
+ const visualTools = new VisualTools(bridge);
174
+ const engineTools = new EngineTools(bridge);
175
+ const server = new Server({
176
+ name: CONFIG.SERVER_NAME,
177
+ version: CONFIG.SERVER_VERSION
178
+ }, {
179
+ capabilities: {
180
+ resources: {},
181
+ tools: {},
182
+ prompts: {},
183
+ logging: {}
184
+ }
185
+ });
186
+ // Handle resource listing
187
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
188
+ return {
189
+ resources: [
190
+ {
191
+ uri: 'ue://assets',
192
+ name: 'Project Assets',
193
+ description: 'List all assets in the project',
194
+ mimeType: 'application/json'
195
+ },
196
+ {
197
+ uri: 'ue://actors',
198
+ name: 'Level Actors',
199
+ description: 'List all actors in the current level',
200
+ mimeType: 'application/json'
201
+ },
202
+ {
203
+ uri: 'ue://level',
204
+ name: 'Current Level',
205
+ description: 'Information about the current level',
206
+ mimeType: 'application/json'
207
+ },
208
+ {
209
+ uri: 'ue://exposed',
210
+ name: 'Remote Control Exposed',
211
+ description: 'List all exposed properties via Remote Control',
212
+ mimeType: 'application/json'
213
+ },
214
+ {
215
+ uri: 'ue://health',
216
+ name: 'Health Status',
217
+ description: 'Server health and performance metrics',
218
+ mimeType: 'application/json'
219
+ },
220
+ {
221
+ uri: 'ue://version',
222
+ name: 'Engine Version',
223
+ description: 'Unreal Engine version and compatibility info',
224
+ mimeType: 'application/json'
225
+ }
226
+ ]
227
+ };
228
+ });
229
+ // Handle resource reading
230
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
231
+ const uri = request.params.uri;
232
+ if (uri === 'ue://assets') {
233
+ const list = await assetResources.list('/Game', true);
234
+ return {
235
+ contents: [{
236
+ uri,
237
+ mimeType: 'application/json',
238
+ text: JSON.stringify(list, null, 2)
239
+ }]
240
+ };
241
+ }
242
+ if (uri === 'ue://actors') {
243
+ const list = await actorResources.listActors();
244
+ return {
245
+ contents: [{
246
+ uri,
247
+ mimeType: 'application/json',
248
+ text: JSON.stringify(list, null, 2)
249
+ }]
250
+ };
251
+ }
252
+ if (uri === 'ue://level') {
253
+ const level = await levelResources.getCurrentLevel();
254
+ return {
255
+ contents: [{
256
+ uri,
257
+ mimeType: 'application/json',
258
+ text: JSON.stringify(level, null, 2)
259
+ }]
260
+ };
261
+ }
262
+ if (uri === 'ue://exposed') {
263
+ try {
264
+ const exposed = await bridge.getExposed();
265
+ return {
266
+ contents: [{
267
+ uri,
268
+ mimeType: 'application/json',
269
+ text: JSON.stringify(exposed, null, 2)
270
+ }]
271
+ };
272
+ }
273
+ catch {
274
+ return {
275
+ contents: [{
276
+ uri,
277
+ mimeType: 'text/plain',
278
+ text: 'Failed to get exposed properties. Ensure Remote Control is configured.'
279
+ }]
280
+ };
281
+ }
282
+ }
283
+ if (uri === 'ue://health') {
284
+ const uptimeMs = Date.now() - metrics.uptime;
285
+ // Query engine version and feature flags (best-effort)
286
+ let versionInfo = {};
287
+ let featureFlags = {};
288
+ try {
289
+ versionInfo = await bridge.getEngineVersion();
290
+ }
291
+ catch { }
292
+ try {
293
+ featureFlags = await bridge.getFeatureFlags();
294
+ }
295
+ catch { }
296
+ const health = {
297
+ status: metrics.connectionStatus,
298
+ uptime: Math.floor(uptimeMs / 1000),
299
+ performance: {
300
+ totalRequests: metrics.totalRequests,
301
+ successfulRequests: metrics.successfulRequests,
302
+ failedRequests: metrics.failedRequests,
303
+ successRate: metrics.totalRequests > 0 ?
304
+ (metrics.successfulRequests / metrics.totalRequests * 100).toFixed(2) + '%' : 'N/A',
305
+ averageResponseTime: Math.round(metrics.averageResponseTime) + 'ms'
306
+ },
307
+ lastHealthCheck: metrics.lastHealthCheck.toISOString(),
308
+ unrealConnection: {
309
+ status: bridge.isConnected ? 'connected' : 'disconnected',
310
+ host: process.env.UE_HOST || 'localhost',
311
+ httpPort: process.env.UE_RC_HTTP_PORT || 30010,
312
+ wsPort: process.env.UE_RC_WS_PORT || 30020,
313
+ engineVersion: versionInfo,
314
+ features: {
315
+ pythonEnabled: featureFlags.pythonEnabled === true,
316
+ subsystems: featureFlags.subsystems || {},
317
+ rcHttpReachable: bridge.isConnected
318
+ }
319
+ },
320
+ recentErrors: metrics.recentErrors.slice(-5)
321
+ };
322
+ return {
323
+ contents: [{
324
+ uri,
325
+ mimeType: 'application/json',
326
+ text: JSON.stringify(health, null, 2)
327
+ }]
328
+ };
329
+ }
330
+ if (uri === 'ue://version') {
331
+ const info = await bridge.getEngineVersion();
332
+ return {
333
+ contents: [{
334
+ uri,
335
+ mimeType: 'application/json',
336
+ text: JSON.stringify(info, null, 2)
337
+ }]
338
+ };
339
+ }
340
+ throw new Error(`Unknown resource: ${uri}`);
341
+ });
342
+ // Handle tool listing - switch between consolidated (10) or individual (36) tools
343
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
344
+ log.info(`Serving ${CONFIG.USE_CONSOLIDATED_TOOLS ? 'consolidated' : 'individual'} tools`);
345
+ return {
346
+ tools: CONFIG.USE_CONSOLIDATED_TOOLS ? consolidatedToolDefinitions : toolDefinitions
347
+ };
348
+ });
349
+ // Handle tool calls - switch between consolidated (10) or individual (36) tools
350
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
351
+ const { name, arguments: args } = request.params;
352
+ const startTime = Date.now();
353
+ // Create tools object for handler
354
+ const tools = {
355
+ actorTools,
356
+ assetTools,
357
+ materialTools,
358
+ editorTools,
359
+ animationTools,
360
+ physicsTools,
361
+ niagaraTools,
362
+ blueprintTools,
363
+ levelTools,
364
+ lightingTools,
365
+ landscapeTools,
366
+ foliageTools,
367
+ debugTools,
368
+ performanceTools,
369
+ audioTools,
370
+ uiTools,
371
+ rcTools,
372
+ sequenceTools,
373
+ introspectionTools,
374
+ visualTools,
375
+ engineTools,
376
+ bridge
377
+ };
378
+ // Use consolidated or individual handler based on configuration
379
+ try {
380
+ log.debug(`Executing tool: ${name}`);
381
+ let result;
382
+ if (CONFIG.USE_CONSOLIDATED_TOOLS) {
383
+ result = await handleConsolidatedToolCall(name, args, tools);
384
+ }
385
+ else {
386
+ result = await handleToolCall(name, args, tools);
387
+ }
388
+ log.debug(`Tool ${name} returned result`);
389
+ // Clean the result to remove circular references
390
+ result = cleanObject(result);
391
+ // Validate and enhance response
392
+ result = responseValidator.wrapResponse(name, result);
393
+ trackPerformance(startTime, true);
394
+ log.info(`Tool ${name} completed successfully in ${Date.now() - startTime}ms`);
395
+ // Log that we're returning the response
396
+ const responsePreview = JSON.stringify(result).substring(0, 100);
397
+ log.debug(`Returning response to MCP client: ${responsePreview}...`);
398
+ return result;
399
+ }
400
+ catch (error) {
401
+ trackPerformance(startTime, false);
402
+ // Use consistent error handling
403
+ const errorResponse = ErrorHandler.createErrorResponse(error, name, { ...args, scope: `tool-call/${name}` });
404
+ log.error(`Tool execution failed: ${name}`, errorResponse);
405
+ // Record error for health diagnostics
406
+ try {
407
+ metrics.recentErrors.push({
408
+ time: new Date().toISOString(),
409
+ scope: errorResponse.scope || `tool-call/${name}`,
410
+ type: errorResponse._debug?.errorType || 'UNKNOWN',
411
+ message: errorResponse.error || errorResponse.message || 'Unknown error',
412
+ retriable: Boolean(errorResponse.retriable)
413
+ });
414
+ if (metrics.recentErrors.length > 20)
415
+ metrics.recentErrors.splice(0, metrics.recentErrors.length - 20);
416
+ }
417
+ catch { }
418
+ return {
419
+ content: [{
420
+ type: 'text',
421
+ text: errorResponse.message || `Failed to execute ${name}`
422
+ }],
423
+ ...errorResponse
424
+ };
425
+ }
426
+ });
427
+ // Handle prompt listing
428
+ server.setRequestHandler(ListPromptsRequestSchema, async () => {
429
+ return {
430
+ prompts: prompts.map(p => ({
431
+ name: p.name,
432
+ description: p.description,
433
+ arguments: Object.entries(p.arguments || {}).map(([name, schema]) => ({
434
+ name,
435
+ description: schema.description,
436
+ required: schema.required || false
437
+ }))
438
+ }))
439
+ };
440
+ });
441
+ // Handle prompt retrieval
442
+ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
443
+ const prompt = prompts.find(p => p.name === request.params.name);
444
+ if (!prompt) {
445
+ throw new Error(`Unknown prompt: ${request.params.name}`);
446
+ }
447
+ // Return a template for the lighting setup
448
+ return {
449
+ messages: [
450
+ {
451
+ role: 'user',
452
+ content: {
453
+ type: 'text',
454
+ text: `Set up three-point lighting with ${request.params.arguments?.intensity || 'medium'} intensity`
455
+ }
456
+ }
457
+ ]
458
+ };
459
+ });
460
+ return { server, bridge };
461
+ }
462
+ export async function startStdioServer() {
463
+ const { server } = await createServer();
464
+ const transport = new StdioServerTransport();
465
+ // Add debugging for transport messages
466
+ const originalWrite = process.stdout.write;
467
+ process.stdout.write = function (...args) {
468
+ const message = args[0];
469
+ if (typeof message === 'string' && message.includes('jsonrpc')) {
470
+ log.debug(`Sending to client: ${message.substring(0, 200)}...`);
471
+ }
472
+ return originalWrite.apply(process.stdout, args);
473
+ };
474
+ await server.connect(transport);
475
+ log.info('Unreal Engine MCP Server started on stdio');
476
+ }
477
+ // Start the server when run directly
478
+ if (import.meta.url === `file://${process.argv[1].replace(/\\/g, '/')}`) {
479
+ startStdioServer().catch(error => {
480
+ console.error('Failed to start server:', error);
481
+ process.exit(1);
482
+ });
483
+ }
484
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,14 @@
1
+ export interface PromptArgument {
2
+ type: string;
3
+ description?: string;
4
+ enum?: string[];
5
+ default?: any;
6
+ required?: boolean;
7
+ }
8
+ export interface Prompt {
9
+ name: string;
10
+ description: string;
11
+ arguments?: Record<string, PromptArgument>;
12
+ }
13
+ export declare const prompts: Prompt[];
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,38 @@
1
+ export const prompts = [
2
+ {
3
+ name: 'setup_three_point_lighting',
4
+ description: 'Set up a basic three-point lighting rig around the current camera focus',
5
+ arguments: {
6
+ intensity: {
7
+ type: 'string',
8
+ enum: ['low', 'medium', 'high'],
9
+ default: 'medium',
10
+ description: 'Light intensity level'
11
+ }
12
+ }
13
+ },
14
+ {
15
+ name: 'create_fps_controller',
16
+ description: 'Create a first-person shooter character controller',
17
+ arguments: {
18
+ spawnLocation: {
19
+ type: 'object',
20
+ description: 'Location to spawn the controller',
21
+ required: false
22
+ }
23
+ }
24
+ },
25
+ {
26
+ name: 'setup_post_processing',
27
+ description: 'Configure post-processing volume with cinematic settings',
28
+ arguments: {
29
+ style: {
30
+ type: 'string',
31
+ enum: ['cinematic', 'realistic', 'stylized', 'noir'],
32
+ default: 'cinematic',
33
+ description: 'Visual style preset'
34
+ }
35
+ }
36
+ }
37
+ ];
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Python Utilities for Modern Unreal Engine API
3
+ *
4
+ * This module provides Python code snippets that use the modern
5
+ * Unreal Engine Python API instead of deprecated functions.
6
+ */
7
+ export declare class PythonUtils {
8
+ /**
9
+ * Get all actors in the level using modern API
10
+ * @returns Python code to get all level actors
11
+ */
12
+ static getAllLevelActors(): string;
13
+ /**
14
+ * Get selected actors using modern API
15
+ * @returns Python code to get selected actors
16
+ */
17
+ static getSelectedActors(): string;
18
+ /**
19
+ * Spawn actor from class using modern API
20
+ * @returns Python code to spawn actor
21
+ */
22
+ static spawnActorFromClass(): string;
23
+ /**
24
+ * Get a safe way to access actors
25
+ * @returns Python code with modern API
26
+ */
27
+ static getSafeActorAccess(): string;
28
+ }
29
+ //# sourceMappingURL=python-utils.d.ts.map
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Python Utilities for Modern Unreal Engine API
3
+ *
4
+ * This module provides Python code snippets that use the modern
5
+ * Unreal Engine Python API instead of deprecated functions.
6
+ */
7
+ export class PythonUtils {
8
+ /**
9
+ * Get all actors in the level using modern API
10
+ * @returns Python code to get all level actors
11
+ */
12
+ static getAllLevelActors() {
13
+ return `
14
+ # Use modern EditorActorSubsystem instead of deprecated EditorLevelLibrary
15
+ editor_actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
16
+ actors = editor_actor_subsystem.get_all_level_actors()
17
+ `.trim();
18
+ }
19
+ /**
20
+ * Get selected actors using modern API
21
+ * @returns Python code to get selected actors
22
+ */
23
+ static getSelectedActors() {
24
+ return `
25
+ editor_actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
26
+ selected_actors = editor_actor_subsystem.get_selected_level_actors()
27
+ `.trim();
28
+ }
29
+ /**
30
+ * Spawn actor from class using modern API
31
+ * @returns Python code to spawn actor
32
+ */
33
+ static spawnActorFromClass() {
34
+ return `
35
+ editor_actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
36
+ # Use spawn_actor_from_class for spawning
37
+ `.trim();
38
+ }
39
+ /**
40
+ * Get a safe way to access actors
41
+ * @returns Python code with modern API
42
+ */
43
+ static getSafeActorAccess() {
44
+ return `
45
+ # Use modern API
46
+ try:
47
+ editor_actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
48
+ actors = editor_actor_subsystem.get_all_level_actors() if editor_actor_subsystem else []
49
+ except:
50
+ actors = []
51
+ `.trim();
52
+ }
53
+ }
54
+ //# sourceMappingURL=python-utils.js.map
@@ -0,0 +1,13 @@
1
+ import { UnrealBridge } from '../unreal-bridge.js';
2
+ export declare class ActorResources {
3
+ private bridge;
4
+ private cache;
5
+ private readonly CACHE_TTL_MS;
6
+ constructor(bridge: UnrealBridge);
7
+ private getFromCache;
8
+ private setCache;
9
+ listActors(): Promise<any>;
10
+ getActorByName(actorName: string): Promise<any>;
11
+ getActorTransform(actorPath: string): Promise<any>;
12
+ }
13
+ //# sourceMappingURL=actors.d.ts.map