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
package/.env.production CHANGED
@@ -19,7 +19,7 @@ LOG_LEVEL=info
19
19
 
20
20
  # Server Settings
21
21
  SERVER_NAME=unreal-engine-mcp
22
- SERVER_VERSION=0.3.1
22
+ SERVER_VERSION=0.4.3
23
23
 
24
24
  # Connection Settings
25
25
  MAX_RETRY_ATTEMPTS=3
@@ -0,0 +1,45 @@
1
+ # Unreal MCP – AI Agent Guide
2
+
3
+ ## Architecture essentials
4
+ - `src/index.ts` boots the Model Context Protocol server, registers output schemas, and connects to Unreal only when a tool/resource call requires it via `ensureConnectedOnDemand`.
5
+ - Consolidated tool routing lives in `src/tools/consolidated-tool-definitions.ts` and `src/tools/consolidated-tool-handlers.ts`, shrinking the surface to 13 multi-action tools that wrap the specialized classes in `src/tools/*`.
6
+ - The Unreal bridge (`src/unreal-bridge.ts`) owns HTTP/WS transport, command throttling, health checks, and graceful fallbacks so callers never talk to Remote Control directly.
7
+ - Health/metrics (connection status, latency, recent errors) are tracked in `index.ts` and exposed through the `ue://health` resource for quick diagnostics.
8
+
9
+ ## Key directories
10
+ - `src/tools/` – domain-specific helpers (actors, landscapes, audio, niagara, etc.) that emit Python scripts or console commands.
11
+ - `src/resources/` – read-only listings (assets, actors, levels) with caching and path normalization utilities.
12
+ - `src/utils/` – shared helpers: validation/coercion, `escapePythonString`, result interpretation, AJV-powered response validation, stdout redirection.
13
+ - `docs/unreal-tool-test-cases.md` + `tests/run-unreal-tool-tests.mjs` – declarative test matrix consumed by the automated harness; reports land in `tests/reports/` with time-stamped JSON.
14
+
15
+ ## Tool workflow expectations
16
+ - New tool actions must be declared in the consolidated definitions (input/output schema) and wired in the handler switch before delegating to the relevant class in `src/tools/*`.
17
+ - Always return plain JS objects with `success`, `message`, `error`, and optional `warnings` arrays; let `responseValidator.wrapResponse` handle MCP formatting.
18
+ - Shared helpers like `interpretStandardResult` and `cleanObject` keep payloads JSON-safe—use them instead of ad-hoc parsing.
19
+ - When validating inputs, reuse `ensureVector3`, `ensureRotation`, and other utilities from `src/utils/validation.ts` to keep error messaging consistent.
20
+
21
+ ## Unreal bridge & Python usage
22
+ - Prefer `bridge.executePythonWithResult` for multi-line scripts; it captures stdout, parses the last `RESULT:` block, and falls back to the console `py` command when plugins are missing.
23
+ - Python snippets should print a single `RESULT:` JSON payload and sanitize inputs with `escapePythonString` or typed coercion helpers.
24
+ - `UnrealBridge.httpCall` enforces timeouts, queues commands, and blocks dangerous console strings (`buildpaths`, `rebuildnavigation`, etc.); avoid bypassing it with raw HTTP.
25
+ - Auto-reconnect is disabled by default—tool handlers should call `ensureConnectedOnDemand()` instead of assuming a live session.
26
+
27
+ ## Response & validation conventions
28
+ - Every consolidated tool has an AJV schema; mismatches surface as `_validation` warnings in responses and appear in stderr logs.
29
+ - For Python-driven tools, use the `interpretResult`/`interpretStandardResult` helpers to turn raw bridge output into the normalized `{ success, message, error, warnings }` shape.
30
+ - Keep warning text short and user-facing—the test harness searches response strings for keywords to grade scenarios.
31
+
32
+ ## Build & test workflow
33
+ - `npm run build` compiles TypeScript to `dist/`; `npm run lint` enforces the ESLint rules shipped in `.eslintrc.json`.
34
+ - `npm run test:tools` launches the compiled server via stdio, iterates the Markdown-defined cases, and writes a JSON run summary under `tests/reports/`.
35
+ - Override harness behavior with env vars like `UNREAL_MCP_SERVER_CMD`, `UNREAL_MCP_SERVER_ARGS`, `UNREAL_MCP_TEST_DOC`, or `UNREAL_MCP_FBX_FILE` when Unreal lives elsewhere.
36
+
37
+ ## Unreal environment & configuration
38
+ - Ensure the project enables: Remote Control API, Remote Control Web Interface, Python Editor Script Plugin, Editor Scripting Utilities, Sequencer, and Level Sequence Editor before invoking automation.
39
+ - Default connection settings come from `UE_HOST`, `UE_RC_HTTP_PORT`, and `UE_RC_WS_PORT` (see README for the `DefaultEngine.ini` snippet that unlocks remote execution).
40
+ - Tools defensively return `UE_NOT_CONNECTED` or asset-not-found errors; keep that contract when extending behavior so clients can retry intelligently.
41
+
42
+ ## Debugging & monitoring
43
+ - Logs are routed to stderr via `routeStdoutLogsToStderr()` to keep MCP stdout JSON-only—check the terminal for detailed stack traces or validation warnings.
44
+ - Use the `ue://health` and `ue://version` resources to confirm bridge connectivity, last health-check timestamp, and detected engine version.
45
+ - The command queue in `UnrealBridge` spaces out console/Python traffic; heavy operations may need explicit `__callTimeoutMs` in the payload to extend HTTP timeouts.
@@ -49,7 +49,7 @@ jobs:
49
49
  - name: Update server.json version
50
50
  run: |
51
51
  VERSION=${{ steps.version.outputs.version }}
52
- jq --arg v "$VERSION" '.version = $v | .packages[] |= if .registry_type == "npm" then .version = $v else . end' server.json > tmp && mv tmp server.json
52
+ jq --arg v "$VERSION" '.version = $v | .packages[] |= if .registryType == "npm" then .version = $v else . end' server.json > tmp && mv tmp server.json
53
53
  echo "Updated server.json:"
54
54
  cat server.json
55
55
 
package/README.md CHANGED
@@ -4,6 +4,7 @@
4
4
  [![NPM Package](https://img.shields.io/npm/v/unreal-engine-mcp-server)](https://www.npmjs.com/package/unreal-engine-mcp-server)
5
5
  [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-TypeScript-blue)](https://github.com/modelcontextprotocol/sdk)
6
6
  [![Unreal Engine](https://img.shields.io/badge/Unreal%20Engine-5.0--5.6-orange)](https://www.unrealengine.com/)
7
+ [![MCP Registry](https://img.shields.io/badge/MCP%20Registry-Published-green)](https://registry.modelcontextprotocol.io/)
7
8
 
8
9
  A comprehensive Model Context Protocol (MCP) server that enables AI assistants to control Unreal Engine via Remote Control API. Built with TypeScript and designed for game development automation.
9
10
 
@@ -24,11 +25,26 @@ A comprehensive Model Context Protocol (MCP) server that enables AI assistants t
24
25
  ### Prerequisites
25
26
  - Node.js 18+
26
27
  - Unreal Engine 5.0-5.6
27
- - Required UE Plugins:
28
- - Remote Control
29
- - Web Remote Control
30
- - Python Script Plugin
31
- - Editor Scripting Utilities
28
+ - Required UE Plugins (enable via **Edit ▸ Plugins**):
29
+ - **Remote Control API** – core Remote Control HTTP/WS endpoints
30
+ - **Remote Control Web Interface** – enables WebSocket bridge used by this server
31
+ - **Python Editor Script Plugin** – exposes Python runtime for automation
32
+ - **Editor Scripting Utilities** – unlocks Editor Actor/Asset subsystems used throughout the tools
33
+ - **Sequencer** *(built-in)* – keep enabled for cinematic tools
34
+ - **Level Sequence Editor** – required for `manage_sequence` operations
35
+
36
+ > 💡 After toggling any plugin, restart the editor to finalize activation. Keep `Editor Scripting Utilities` and `Python Editor Script Plugin` enabled prior to connecting, otherwise many subsystem-based tools (actor spawning, audio, foliage, UI widgets) will refuse to run for safety.
37
+
38
+ ### Plugin feature map
39
+
40
+ | Plugin | Location | Used By | Notes |
41
+ |--------|----------|---------|-------|
42
+ | Remote Control API | Developer Tools ▸ Remote Control | All tools | Provides HTTP/WS endpoints consumed by the MCP bridge |
43
+ | Remote Control Web Interface | Developer Tools ▸ Remote Control | All tools | Enables persistent WebSocket session |
44
+ | Python Editor Script Plugin | Scripting | Landscapes, lighting, audio, physics, sequences, UI | Required for every Python execution path |
45
+ | Editor Scripting Utilities | Scripting | Actors, foliage, assets, landscapes, UI | Supplies Editor Actor/Asset subsystems in UE5.6 |
46
+ | Sequencer | Built-in | Sequencer tools | Ensure not disabled in project settings |
47
+ | Level Sequence Editor | Animation | Sequencer tools | Activate before calling `manage_sequence` operations |
32
48
 
33
49
  ### Installation
34
50
 
@@ -114,7 +130,7 @@ Then enable Python execution in: Edit > Project Settings > Plugins > Remote Cont
114
130
  }
115
131
  ```
116
132
 
117
- ## Available Tools (13 Consolidated)
133
+ ## Available Tools (13)
118
134
 
119
135
  | Tool | Description |
120
136
  |------|-------------|
@@ -161,7 +177,6 @@ Blueprints, Materials, Textures, Static/Skeletal Meshes, Levels, Sounds, Particl
161
177
  UE_HOST=127.0.0.1 # Unreal Engine host
162
178
  UE_RC_HTTP_PORT=30010 # Remote Control HTTP port
163
179
  UE_RC_WS_PORT=30020 # Remote Control WebSocket port
164
- USE_CONSOLIDATED_TOOLS=true # Use 13 consolidated tools (false = 37 individual)
165
180
  LOG_LEVEL=info # debug | info | warn | error
166
181
  ```
167
182
 
package/dist/index.js CHANGED
@@ -17,6 +17,7 @@ import { BlueprintTools } from './tools/blueprint.js';
17
17
  import { LevelTools } from './tools/level.js';
18
18
  import { LightingTools } from './tools/lighting.js';
19
19
  import { LandscapeTools } from './tools/landscape.js';
20
+ import { BuildEnvironmentAdvanced } from './tools/build_environment_advanced.js';
20
21
  import { FoliageTools } from './tools/foliage.js';
21
22
  import { DebugVisualizationTools } from './tools/debug.js';
22
23
  import { PerformanceTools } from './tools/performance.js';
@@ -27,8 +28,6 @@ import { SequenceTools } from './tools/sequence.js';
27
28
  import { IntrospectionTools } from './tools/introspection.js';
28
29
  import { VisualTools } from './tools/visual.js';
29
30
  import { EngineTools } from './tools/engine.js';
30
- import { toolDefinitions } from './tools/tool-definitions.js';
31
- import { handleToolCall } from './tools/tool-handlers.js';
32
31
  import { consolidatedToolDefinitions } from './tools/consolidated-tool-definitions.js';
33
32
  import { handleConsolidatedToolCall } from './tools/consolidated-tool-handlers.js';
34
33
  import { prompts } from './prompts/index.js';
@@ -37,6 +36,7 @@ import { responseValidator } from './utils/response-validator.js';
37
36
  import { ErrorHandler } from './utils/error-handler.js';
38
37
  import { routeStdoutLogsToStderr } from './utils/stdio-redirect.js';
39
38
  import { cleanObject } from './utils/safe-json.js';
39
+ import { createElicitationHelper } from './utils/elicitation.js';
40
40
  const log = new Logger('UE-MCP');
41
41
  // Ensure stdout remains JSON-only for MCP by routing logs to stderr unless opted out.
42
42
  routeStdoutLogsToStderr();
@@ -56,14 +56,13 @@ let healthCheckTimer;
56
56
  let lastHealthSuccessAt = 0;
57
57
  // Configuration
58
58
  const CONFIG = {
59
- // Tool mode: true = consolidated (13 tools), false = individual (36+ tools)
60
- USE_CONSOLIDATED_TOOLS: process.env.USE_CONSOLIDATED_TOOLS !== 'false',
59
+ // Tooling: use consolidated tools only (13 tools)
61
60
  // Connection retry settings
62
61
  MAX_RETRY_ATTEMPTS: 3,
63
62
  RETRY_DELAY_MS: 2000,
64
63
  // Server info
65
64
  SERVER_NAME: 'unreal-engine-mcp',
66
- SERVER_VERSION: '0.3.1',
65
+ SERVER_VERSION: '0.4.3',
67
66
  // Monitoring
68
67
  HEALTH_CHECK_INTERVAL_MS: 30000 // 30 seconds
69
68
  };
@@ -123,7 +122,7 @@ export async function createServer() {
123
122
  bridge.setAutoReconnectEnabled(false);
124
123
  // Initialize response validation with schemas
125
124
  log.debug('Initializing response validation...');
126
- const toolDefs = CONFIG.USE_CONSOLIDATED_TOOLS ? consolidatedToolDefinitions : toolDefinitions;
125
+ const toolDefs = consolidatedToolDefinitions;
127
126
  toolDefs.forEach((tool) => {
128
127
  if (tool.outputSchema) {
129
128
  responseValidator.registerSchema(tool.name, tool.outputSchema);
@@ -196,6 +195,7 @@ export async function createServer() {
196
195
  const lightingTools = new LightingTools(bridge);
197
196
  const landscapeTools = new LandscapeTools(bridge);
198
197
  const foliageTools = new FoliageTools(bridge);
198
+ const buildEnvAdvanced = new BuildEnvironmentAdvanced(bridge);
199
199
  const debugTools = new DebugVisualizationTools(bridge);
200
200
  const performanceTools = new PerformanceTools(bridge);
201
201
  const audioTools = new AudioTools(bridge);
@@ -212,10 +212,34 @@ export async function createServer() {
212
212
  capabilities: {
213
213
  resources: {},
214
214
  tools: {},
215
- prompts: {},
216
- logging: {}
215
+ prompts: {
216
+ listChanged: false
217
+ },
218
+ logging: {},
219
+ elicitation: {}
217
220
  }
218
221
  });
222
+ // Optional elicitation helper – used only if client supports it.
223
+ const elicitation = createElicitationHelper(server, log);
224
+ const defaultElicitationTimeoutMs = elicitation.getDefaultTimeoutMs();
225
+ const createNotConnectedResponse = (toolName) => {
226
+ const payload = {
227
+ success: false,
228
+ error: 'UE_NOT_CONNECTED',
229
+ message: 'Unreal Engine is not connected (after 3 attempts). Please open UE and try again.',
230
+ retriable: false,
231
+ scope: `tool-call/${toolName}`
232
+ };
233
+ return responseValidator.wrapResponse(toolName, {
234
+ ...payload,
235
+ content: [
236
+ {
237
+ type: 'text',
238
+ text: JSON.stringify(payload, null, 2)
239
+ }
240
+ ]
241
+ });
242
+ };
219
243
  // Handle resource listing
220
244
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
221
245
  return {
@@ -394,29 +418,23 @@ export async function createServer() {
394
418
  }
395
419
  throw new Error(`Unknown resource: ${uri}`);
396
420
  });
397
- // Handle tool listing - switch between consolidated (13) or individual (36) tools
421
+ // Handle tool listing - consolidated tools only
398
422
  server.setRequestHandler(ListToolsRequestSchema, async () => {
399
- log.info(`Serving ${CONFIG.USE_CONSOLIDATED_TOOLS ? 'consolidated' : 'individual'} tools`);
423
+ log.info('Serving consolidated tools');
400
424
  return {
401
- tools: CONFIG.USE_CONSOLIDATED_TOOLS ? consolidatedToolDefinitions : toolDefinitions
425
+ tools: consolidatedToolDefinitions
402
426
  };
403
427
  });
404
- // Handle tool calls - switch between consolidated (13) or individual (36) tools
428
+ // Handle tool calls - consolidated tools only (13)
405
429
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
406
- const { name, arguments: args } = request.params;
430
+ const { name } = request.params;
431
+ let args = request.params.arguments || {};
407
432
  const startTime = Date.now();
408
433
  // Ensure connection only when needed, with 3 attempts
409
434
  const connected = await ensureConnectedOnDemand();
410
435
  if (!connected) {
411
- const notConnected = {
412
- content: [{ type: 'text', text: 'Unreal Engine is not connected (after 3 attempts). Please open UE and try again.' }],
413
- success: false,
414
- error: 'UE_NOT_CONNECTED',
415
- retriable: false,
416
- scope: `tool-call/${name}`
417
- };
418
436
  trackPerformance(startTime, false);
419
- return notConnected;
437
+ return createNotConnectedResponse(name);
420
438
  }
421
439
  // Create tools object for handler
422
440
  const tools = {
@@ -432,6 +450,7 @@ export async function createServer() {
432
450
  lightingTools,
433
451
  landscapeTools,
434
452
  foliageTools,
453
+ buildEnvAdvanced,
435
454
  debugTools,
436
455
  performanceTools,
437
456
  audioTools,
@@ -441,18 +460,76 @@ export async function createServer() {
441
460
  introspectionTools,
442
461
  visualTools,
443
462
  engineTools,
463
+ // Elicitation (client-optional)
464
+ elicit: elicitation.elicit,
465
+ supportsElicitation: elicitation.supports,
466
+ elicitationTimeoutMs: defaultElicitationTimeoutMs,
467
+ // Resources for listing and info
468
+ assetResources,
469
+ actorResources,
470
+ levelResources,
444
471
  bridge
445
472
  };
446
- // Use consolidated or individual handler based on configuration
473
+ // Execute consolidated tool handler
447
474
  try {
448
475
  log.debug(`Executing tool: ${name}`);
449
- let result;
450
- if (CONFIG.USE_CONSOLIDATED_TOOLS) {
451
- result = await handleConsolidatedToolCall(name, args, tools);
476
+ // Opportunistic generic elicitation for missing primitive required fields
477
+ try {
478
+ const toolDef = consolidatedToolDefinitions.find(t => t.name === name);
479
+ const inputSchema = toolDef?.inputSchema;
480
+ const elicitFn = tools.elicit;
481
+ if (inputSchema && typeof elicitFn === 'function') {
482
+ const props = inputSchema.properties || {};
483
+ const required = Array.isArray(inputSchema.required) ? inputSchema.required : [];
484
+ const missing = required.filter((k) => {
485
+ const v = args[k];
486
+ if (v === undefined || v === null)
487
+ return true;
488
+ if (typeof v === 'string' && v.trim() === '')
489
+ return true;
490
+ return false;
491
+ });
492
+ // Build a flat primitive-only schema subset per MCP Elicitation rules
493
+ const primitiveProps = {};
494
+ for (const k of missing) {
495
+ const p = props[k];
496
+ if (!p || typeof p !== 'object')
497
+ continue;
498
+ const t = (p.type || '').toString();
499
+ const isEnum = Array.isArray(p.enum);
500
+ if (t === 'string' || t === 'number' || t === 'integer' || t === 'boolean' || isEnum) {
501
+ primitiveProps[k] = {
502
+ type: t || (isEnum ? 'string' : undefined),
503
+ title: p.title,
504
+ description: p.description,
505
+ enum: p.enum,
506
+ enumNames: p.enumNames,
507
+ minimum: p.minimum,
508
+ maximum: p.maximum,
509
+ minLength: p.minLength,
510
+ maxLength: p.maxLength,
511
+ pattern: p.pattern,
512
+ format: p.format,
513
+ default: p.default
514
+ };
515
+ }
516
+ }
517
+ if (Object.keys(primitiveProps).length > 0) {
518
+ const elicitOptions = { fallback: async () => ({ ok: false, error: 'missing-params' }) };
519
+ if (typeof tools.elicitationTimeoutMs === 'number' && Number.isFinite(tools.elicitationTimeoutMs)) {
520
+ elicitOptions.timeoutMs = tools.elicitationTimeoutMs;
521
+ }
522
+ const elicitRes = await elicitFn(`Provide missing parameters for ${name}`, { type: 'object', properties: primitiveProps, required: Object.keys(primitiveProps) }, elicitOptions);
523
+ if (elicitRes && elicitRes.ok && elicitRes.value) {
524
+ args = { ...args, ...elicitRes.value };
525
+ }
526
+ }
527
+ }
452
528
  }
453
- else {
454
- result = await handleToolCall(name, args, tools);
529
+ catch (e) {
530
+ log.debug('Generic elicitation prefill skipped', { err: e?.message || String(e) });
455
531
  }
532
+ let result = await handleConsolidatedToolCall(name, args, tools);
456
533
  log.debug(`Tool ${name} returned result`);
457
534
  // Clean the result to remove circular references
458
535
  result = cleanObject(result);
@@ -483,13 +560,23 @@ export async function createServer() {
483
560
  metrics.recentErrors.splice(0, metrics.recentErrors.length - 20);
484
561
  }
485
562
  catch { }
486
- return {
563
+ const sanitizedError = cleanObject(errorResponse);
564
+ let errorText = '';
565
+ try {
566
+ errorText = JSON.stringify(sanitizedError, null, 2);
567
+ }
568
+ catch {
569
+ errorText = sanitizedError.message || errorResponse.message || `Failed to execute ${name}`;
570
+ }
571
+ const wrappedError = {
572
+ ...sanitizedError,
573
+ isError: true,
487
574
  content: [{
488
575
  type: 'text',
489
- text: errorResponse.message || `Failed to execute ${name}`
490
- }],
491
- ...errorResponse
576
+ text: errorText
577
+ }]
492
578
  };
579
+ return responseValidator.wrapResponse(name, wrappedError);
493
580
  }
494
581
  });
495
582
  // Handle prompt listing
@@ -498,11 +585,21 @@ export async function createServer() {
498
585
  prompts: prompts.map(p => ({
499
586
  name: p.name,
500
587
  description: p.description,
501
- arguments: Object.entries(p.arguments || {}).map(([name, schema]) => ({
502
- name,
503
- description: schema.description,
504
- required: schema.required || false
505
- }))
588
+ arguments: Object.entries(p.arguments || {}).map(([name, schema]) => {
589
+ const meta = {};
590
+ if (schema.type)
591
+ meta.type = schema.type;
592
+ if (schema.enum)
593
+ meta.enum = schema.enum;
594
+ if (schema.default !== undefined)
595
+ meta.default = schema.default;
596
+ return {
597
+ name,
598
+ description: schema.description,
599
+ required: schema.required ?? false,
600
+ ...(Object.keys(meta).length ? { _meta: meta } : {})
601
+ };
602
+ })
506
603
  }))
507
604
  };
508
605
  });
@@ -512,17 +609,11 @@ export async function createServer() {
512
609
  if (!prompt) {
513
610
  throw new Error(`Unknown prompt: ${request.params.name}`);
514
611
  }
515
- // Return a template for the lighting setup
612
+ const args = (request.params.arguments || {});
613
+ const messages = prompt.build(args);
516
614
  return {
517
- messages: [
518
- {
519
- role: 'user',
520
- content: {
521
- type: 'text',
522
- text: `Set up three-point lighting with ${request.params.arguments?.intensity || 'medium'} intensity`
523
- }
524
- }
525
- ]
615
+ description: prompt.description,
616
+ messages
526
617
  };
527
618
  });
528
619
  return { server, bridge };
@@ -2,13 +2,20 @@ export interface PromptArgument {
2
2
  type: string;
3
3
  description?: string;
4
4
  enum?: string[];
5
- default?: any;
5
+ default?: unknown;
6
6
  required?: boolean;
7
7
  }
8
- export interface Prompt {
8
+ export interface PromptTemplate {
9
9
  name: string;
10
10
  description: string;
11
11
  arguments?: Record<string, PromptArgument>;
12
+ build: (args: Record<string, unknown>) => Array<{
13
+ role: 'user' | 'assistant';
14
+ content: {
15
+ type: 'text';
16
+ text: string;
17
+ };
18
+ }>;
12
19
  }
13
- export declare const prompts: Prompt[];
20
+ export declare const prompts: PromptTemplate[];
14
21
  //# sourceMappingURL=index.d.ts.map