unreal-engine-mcp-server 0.5.0 → 0.5.2
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.
- package/.env.example +1 -1
- package/.github/release-drafter-config.yml +51 -0
- package/.github/workflows/greetings.yml +5 -1
- package/.github/workflows/labeler.yml +2 -1
- package/.github/workflows/publish-mcp.yml +2 -4
- package/.github/workflows/release-drafter.yml +3 -2
- package/.github/workflows/release.yml +3 -3
- package/CHANGELOG.md +109 -0
- package/CONTRIBUTING.md +1 -1
- package/GEMINI.md +115 -0
- package/Public/Plugin_setup_guide.mp4 +0 -0
- package/README.md +166 -200
- package/dist/automation/bridge.d.ts +1 -2
- package/dist/automation/bridge.js +24 -23
- package/dist/automation/connection-manager.d.ts +1 -0
- package/dist/automation/connection-manager.js +10 -0
- package/dist/automation/message-handler.js +5 -4
- package/dist/automation/request-tracker.d.ts +4 -0
- package/dist/automation/request-tracker.js +11 -3
- package/dist/config.d.ts +0 -1
- package/dist/config.js +0 -1
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +4 -0
- package/dist/graphql/loaders.d.ts +64 -0
- package/dist/graphql/loaders.js +117 -0
- package/dist/graphql/resolvers.d.ts +3 -3
- package/dist/graphql/resolvers.js +33 -30
- package/dist/graphql/server.js +3 -1
- package/dist/graphql/types.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +13 -2
- package/dist/server-setup.d.ts +0 -1
- package/dist/server-setup.js +0 -40
- package/dist/tools/actors.d.ts +58 -24
- package/dist/tools/actors.js +22 -6
- package/dist/tools/assets.d.ts +19 -71
- package/dist/tools/assets.js +28 -22
- package/dist/tools/base-tool.d.ts +4 -4
- package/dist/tools/base-tool.js +1 -1
- package/dist/tools/blueprint.d.ts +45 -61
- package/dist/tools/blueprint.js +43 -14
- package/dist/tools/consolidated-tool-definitions.js +2 -1
- package/dist/tools/consolidated-tool-handlers.js +96 -110
- package/dist/tools/dynamic-handler-registry.d.ts +11 -9
- package/dist/tools/dynamic-handler-registry.js +17 -95
- package/dist/tools/editor.d.ts +19 -193
- package/dist/tools/editor.js +11 -2
- package/dist/tools/environment.d.ts +8 -14
- package/dist/tools/foliage.d.ts +18 -143
- package/dist/tools/foliage.js +4 -2
- package/dist/tools/handlers/actor-handlers.d.ts +1 -1
- package/dist/tools/handlers/actor-handlers.js +14 -13
- package/dist/tools/handlers/asset-handlers.js +454 -454
- package/dist/tools/handlers/sequence-handlers.d.ts +1 -1
- package/dist/tools/handlers/sequence-handlers.js +24 -13
- package/dist/tools/introspection.d.ts +1 -1
- package/dist/tools/introspection.js +1 -1
- package/dist/tools/landscape.d.ts +16 -116
- package/dist/tools/landscape.js +7 -3
- package/dist/tools/level.d.ts +22 -103
- package/dist/tools/level.js +26 -18
- package/dist/tools/lighting.d.ts +54 -7
- package/dist/tools/lighting.js +9 -5
- package/dist/tools/materials.d.ts +1 -1
- package/dist/tools/materials.js +5 -1
- package/dist/tools/niagara.js +37 -2
- package/dist/tools/performance.d.ts +0 -1
- package/dist/tools/performance.js +0 -1
- package/dist/tools/physics.js +5 -1
- package/dist/tools/sequence.d.ts +24 -24
- package/dist/tools/sequence.js +13 -0
- package/dist/tools/ui.d.ts +0 -2
- package/dist/types/automation-responses.d.ts +115 -0
- package/dist/types/automation-responses.js +2 -0
- package/dist/types/responses.d.ts +249 -0
- package/dist/types/responses.js +2 -0
- package/dist/types/tool-interfaces.d.ts +135 -135
- package/dist/types/tool-types.d.ts +2 -0
- package/dist/unreal-bridge.js +4 -4
- package/dist/utils/command-validator.js +7 -5
- package/dist/utils/error-handler.d.ts +24 -2
- package/dist/utils/error-handler.js +58 -23
- package/dist/utils/normalize.d.ts +7 -4
- package/dist/utils/normalize.js +12 -10
- package/dist/utils/path-security.d.ts +2 -0
- package/dist/utils/path-security.js +24 -0
- package/dist/utils/response-factory.d.ts +4 -4
- package/dist/utils/response-factory.js +15 -21
- package/dist/utils/response-validator.js +88 -73
- package/dist/utils/unreal-command-queue.d.ts +2 -0
- package/dist/utils/unreal-command-queue.js +8 -1
- package/docs/Migration-Guide-v0.5.0.md +1 -9
- package/docs/handler-mapping.md +4 -2
- package/docs/testing-guide.md +2 -2
- package/package.json +12 -6
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSubsystem.cpp +298 -33
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AnimationHandlers.cpp +7 -8
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintGraphHandlers.cpp +229 -319
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers.cpp +98 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EffectHandlers.cpp +24 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EnvironmentHandlers.cpp +96 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LightingHandlers.cpp +52 -5
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ProcessRequest.cpp +5 -268
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequenceHandlers.cpp +57 -2
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpConnectionManager.cpp +0 -1
- package/scripts/run-all-tests.mjs +25 -20
- package/server.json +3 -2
- package/src/automation/bridge.ts +27 -25
- package/src/automation/connection-manager.ts +18 -0
- package/src/automation/message-handler.ts +33 -8
- package/src/automation/request-tracker.ts +39 -7
- package/src/config.ts +1 -1
- package/src/constants.ts +7 -0
- package/src/graphql/loaders.ts +244 -0
- package/src/graphql/resolvers.ts +47 -49
- package/src/graphql/server.ts +3 -1
- package/src/graphql/types.ts +3 -0
- package/src/index.ts +15 -2
- package/src/resources/assets.ts +5 -4
- package/src/server/tool-registry.ts +3 -3
- package/src/server-setup.ts +3 -37
- package/src/tools/actors.ts +77 -44
- package/src/tools/animation.ts +1 -0
- package/src/tools/assets.ts +76 -65
- package/src/tools/base-tool.ts +3 -3
- package/src/tools/blueprint.ts +170 -104
- package/src/tools/consolidated-tool-definitions.ts +2 -1
- package/src/tools/consolidated-tool-handlers.ts +129 -150
- package/src/tools/dynamic-handler-registry.ts +22 -140
- package/src/tools/editor.ts +43 -29
- package/src/tools/environment.ts +21 -27
- package/src/tools/foliage.ts +28 -25
- package/src/tools/handlers/actor-handlers.ts +16 -17
- package/src/tools/handlers/asset-handlers.ts +484 -484
- package/src/tools/handlers/sequence-handlers.ts +85 -62
- package/src/tools/introspection.ts +7 -7
- package/src/tools/landscape.ts +34 -28
- package/src/tools/level.ts +100 -80
- package/src/tools/lighting.ts +25 -20
- package/src/tools/materials.ts +9 -3
- package/src/tools/niagara.ts +44 -2
- package/src/tools/performance.ts +1 -2
- package/src/tools/physics.ts +7 -1
- package/src/tools/sequence.ts +42 -26
- package/src/tools/ui.ts +1 -3
- package/src/types/automation-responses.ts +119 -0
- package/src/types/responses.ts +355 -0
- package/src/types/tool-interfaces.ts +135 -135
- package/src/types/tool-types.ts +4 -0
- package/src/unreal-bridge.ts +71 -26
- package/src/utils/command-validator.ts +47 -5
- package/src/utils/error-handler.ts +128 -45
- package/src/utils/normalize.test.ts +162 -0
- package/src/utils/normalize.ts +38 -16
- package/src/utils/path-security.ts +43 -0
- package/src/utils/response-factory.ts +29 -24
- package/src/utils/response-validator.ts +103 -87
- package/src/utils/safe-json.test.ts +90 -0
- package/src/utils/unreal-command-queue.ts +13 -1
- package/src/utils/validation.test.ts +184 -0
- package/tests/test-animation.mjs +358 -33
- package/tests/test-asset-graph.mjs +311 -0
- package/tests/test-audio.mjs +314 -116
- package/tests/test-behavior-tree.mjs +327 -144
- package/tests/test-blueprint-graph.mjs +343 -12
- package/tests/test-control-editor.mjs +85 -53
- package/tests/test-graphql.mjs +58 -8
- package/tests/test-input.mjs +349 -0
- package/tests/test-inspect.mjs +291 -61
- package/tests/test-landscape.mjs +304 -48
- package/tests/test-lighting.mjs +428 -0
- package/tests/test-manage-level.mjs +70 -51
- package/tests/test-performance.mjs +539 -0
- package/tests/test-sequence.mjs +82 -46
- package/tests/test-system.mjs +72 -33
- package/tests/test-wasm.mjs +98 -8
- package/vitest.config.ts +35 -0
- package/.github/release-drafter.yml +0 -148
- package/dist/prompts/index.d.ts +0 -21
- package/dist/prompts/index.js +0 -217
- package/dist/tools/blueprint/helpers.d.ts +0 -29
- package/dist/tools/blueprint/helpers.js +0 -182
- package/src/prompts/index.ts +0 -249
- package/src/tools/blueprint/helpers.ts +0 -189
- package/tests/test-blueprint-events.mjs +0 -35
- package/tests/test-extra-tools.mjs +0 -38
- package/tests/test-render.mjs +0 -33
- package/tests/test-search-assets.mjs +0 -66
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { cleanObject } from '../utils/safe-json.js';
|
|
2
2
|
import { Logger } from '../utils/logger.js';
|
|
3
3
|
import { ResponseFactory } from '../utils/response-factory.js';
|
|
4
|
+
import { toolRegistry } from './dynamic-handler-registry.js';
|
|
4
5
|
import { executeAutomationRequest, requireAction } from './handlers/common-handlers.js';
|
|
5
6
|
import { handleAssetTools } from './handlers/asset-handlers.js';
|
|
6
7
|
import { handleActorTools } from './handlers/actor-handlers.js';
|
|
@@ -19,8 +20,6 @@ import { handleAudioTools } from './handlers/audio-handlers.js';
|
|
|
19
20
|
import { handleLightingTools } from './handlers/lighting-handlers.js';
|
|
20
21
|
import { handlePerformanceTools } from './handlers/performance-handlers.js';
|
|
21
22
|
import { handleInputTools } from './handlers/input-handlers.js';
|
|
22
|
-
import { getDynamicHandlerForTool } from './dynamic-handler-registry.js';
|
|
23
|
-
import { consolidatedToolDefinitions } from './consolidated-tool-definitions.js';
|
|
24
23
|
const MATERIAL_GRAPH_ACTION_MAP = {
|
|
25
24
|
add_material_node: 'add_node',
|
|
26
25
|
connect_material_pins: 'connect_pins',
|
|
@@ -92,105 +91,103 @@ function normalizeToolCall(name, args) {
|
|
|
92
91
|
args
|
|
93
92
|
};
|
|
94
93
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
if (isMaterialGraphAction(action)) {
|
|
103
|
-
const subAction = MATERIAL_GRAPH_ACTION_MAP[action] || action;
|
|
104
|
-
return await handleGraphTools('manage_material_graph', subAction, args, tools);
|
|
105
|
-
}
|
|
106
|
-
if (isBehaviorTreeGraphAction(action)) {
|
|
107
|
-
const subAction = BEHAVIOR_TREE_ACTION_MAP[action] || action;
|
|
108
|
-
return await handleGraphTools('manage_behavior_tree', subAction, args, tools);
|
|
109
|
-
}
|
|
110
|
-
return await handleAssetTools(action, args, tools);
|
|
94
|
+
function registerDefaultHandlers() {
|
|
95
|
+
toolRegistry.register('manage_asset', async (args, tools) => {
|
|
96
|
+
const action = args.subAction || args.action || requireAction(args);
|
|
97
|
+
if (['create_render_target', 'nanite_rebuild_mesh'].includes(action)) {
|
|
98
|
+
const payload = { ...args, subAction: action };
|
|
99
|
+
return cleanObject(await executeAutomationRequest(tools, 'manage_render', payload, `Automation bridge not available for ${action}`));
|
|
111
100
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
const graphActions = ['create_node', 'delete_node', 'connect_pins', 'break_pin_links', 'set_node_property', 'create_reroute_node', 'get_node_details', 'get_graph_details', 'get_pin_details'];
|
|
117
|
-
if (graphActions.includes(action)) {
|
|
118
|
-
return await handleGraphTools('manage_blueprint_graph', action, args, tools);
|
|
119
|
-
}
|
|
120
|
-
return await handleBlueprintTools(action, args, tools);
|
|
101
|
+
if (isMaterialGraphAction(action)) {
|
|
102
|
+
const subAction = MATERIAL_GRAPH_ACTION_MAP[action] || action;
|
|
103
|
+
return await handleGraphTools('manage_material_graph', subAction, args, tools);
|
|
121
104
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (action === 'simulate_input') {
|
|
126
|
-
const payload = { ...args, subAction: action };
|
|
127
|
-
return cleanObject(await executeAutomationRequest(tools, 'manage_ui', payload, 'Automation bridge not available'));
|
|
128
|
-
}
|
|
129
|
-
return await handleEditorTools(action, args, tools);
|
|
105
|
+
if (isBehaviorTreeGraphAction(action)) {
|
|
106
|
+
const subAction = BEHAVIOR_TREE_ACTION_MAP[action] || action;
|
|
107
|
+
return await handleGraphTools('manage_behavior_tree', subAction, args, tools);
|
|
130
108
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
return await
|
|
109
|
+
return await handleAssetTools(action, args, tools);
|
|
110
|
+
});
|
|
111
|
+
toolRegistry.register('manage_blueprint', async (args, tools) => {
|
|
112
|
+
const action = args.action || requireAction(args);
|
|
113
|
+
if (action === 'get_blueprint') {
|
|
114
|
+
return await handleBlueprintGet(args, tools);
|
|
137
115
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (isNiagaraGraphAction(action)) {
|
|
142
|
-
const isInstanceOp = action === 'set_niagara_parameter' && (args.actorName || (args.systemName && !args.assetPath && !args.systemPath));
|
|
143
|
-
if (isInstanceOp) {
|
|
144
|
-
return await handleEffectTools(action, args, tools);
|
|
145
|
-
}
|
|
146
|
-
const subAction = NIAGARA_GRAPH_ACTION_MAP[action] || action;
|
|
147
|
-
return await handleGraphTools('manage_niagara_graph', subAction, args, tools);
|
|
148
|
-
}
|
|
149
|
-
return await handleEffectTools(action, args, tools);
|
|
116
|
+
const graphActions = ['create_node', 'delete_node', 'connect_pins', 'break_pin_links', 'set_node_property', 'create_reroute_node', 'get_node_details', 'get_graph_details', 'get_pin_details'];
|
|
117
|
+
if (graphActions.includes(action)) {
|
|
118
|
+
return await handleGraphTools('manage_blueprint_graph', action, args, tools);
|
|
150
119
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return cleanObject(await executeAutomationRequest(tools, 'manage_logs', { ...args, subAction: action }, 'Bridge unavailable'));
|
|
162
|
-
if (action === 'spawn_category')
|
|
163
|
-
return cleanObject(await executeAutomationRequest(tools, 'manage_debug', { ...args, subAction: action }, 'Bridge unavailable'));
|
|
164
|
-
if (action === 'start_session')
|
|
165
|
-
return cleanObject(await executeAutomationRequest(tools, 'manage_insights', { ...args, subAction: action }, 'Bridge unavailable'));
|
|
166
|
-
if (action === 'lumen_update_scene')
|
|
167
|
-
return cleanObject(await executeAutomationRequest(tools, 'manage_render', { ...args, subAction: action }, 'Bridge unavailable'));
|
|
168
|
-
return await handleSystemTools(action, args, tools);
|
|
120
|
+
return await handleBlueprintTools(action, args, tools);
|
|
121
|
+
});
|
|
122
|
+
toolRegistry.register('control_actor', async (args, tools) => {
|
|
123
|
+
return await handleActorTools(args.action || requireAction(args), args, tools);
|
|
124
|
+
});
|
|
125
|
+
toolRegistry.register('control_editor', async (args, tools) => {
|
|
126
|
+
const action = args.action || requireAction(args);
|
|
127
|
+
if (action === 'simulate_input') {
|
|
128
|
+
const payload = { ...args, subAction: action };
|
|
129
|
+
return cleanObject(await executeAutomationRequest(tools, 'manage_ui', payload, 'Automation bridge not available'));
|
|
169
130
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
131
|
+
return await handleEditorTools(action, args, tools);
|
|
132
|
+
});
|
|
133
|
+
toolRegistry.register('manage_level', async (args, tools) => {
|
|
134
|
+
const action = args.action || requireAction(args);
|
|
135
|
+
if (['load_cells', 'set_datalayer'].includes(action)) {
|
|
136
|
+
const payload = { ...args, subAction: action };
|
|
137
|
+
return cleanObject(await executeAutomationRequest(tools, 'manage_world_partition', payload, 'Automation bridge not available'));
|
|
138
|
+
}
|
|
139
|
+
return await handleLevelTools(action, args, tools);
|
|
140
|
+
});
|
|
141
|
+
toolRegistry.register('animation_physics', async (args, tools) => await handleAnimationTools(args.action || requireAction(args), args, tools));
|
|
142
|
+
toolRegistry.register('manage_effect', async (args, tools) => {
|
|
143
|
+
const action = args.action || requireAction(args);
|
|
144
|
+
if (isNiagaraGraphAction(action)) {
|
|
145
|
+
const isInstanceOp = action === 'set_niagara_parameter' && (args.actorName || (args.systemName && !args.assetPath && !args.systemPath));
|
|
146
|
+
if (isInstanceOp) {
|
|
147
|
+
return await handleEffectTools(action, args, tools);
|
|
148
|
+
}
|
|
149
|
+
const subAction = NIAGARA_GRAPH_ACTION_MAP[action] || action;
|
|
150
|
+
return await handleGraphTools('manage_niagara_graph', subAction, args, tools);
|
|
151
|
+
}
|
|
152
|
+
return await handleEffectTools(action, args, tools);
|
|
153
|
+
});
|
|
154
|
+
toolRegistry.register('build_environment', async (args, tools) => await handleEnvironmentTools(args.action || requireAction(args), args, tools));
|
|
155
|
+
toolRegistry.register('system_control', async (args, tools) => {
|
|
156
|
+
const action = args.action || requireAction(args);
|
|
157
|
+
if (action === 'console_command')
|
|
158
|
+
return await handleConsoleCommand(args, tools);
|
|
159
|
+
if (action === 'run_ubt')
|
|
160
|
+
return await handlePipelineTools(action, args, tools);
|
|
161
|
+
if (action === 'run_tests')
|
|
162
|
+
return cleanObject(await executeAutomationRequest(tools, 'manage_tests', { ...args, subAction: action }, 'Bridge unavailable'));
|
|
163
|
+
if (action === 'subscribe' || action === 'unsubscribe')
|
|
164
|
+
return cleanObject(await executeAutomationRequest(tools, 'manage_logs', { ...args, subAction: action }, 'Bridge unavailable'));
|
|
165
|
+
if (action === 'spawn_category')
|
|
166
|
+
return cleanObject(await executeAutomationRequest(tools, 'manage_debug', { ...args, subAction: action }, 'Bridge unavailable'));
|
|
167
|
+
if (action === 'start_session')
|
|
168
|
+
return cleanObject(await executeAutomationRequest(tools, 'manage_insights', { ...args, subAction: action }, 'Bridge unavailable'));
|
|
169
|
+
if (action === 'lumen_update_scene')
|
|
181
170
|
return cleanObject(await executeAutomationRequest(tools, 'manage_render', { ...args, subAction: action }, 'Bridge unavailable'));
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
171
|
+
return await handleSystemTools(action, args, tools);
|
|
172
|
+
});
|
|
173
|
+
toolRegistry.register('manage_sequence', async (args, tools) => await handleSequenceTools(args.action || requireAction(args), args, tools));
|
|
174
|
+
toolRegistry.register('inspect', async (args, tools) => await handleInspectTools(args.action || requireAction(args), args, tools));
|
|
175
|
+
toolRegistry.register('manage_audio', async (args, tools) => await handleAudioTools(args.action || requireAction(args), args, tools));
|
|
176
|
+
toolRegistry.register('manage_behavior_tree', async (args, tools) => await handleGraphTools('manage_behavior_tree', args.action || requireAction(args), args, tools));
|
|
177
|
+
toolRegistry.register('manage_blueprint_graph', async (args, tools) => await handleGraphTools('manage_blueprint_graph', args.action || requireAction(args), args, tools));
|
|
178
|
+
toolRegistry.register('manage_render', async (args, tools) => {
|
|
179
|
+
const action = args.action || requireAction(args);
|
|
180
|
+
return cleanObject(await executeAutomationRequest(tools, 'manage_render', { ...args, subAction: action }, 'Bridge unavailable'));
|
|
181
|
+
});
|
|
182
|
+
toolRegistry.register('manage_world_partition', async (args, tools) => {
|
|
183
|
+
const action = args.action || requireAction(args);
|
|
184
|
+
return cleanObject(await executeAutomationRequest(tools, 'manage_world_partition', { ...args, subAction: action }, 'Bridge unavailable'));
|
|
185
|
+
});
|
|
186
|
+
toolRegistry.register('manage_lighting', async (args, tools) => await handleLightingTools(args.action || requireAction(args), args, tools));
|
|
187
|
+
toolRegistry.register('manage_performance', async (args, tools) => await handlePerformanceTools(args.action || requireAction(args), args, tools));
|
|
188
|
+
toolRegistry.register('manage_input', async (args, tools) => await handleInputTools(args.action || requireAction(args), args, tools));
|
|
193
189
|
}
|
|
190
|
+
registerDefaultHandlers();
|
|
194
191
|
export async function handleConsolidatedToolCall(name, args, tools) {
|
|
195
192
|
const logger = new Logger('ConsolidatedToolHandler');
|
|
196
193
|
const startTime = Date.now();
|
|
@@ -198,26 +195,15 @@ export async function handleConsolidatedToolCall(name, args, tools) {
|
|
|
198
195
|
try {
|
|
199
196
|
const normalized = normalizeToolCall(name, args);
|
|
200
197
|
const normalizedName = normalized.name;
|
|
201
|
-
const action = normalized.action;
|
|
202
198
|
const normalizedArgs = normalized.args;
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (!dynamicHandler && toolDef && toolDef.inputSchema && toolDef.inputSchema.properties && toolDef.inputSchema.properties.action) {
|
|
206
|
-
const actionProp = toolDef.inputSchema.properties.action;
|
|
207
|
-
const allowed = Array.isArray(actionProp.enum) ? actionProp.enum : undefined;
|
|
208
|
-
if (allowed && !allowed.includes(action)) {
|
|
209
|
-
return cleanObject({
|
|
210
|
-
success: false,
|
|
211
|
-
error: 'UNKNOWN_ACTION',
|
|
212
|
-
message: `Unknown action '${action}' for consolidated tool '${normalizedName}'.`
|
|
213
|
-
});
|
|
214
|
-
}
|
|
199
|
+
if (normalized.action && !normalizedArgs.action) {
|
|
200
|
+
normalizedArgs.action = normalized.action;
|
|
215
201
|
}
|
|
216
|
-
const
|
|
217
|
-
if (
|
|
218
|
-
return await
|
|
202
|
+
const handler = toolRegistry.getHandler(normalizedName);
|
|
203
|
+
if (handler) {
|
|
204
|
+
return await handler(normalizedArgs, tools);
|
|
219
205
|
}
|
|
220
|
-
return
|
|
206
|
+
return cleanObject({ success: false, error: 'UNKNOWN_TOOL', message: `Unknown consolidated tool: ${name}` });
|
|
221
207
|
}
|
|
222
208
|
catch (err) {
|
|
223
209
|
const duration = Date.now() - startTime;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { ITools } from '../types/tool-interfaces.js';
|
|
2
|
+
type ToolHandler = (args: any, tools: ITools) => Promise<any>;
|
|
3
|
+
export declare class DynamicHandlerRegistry {
|
|
4
|
+
private handlers;
|
|
5
|
+
register(toolName: string, handler: ToolHandler): void;
|
|
6
|
+
getHandler(toolName: string): ToolHandler | undefined;
|
|
7
|
+
hasHandler(toolName: string): boolean;
|
|
8
|
+
removeHandler(toolName: string): boolean;
|
|
9
|
+
getAllRegisteredTools(): string[];
|
|
8
10
|
}
|
|
9
|
-
export
|
|
10
|
-
export
|
|
11
|
+
export declare const toolRegistry: DynamicHandlerRegistry;
|
|
12
|
+
export {};
|
|
11
13
|
//# sourceMappingURL=dynamic-handler-registry.d.ts.map
|
|
@@ -1,101 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let registryLoaded = false;
|
|
7
|
-
const loadedHandlers = [];
|
|
8
|
-
async function loadRegistryIfNeeded() {
|
|
9
|
-
if (registryLoaded)
|
|
10
|
-
return;
|
|
11
|
-
registryLoaded = true;
|
|
12
|
-
const rootUrl = new URL('../..', import.meta.url);
|
|
13
|
-
const envPath = (process.env.MCP_HANDLER_REGISTRY || '').trim();
|
|
14
|
-
let configUrl = null;
|
|
15
|
-
try {
|
|
16
|
-
if (envPath) {
|
|
17
|
-
if (envPath.startsWith('file:')) {
|
|
18
|
-
configUrl = new URL(envPath);
|
|
19
|
-
}
|
|
20
|
-
else if (path.isAbsolute(envPath)) {
|
|
21
|
-
configUrl = pathToFileURL(envPath);
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
configUrl = new URL(envPath, rootUrl);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
configUrl = new URL('handler-registry.json', rootUrl);
|
|
29
|
-
}
|
|
30
|
-
let jsonText;
|
|
31
|
-
try {
|
|
32
|
-
jsonText = await fs.readFile(configUrl, 'utf8');
|
|
33
|
-
}
|
|
34
|
-
catch (err) {
|
|
35
|
-
if (err && (err.code === 'ENOENT' || err.code === 'ERR_MODULE_NOT_FOUND')) {
|
|
36
|
-
log.debug(`Handler registry not found at ${configUrl.href}; dynamic handlers disabled.`);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
log.warn(`Failed to read handler registry from ${configUrl.href}:`, err);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
let raw;
|
|
43
|
-
try {
|
|
44
|
-
raw = JSON.parse(jsonText);
|
|
45
|
-
}
|
|
46
|
-
catch (err) {
|
|
47
|
-
log.warn(`Invalid JSON in handler registry at ${configUrl.href}:`, err);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
if (!raw.handlers || !Array.isArray(raw.handlers)) {
|
|
51
|
-
log.debug('Handler registry contains no handlers.');
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
for (const entry of raw.handlers) {
|
|
55
|
-
if (!entry || typeof entry.tool !== 'string' || typeof entry.module !== 'string') {
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
try {
|
|
59
|
-
const modUrl = new URL(entry.module, rootUrl);
|
|
60
|
-
const mod = await import(modUrl.href);
|
|
61
|
-
const exportName = entry.function && entry.function.trim().length > 0
|
|
62
|
-
? entry.function.trim()
|
|
63
|
-
: 'default';
|
|
64
|
-
const fnExport = mod[exportName];
|
|
65
|
-
if (typeof fnExport !== 'function') {
|
|
66
|
-
log.warn(`Dynamic handler module ${modUrl.href} for tool '${entry.tool}' does not export a callable '${exportName}'.`);
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
const wrapped = fnExport;
|
|
70
|
-
loadedHandlers.push({
|
|
71
|
-
tool: entry.tool,
|
|
72
|
-
actions: Array.isArray(entry.actions) ? entry.actions.slice() : undefined,
|
|
73
|
-
fn: wrapped
|
|
74
|
-
});
|
|
75
|
-
log.info(`Registered dynamic handler for tool '${entry.tool}' from ${modUrl.href}`);
|
|
76
|
-
}
|
|
77
|
-
catch (err) {
|
|
78
|
-
log.warn(`Failed to load dynamic handler for tool '${entry.tool}' from module spec '${entry.module}':`, err);
|
|
79
|
-
}
|
|
1
|
+
export class DynamicHandlerRegistry {
|
|
2
|
+
handlers = new Map();
|
|
3
|
+
register(toolName, handler) {
|
|
4
|
+
if (this.handlers.has(toolName)) {
|
|
5
|
+
console.warn(`Handler for tool '${toolName}' is being overwritten.`);
|
|
80
6
|
}
|
|
7
|
+
this.handlers.set(toolName, handler);
|
|
81
8
|
}
|
|
82
|
-
|
|
83
|
-
|
|
9
|
+
getHandler(toolName) {
|
|
10
|
+
return this.handlers.get(toolName);
|
|
84
11
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (handler.tool !== name)
|
|
94
|
-
continue;
|
|
95
|
-
if (handler.actions && act && !handler.actions.includes(act))
|
|
96
|
-
continue;
|
|
97
|
-
return handler.fn;
|
|
12
|
+
hasHandler(toolName) {
|
|
13
|
+
return this.handlers.has(toolName);
|
|
14
|
+
}
|
|
15
|
+
removeHandler(toolName) {
|
|
16
|
+
return this.handlers.delete(toolName);
|
|
17
|
+
}
|
|
18
|
+
getAllRegisteredTools() {
|
|
19
|
+
return Array.from(this.handlers.keys());
|
|
98
20
|
}
|
|
99
|
-
return null;
|
|
100
21
|
}
|
|
22
|
+
export const toolRegistry = new DynamicHandlerRegistry();
|
|
101
23
|
//# sourceMappingURL=dynamic-handler-registry.js.map
|
package/dist/tools/editor.d.ts
CHANGED
|
@@ -1,56 +1,16 @@
|
|
|
1
1
|
import { BaseTool } from './base-tool.js';
|
|
2
|
-
import { IEditorTools } from '../types/tool-interfaces.js';
|
|
2
|
+
import { IEditorTools, StandardActionResponse } from '../types/tool-interfaces.js';
|
|
3
3
|
export declare class EditorTools extends BaseTool implements IEditorTools {
|
|
4
4
|
private cameraBookmarks;
|
|
5
5
|
private editorPreferences;
|
|
6
6
|
private activeRecording?;
|
|
7
7
|
isInPIE(): Promise<boolean>;
|
|
8
8
|
ensureNotInPIE(): Promise<void>;
|
|
9
|
-
playInEditor(timeoutMs?: number): Promise<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
success: boolean;
|
|
15
|
-
error: any;
|
|
16
|
-
message?: undefined;
|
|
17
|
-
}>;
|
|
18
|
-
stopPlayInEditor(): Promise<{
|
|
19
|
-
success: boolean;
|
|
20
|
-
message: any;
|
|
21
|
-
error?: undefined;
|
|
22
|
-
} | {
|
|
23
|
-
success: boolean;
|
|
24
|
-
error: any;
|
|
25
|
-
message?: undefined;
|
|
26
|
-
}>;
|
|
27
|
-
pausePlayInEditor(): Promise<{
|
|
28
|
-
success: boolean;
|
|
29
|
-
message: string;
|
|
30
|
-
error?: undefined;
|
|
31
|
-
} | {
|
|
32
|
-
success: boolean;
|
|
33
|
-
error: string;
|
|
34
|
-
message?: undefined;
|
|
35
|
-
}>;
|
|
36
|
-
pauseInEditor(): Promise<{
|
|
37
|
-
success: boolean;
|
|
38
|
-
message: string;
|
|
39
|
-
error?: undefined;
|
|
40
|
-
} | {
|
|
41
|
-
success: boolean;
|
|
42
|
-
error: string;
|
|
43
|
-
message?: undefined;
|
|
44
|
-
}>;
|
|
45
|
-
buildLighting(): Promise<{
|
|
46
|
-
success: boolean;
|
|
47
|
-
message: string;
|
|
48
|
-
error?: undefined;
|
|
49
|
-
} | {
|
|
50
|
-
success: boolean;
|
|
51
|
-
error: string;
|
|
52
|
-
message?: undefined;
|
|
53
|
-
}>;
|
|
9
|
+
playInEditor(timeoutMs?: number): Promise<StandardActionResponse>;
|
|
10
|
+
stopPlayInEditor(): Promise<StandardActionResponse>;
|
|
11
|
+
pausePlayInEditor(): Promise<StandardActionResponse>;
|
|
12
|
+
pauseInEditor(): Promise<StandardActionResponse>;
|
|
13
|
+
buildLighting(): Promise<StandardActionResponse>;
|
|
54
14
|
private getViewportCameraInfo;
|
|
55
15
|
setViewportCamera(location?: {
|
|
56
16
|
x: number;
|
|
@@ -60,157 +20,23 @@ export declare class EditorTools extends BaseTool implements IEditorTools {
|
|
|
60
20
|
pitch: number;
|
|
61
21
|
yaw: number;
|
|
62
22
|
roll: number;
|
|
63
|
-
} | [number, number, number] | null | undefined): Promise<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
z: number;
|
|
70
|
-
} | null | undefined;
|
|
71
|
-
rotation: [number, number, number] | {
|
|
72
|
-
pitch: number;
|
|
73
|
-
yaw: number;
|
|
74
|
-
roll: number;
|
|
75
|
-
} | null | undefined;
|
|
76
|
-
error?: undefined;
|
|
77
|
-
} | {
|
|
78
|
-
success: boolean;
|
|
79
|
-
error: any;
|
|
80
|
-
message?: undefined;
|
|
81
|
-
location?: undefined;
|
|
82
|
-
rotation?: undefined;
|
|
83
|
-
}>;
|
|
84
|
-
setCameraSpeed(speed: number): Promise<{
|
|
85
|
-
success: boolean;
|
|
86
|
-
message: string;
|
|
87
|
-
error?: undefined;
|
|
88
|
-
} | {
|
|
89
|
-
success: boolean;
|
|
90
|
-
error: string;
|
|
91
|
-
message?: undefined;
|
|
92
|
-
}>;
|
|
93
|
-
setFOV(fov: number): Promise<{
|
|
94
|
-
success: boolean;
|
|
95
|
-
message: string;
|
|
96
|
-
error?: undefined;
|
|
97
|
-
} | {
|
|
98
|
-
success: boolean;
|
|
99
|
-
error: string;
|
|
100
|
-
message?: undefined;
|
|
101
|
-
}>;
|
|
102
|
-
takeScreenshot(filename?: string, resolution?: string): Promise<{
|
|
103
|
-
success: boolean;
|
|
104
|
-
error: string;
|
|
105
|
-
message?: undefined;
|
|
106
|
-
filename?: undefined;
|
|
107
|
-
command?: undefined;
|
|
108
|
-
} | {
|
|
109
|
-
success: boolean;
|
|
110
|
-
message: string;
|
|
111
|
-
filename: string;
|
|
112
|
-
command: string;
|
|
113
|
-
error?: undefined;
|
|
114
|
-
}>;
|
|
115
|
-
resumePlayInEditor(): Promise<{
|
|
116
|
-
success: boolean;
|
|
117
|
-
message: string;
|
|
118
|
-
error?: undefined;
|
|
119
|
-
} | {
|
|
120
|
-
success: boolean;
|
|
121
|
-
error: string;
|
|
122
|
-
message?: undefined;
|
|
123
|
-
}>;
|
|
124
|
-
stepPIEFrame(steps?: number): Promise<{
|
|
125
|
-
success: boolean;
|
|
126
|
-
message: string;
|
|
127
|
-
steps: number;
|
|
128
|
-
error?: undefined;
|
|
129
|
-
} | {
|
|
130
|
-
success: boolean;
|
|
131
|
-
error: string;
|
|
132
|
-
message?: undefined;
|
|
133
|
-
steps?: undefined;
|
|
134
|
-
}>;
|
|
23
|
+
} | [number, number, number] | null | undefined): Promise<StandardActionResponse>;
|
|
24
|
+
setCameraSpeed(speed: number): Promise<StandardActionResponse>;
|
|
25
|
+
setFOV(fov: number): Promise<StandardActionResponse>;
|
|
26
|
+
takeScreenshot(filename?: string, resolution?: string): Promise<StandardActionResponse>;
|
|
27
|
+
resumePlayInEditor(): Promise<StandardActionResponse>;
|
|
28
|
+
stepPIEFrame(steps?: number): Promise<StandardActionResponse>;
|
|
135
29
|
startRecording(options?: {
|
|
136
30
|
filename?: string;
|
|
137
31
|
frameRate?: number;
|
|
138
32
|
durationSeconds?: number;
|
|
139
33
|
metadata?: Record<string, unknown>;
|
|
140
|
-
}): Promise<
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
};
|
|
148
|
-
}>;
|
|
149
|
-
stopRecording(): Promise<{
|
|
150
|
-
success: true;
|
|
151
|
-
message: string;
|
|
152
|
-
recording?: undefined;
|
|
153
|
-
} | {
|
|
154
|
-
success: true;
|
|
155
|
-
message: string;
|
|
156
|
-
recording: {
|
|
157
|
-
name?: string;
|
|
158
|
-
options?: Record<string, unknown>;
|
|
159
|
-
startedAt: number;
|
|
160
|
-
};
|
|
161
|
-
}>;
|
|
162
|
-
createCameraBookmark(name: string): Promise<{
|
|
163
|
-
success: false;
|
|
164
|
-
error: string;
|
|
165
|
-
message?: undefined;
|
|
166
|
-
bookmark?: undefined;
|
|
167
|
-
} | {
|
|
168
|
-
success: true;
|
|
169
|
-
message: string;
|
|
170
|
-
bookmark: {
|
|
171
|
-
name: string;
|
|
172
|
-
location: [number, number, number];
|
|
173
|
-
rotation: [number, number, number];
|
|
174
|
-
};
|
|
175
|
-
error?: undefined;
|
|
176
|
-
}>;
|
|
177
|
-
jumpToCameraBookmark(name: string): Promise<{
|
|
178
|
-
success: false;
|
|
179
|
-
error: string;
|
|
180
|
-
message?: undefined;
|
|
181
|
-
} | {
|
|
182
|
-
success: true;
|
|
183
|
-
message: string;
|
|
184
|
-
error?: undefined;
|
|
185
|
-
}>;
|
|
186
|
-
setEditorPreferences(category: string | undefined, preferences: Record<string, unknown>): Promise<{
|
|
187
|
-
success: true;
|
|
188
|
-
message: string;
|
|
189
|
-
preferences: Record<string, unknown> | undefined;
|
|
190
|
-
}>;
|
|
191
|
-
setViewportResolution(width: number, height: number): Promise<{
|
|
192
|
-
success: boolean;
|
|
193
|
-
message: string;
|
|
194
|
-
width: number;
|
|
195
|
-
height: number;
|
|
196
|
-
error?: undefined;
|
|
197
|
-
} | {
|
|
198
|
-
success: boolean;
|
|
199
|
-
error: string;
|
|
200
|
-
message?: undefined;
|
|
201
|
-
width?: undefined;
|
|
202
|
-
height?: undefined;
|
|
203
|
-
}>;
|
|
204
|
-
executeConsoleCommand(command: string): Promise<{
|
|
205
|
-
success: boolean;
|
|
206
|
-
error: string;
|
|
207
|
-
message?: undefined;
|
|
208
|
-
output?: undefined;
|
|
209
|
-
} | {
|
|
210
|
-
success: boolean;
|
|
211
|
-
message: string;
|
|
212
|
-
output: any;
|
|
213
|
-
error?: undefined;
|
|
214
|
-
}>;
|
|
34
|
+
}): Promise<StandardActionResponse>;
|
|
35
|
+
stopRecording(): Promise<StandardActionResponse>;
|
|
36
|
+
createCameraBookmark(name: string): Promise<StandardActionResponse>;
|
|
37
|
+
jumpToCameraBookmark(name: string): Promise<StandardActionResponse>;
|
|
38
|
+
setEditorPreferences(category: string | undefined, preferences: Record<string, unknown>): Promise<StandardActionResponse>;
|
|
39
|
+
setViewportResolution(width: number, height: number): Promise<StandardActionResponse>;
|
|
40
|
+
executeConsoleCommand(command: string): Promise<StandardActionResponse>;
|
|
215
41
|
}
|
|
216
42
|
//# sourceMappingURL=editor.d.ts.map
|
package/dist/tools/editor.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BaseTool } from './base-tool.js';
|
|
2
2
|
import { toVec3Object, toRotObject } from '../utils/normalize.js';
|
|
3
3
|
import { DEFAULT_SCREENSHOT_RESOLUTION } from '../constants.js';
|
|
4
|
+
import { wasmIntegration } from '../wasm/index.js';
|
|
4
5
|
export class EditorTools extends BaseTool {
|
|
5
6
|
cameraBookmarks = new Map();
|
|
6
7
|
editorPreferences = new Map();
|
|
@@ -33,8 +34,9 @@ export class EditorTools extends BaseTool {
|
|
|
33
34
|
return { success: false, error: response?.error || response?.message || 'Failed to start PIE' };
|
|
34
35
|
}
|
|
35
36
|
catch (err) {
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
38
|
+
if (errMsg && /time.*out/i.test(errMsg)) {
|
|
39
|
+
return { success: false, error: `Timeout waiting for PIE to start: ${errMsg}` };
|
|
38
40
|
}
|
|
39
41
|
await this.bridge.executeConsoleCommand('t.MaxFPS 60');
|
|
40
42
|
await this.bridge.executeConsoleCommand('PlayInViewport');
|
|
@@ -136,6 +138,13 @@ export class EditorTools extends BaseTool {
|
|
|
136
138
|
rotation = rotObj;
|
|
137
139
|
}
|
|
138
140
|
try {
|
|
141
|
+
const locArray = location
|
|
142
|
+
? [(location.x ?? location[0] ?? 0), (location.y ?? location[1] ?? 0), (location.z ?? location[2] ?? 0)]
|
|
143
|
+
: [0, 0, 0];
|
|
144
|
+
const rotArray = rotation
|
|
145
|
+
? [(rotation.pitch ?? rotation[0] ?? 0), (rotation.yaw ?? rotation[1] ?? 0), (rotation.roll ?? rotation[2] ?? 0)]
|
|
146
|
+
: [0, 0, 0];
|
|
147
|
+
wasmIntegration.composeTransform(locArray, rotArray, [1, 1, 1]);
|
|
139
148
|
const resp = await this.sendAutomationRequest('control_editor', {
|
|
140
149
|
action: 'set_camera',
|
|
141
150
|
location: location,
|