ultimate-unreal-engine-mcp 0.1.0

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 (124) hide show
  1. package/README.md +729 -0
  2. package/dist/build/error-parser.js +51 -0
  3. package/dist/build/fix-suggester.js +84 -0
  4. package/dist/build/ubt-runner.js +146 -0
  5. package/dist/cli.js +13 -0
  6. package/dist/config.js +8 -0
  7. package/dist/docs/data/ue57-api.js +228 -0
  8. package/dist/docs/doc-index.js +110 -0
  9. package/dist/docs/types.js +4 -0
  10. package/dist/generators/class-generator.js +363 -0
  11. package/dist/generators/file-modifier.js +276 -0
  12. package/dist/generators/uht-validator.js +177 -0
  13. package/dist/index.js +89 -0
  14. package/dist/parsers/cpp-class-index.js +230 -0
  15. package/dist/parsers/cpp-parser.js +369 -0
  16. package/dist/parsers/ini-parser.js +216 -0
  17. package/dist/parsers/uproject-parser.js +130 -0
  18. package/dist/plugin-bridge/client.js +217 -0
  19. package/dist/plugin-bridge/protocol.js +6 -0
  20. package/dist/plugin-bridge/retry.js +23 -0
  21. package/dist/setup.js +209 -0
  22. package/dist/tools/ai-systems/index.js +247 -0
  23. package/dist/tools/ai-systems/types.js +4 -0
  24. package/dist/tools/animation/index.js +241 -0
  25. package/dist/tools/animation/types.js +4 -0
  26. package/dist/tools/audio/index.js +204 -0
  27. package/dist/tools/audio/types.js +4 -0
  28. package/dist/tools/blueprint/index.js +495 -0
  29. package/dist/tools/blueprint/types.js +4 -0
  30. package/dist/tools/build/index.js +163 -0
  31. package/dist/tools/chaos/index.js +230 -0
  32. package/dist/tools/chaos/types.js +4 -0
  33. package/dist/tools/collision-physics/index.js +211 -0
  34. package/dist/tools/config/index.js +288 -0
  35. package/dist/tools/cpp/index.js +305 -0
  36. package/dist/tools/docs/index.js +251 -0
  37. package/dist/tools/editor/index.js +242 -0
  38. package/dist/tools/gas/index.js +222 -0
  39. package/dist/tools/gas/types.js +5 -0
  40. package/dist/tools/import-export/index.js +218 -0
  41. package/dist/tools/input/index.js +146 -0
  42. package/dist/tools/known-issues/index.js +88 -0
  43. package/dist/tools/known-issues/middleware.js +55 -0
  44. package/dist/tools/known-issues/store.js +125 -0
  45. package/dist/tools/livelink/index.js +203 -0
  46. package/dist/tools/livelink/types.js +4 -0
  47. package/dist/tools/material/index.js +190 -0
  48. package/dist/tools/motion-design/index.js +251 -0
  49. package/dist/tools/motion-design/types.js +6 -0
  50. package/dist/tools/movie-render/index.js +220 -0
  51. package/dist/tools/networking/index.js +149 -0
  52. package/dist/tools/pcg/index.js +164 -0
  53. package/dist/tools/selection/index.js +180 -0
  54. package/dist/tools/sequencer/index.js +218 -0
  55. package/dist/tools/validation/index.js +183 -0
  56. package/dist/tools/validation/types.js +4 -0
  57. package/dist/tools/viewport/index.js +310 -0
  58. package/dist/tools/worldpartition/index.js +226 -0
  59. package/dist/tools/worldpartition/types.js +4 -0
  60. package/dist/utils/execFileNoThrow.js +40 -0
  61. package/dist/utils/logger.js +27 -0
  62. package/dist/utils/path-guard.js +26 -0
  63. package/package.json +40 -0
  64. package/unreal-plugin/MCPBridge/MCPBridge.uplugin +29 -0
  65. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/MCPBridgeEditor.Build.cs +68 -0
  66. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAICommands.cpp +919 -0
  67. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAICommands.h +23 -0
  68. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPActorCommands.cpp +415 -0
  69. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPActorCommands.h +16 -0
  70. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAnimationCommands.cpp +653 -0
  71. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAnimationCommands.h +24 -0
  72. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAssetCommands.cpp +290 -0
  73. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAssetCommands.h +17 -0
  74. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAudioCommands.cpp +624 -0
  75. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAudioCommands.h +22 -0
  76. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintHandlers.cpp +616 -0
  77. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintHandlers.h +25 -0
  78. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintWriteHandlers.cpp +744 -0
  79. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintWriteHandlers.h +24 -0
  80. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBridgeEditor.cpp +23 -0
  81. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBridgeSubsystem.cpp +149 -0
  82. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBridgeSubsystem.h +38 -0
  83. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPChaosCommands.cpp +771 -0
  84. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPChaosCommands.h +22 -0
  85. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPCollisionPhysicsCommands.cpp +749 -0
  86. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPCollisionPhysicsCommands.h +22 -0
  87. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPEditorStateCommands.cpp +172 -0
  88. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPEditorStateCommands.h +16 -0
  89. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPGASCommands.cpp +715 -0
  90. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPGASCommands.h +22 -0
  91. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPImportExportCommands.cpp +679 -0
  92. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPImportExportCommands.h +22 -0
  93. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPInputHandlers.cpp +381 -0
  94. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPInputHandlers.h +24 -0
  95. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPLiveLinkCommands.cpp +504 -0
  96. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPLiveLinkCommands.h +22 -0
  97. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMaterialCommands.cpp +511 -0
  98. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMaterialCommands.h +22 -0
  99. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMotionDesignCommands.cpp +1110 -0
  100. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMotionDesignCommands.h +28 -0
  101. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMovieRenderCommands.cpp +590 -0
  102. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMovieRenderCommands.h +16 -0
  103. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPNetworkingCommands.cpp +482 -0
  104. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPNetworkingCommands.h +16 -0
  105. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPPieCommands.cpp +338 -0
  106. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPPieCommands.h +16 -0
  107. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSelectionCommands.cpp +677 -0
  108. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSelectionCommands.h +22 -0
  109. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSequencerCommands.cpp +721 -0
  110. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSequencerCommands.h +16 -0
  111. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPValidationCommands.cpp +368 -0
  112. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPValidationCommands.h +22 -0
  113. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPViewportCommands.cpp +1208 -0
  114. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPViewportCommands.h +29 -0
  115. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPWorldPartitionCommands.cpp +822 -0
  116. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPWorldPartitionCommands.h +23 -0
  117. package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Public/MCPBridgeEditor.h +14 -0
  118. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/MCPBridgeRuntime.Build.cs +28 -0
  119. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Private/MCPBridgeRuntime.cpp +22 -0
  120. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Private/MCPCommandRouter.cpp +118 -0
  121. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Private/MCPTcpServer.cpp +196 -0
  122. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Public/MCPBridgeRuntime.h +15 -0
  123. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Public/MCPCommandRouter.h +55 -0
  124. package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Public/MCPTcpServer.h +59 -0
@@ -0,0 +1,230 @@
1
+ // src/tools/chaos/index.ts
2
+ // MCP tool implementations for Chaos physics management (Phase 26).
3
+ // All tools route commands through PluginBridgeClient to the C++ MCPBridge plugin.
4
+ // Returns structured plugin_not_connected errors when the plugin is absent.
5
+ //
6
+ // Tools registered (Phase 26 — CHAOS-01 through CHAOS-04):
7
+ // ue_inspect_geometry_collection — Inspect geometry collection fracture hierarchy and bone data
8
+ // ue_reset_destruction — Reset geometry collection actor to initial unfractured state
9
+ // ue_read_cloth_params — Read Chaos cloth simulation parameters from actor or asset
10
+ // ue_manage_physics_cache — Start, stop, or query Chaos physics cache recording
11
+ //
12
+ // All tools require MCPBridge plugin (Phase 26 — CHAOS-01 through CHAOS-04).
13
+ import { z } from 'zod';
14
+ import { withKnownIssues } from '../known-issues/middleware.js';
15
+ import { PluginBridgeClient, PluginNotConnectedError } from '../../plugin-bridge/client.js';
16
+ // Module-level bridge instance — injected in tests via exported handler signatures.
17
+ const _defaultBridge = new PluginBridgeClient();
18
+ // ---------------------------------------------------------------------------
19
+ // sendOrDisconnect helper
20
+ // ---------------------------------------------------------------------------
21
+ /**
22
+ * Sends a command to the bridge and returns a ToolResult.
23
+ *
24
+ * - On success (response.success true): returns data as JSON text.
25
+ * - On command-level failure (response.success false): returns isError:true with error JSON.
26
+ * - On PluginNotConnectedError: returns isError:true with plugin_not_connected JSON.
27
+ * - On other errors: rethrows (withKnownIssues catches and formats).
28
+ *
29
+ * NOTE: sendCommand() overwrites correlationId with crypto.randomUUID() internally;
30
+ * passing an empty string is safe and correct (per STATE.md decision).
31
+ */
32
+ async function sendOrDisconnect(b, cmd) {
33
+ try {
34
+ const response = await b.sendCommand({ ...cmd, correlationId: '' });
35
+ if (!response.success) {
36
+ return {
37
+ isError: true,
38
+ content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
39
+ };
40
+ }
41
+ return {
42
+ content: [{ type: 'text', text: JSON.stringify(response.data ?? {}) }],
43
+ };
44
+ }
45
+ catch (err) {
46
+ if (err instanceof PluginNotConnectedError) {
47
+ return {
48
+ isError: true,
49
+ content: [{ type: 'text', text: JSON.stringify(err.bridgeError) }],
50
+ };
51
+ }
52
+ throw err; // withKnownIssues catches unexpected errors
53
+ }
54
+ }
55
+ // ---------------------------------------------------------------------------
56
+ // Exported handler functions (for direct unit testing via bridge injection)
57
+ // ---------------------------------------------------------------------------
58
+ /**
59
+ * ue_inspect_geometry_collection handler — satisfies CHAOS-01.
60
+ * Sends chaos.geometryCollection to the plugin; returns fracture hierarchy,
61
+ * bone count, level breakdown, and damage thresholds.
62
+ *
63
+ * @param args Tool arguments — provide asset_path and/or actor_label.
64
+ * @param b PluginBridgeClient instance (defaults to module-level singleton).
65
+ */
66
+ export async function handleInspectGeometryCollection(args, b = _defaultBridge) {
67
+ // Response data shape: GeometryCollectionInspectResult
68
+ const payload = {};
69
+ if (args.asset_path !== undefined)
70
+ payload['asset_path'] = args.asset_path;
71
+ if (args.actor_label !== undefined)
72
+ payload['actor_label'] = args.actor_label;
73
+ return sendOrDisconnect(b, {
74
+ type: 'chaos.geometryCollection',
75
+ payload,
76
+ });
77
+ }
78
+ /**
79
+ * ue_reset_destruction handler — satisfies CHAOS-02.
80
+ * Sends chaos.resetDestruction to the plugin; resets a geometry collection
81
+ * actor to its initial unfractured state.
82
+ *
83
+ * @param args Tool arguments including actor_label.
84
+ * @param b PluginBridgeClient instance (defaults to module-level singleton).
85
+ */
86
+ export async function handleResetDestruction(args, b = _defaultBridge) {
87
+ // Response data shape: DestructionResetResult
88
+ return sendOrDisconnect(b, {
89
+ type: 'chaos.resetDestruction',
90
+ payload: { actor_label: args.actor_label },
91
+ });
92
+ }
93
+ /**
94
+ * ue_read_cloth_params handler — satisfies CHAOS-03.
95
+ * Sends chaos.cloth to the plugin; returns cloth simulation parameters
96
+ * (stiffness, damping, friction, gravity scale, wind coefficients).
97
+ *
98
+ * @param args Tool arguments — provide actor_label and/or asset_path.
99
+ * @param b PluginBridgeClient instance (defaults to module-level singleton).
100
+ */
101
+ export async function handleReadClothParams(args, b = _defaultBridge) {
102
+ // Response data shape: ClothParamsResult
103
+ const payload = {};
104
+ if (args.actor_label !== undefined)
105
+ payload['actor_label'] = args.actor_label;
106
+ if (args.asset_path !== undefined)
107
+ payload['asset_path'] = args.asset_path;
108
+ return sendOrDisconnect(b, {
109
+ type: 'chaos.cloth',
110
+ payload,
111
+ });
112
+ }
113
+ /**
114
+ * ue_manage_physics_cache handler — satisfies CHAOS-04.
115
+ * Sends chaos.physicsCache to the plugin; starts, stops, or queries
116
+ * Chaos physics cache recording state.
117
+ *
118
+ * @param args Tool arguments including action and optional actor_label.
119
+ * @param b PluginBridgeClient instance (defaults to module-level singleton).
120
+ */
121
+ export async function handleManagePhysicsCache(args, b = _defaultBridge) {
122
+ // Response data shape: PhysicsCacheResult
123
+ const payload = { action: args.action };
124
+ if (args.actor_label !== undefined)
125
+ payload['actor_label'] = args.actor_label;
126
+ return sendOrDisconnect(b, {
127
+ type: 'chaos.physicsCache',
128
+ payload,
129
+ });
130
+ }
131
+ // ---------------------------------------------------------------------------
132
+ // registerChaosTools
133
+ // ---------------------------------------------------------------------------
134
+ /**
135
+ * Register UE Chaos physics management tools on the MCP server.
136
+ *
137
+ * All tools in this domain require the MCPBridge editor plugin.
138
+ * When the plugin is not connected, each handler returns:
139
+ * { isError: true, content: [{ type: 'text', text: <plugin_not_connected JSON> }] }
140
+ *
141
+ * Tools registered (Phase 26):
142
+ * ue_inspect_geometry_collection — CHAOS-01: Inspect fracture hierarchy and clusters
143
+ * ue_reset_destruction — CHAOS-02: Reset geometry collection to unfractured state
144
+ * ue_read_cloth_params — CHAOS-03: Read cloth simulation parameters
145
+ * ue_manage_physics_cache — CHAOS-04: Start/stop/query physics cache recording
146
+ *
147
+ * @param server The McpServer instance to register tools on.
148
+ * @param bridge Optional PluginBridgeClient for testing (defaults to a new instance).
149
+ */
150
+ export function registerChaosTools(server, bridge) {
151
+ const b = bridge ?? new PluginBridgeClient();
152
+ // --------------------------------------------------------------------------
153
+ // ue_inspect_geometry_collection (CHAOS-01)
154
+ // --------------------------------------------------------------------------
155
+ server.registerTool('ue_inspect_geometry_collection', {
156
+ title: 'Inspect Geometry Collection',
157
+ description: "[requires_plugin] Inspect a Chaos geometry collection's fracture hierarchy, bone count, level breakdown, and damage thresholds. Provide either asset_path or actor_label.",
158
+ inputSchema: z.object({
159
+ asset_path: z
160
+ .string()
161
+ .optional()
162
+ .describe("UE asset path to the geometry collection, e.g. '/Game/Destruction/GC_Wall'"),
163
+ actor_label: z
164
+ .string()
165
+ .optional()
166
+ .describe('Editor actor label of a placed geometry collection actor'),
167
+ }),
168
+ annotations: {
169
+ readOnlyHint: true,
170
+ destructiveHint: false,
171
+ },
172
+ }, withKnownIssues('ue_inspect_geometry_collection', async (args) => handleInspectGeometryCollection(args, b)));
173
+ // --------------------------------------------------------------------------
174
+ // ue_reset_destruction (CHAOS-02)
175
+ // --------------------------------------------------------------------------
176
+ server.registerTool('ue_reset_destruction', {
177
+ title: 'Reset Destruction State',
178
+ description: '[requires_plugin] Reset a geometry collection actor to its initial unfractured state. Reverses any in-editor destruction simulation.',
179
+ inputSchema: z.object({
180
+ actor_label: z
181
+ .string()
182
+ .describe('Editor actor label of the geometry collection actor to reset'),
183
+ }),
184
+ annotations: {
185
+ readOnlyHint: false,
186
+ destructiveHint: false,
187
+ },
188
+ }, withKnownIssues('ue_reset_destruction', async (args) => handleResetDestruction(args, b)));
189
+ // --------------------------------------------------------------------------
190
+ // ue_read_cloth_params (CHAOS-03)
191
+ // --------------------------------------------------------------------------
192
+ server.registerTool('ue_read_cloth_params', {
193
+ title: 'Read Cloth Simulation Parameters',
194
+ description: '[requires_plugin] Read Chaos cloth simulation parameters (stiffness, damping, friction, gravity, wind) from a skeletal mesh actor or cloth asset. Requires the ChaosCloth plugin to be enabled.',
195
+ inputSchema: z.object({
196
+ actor_label: z
197
+ .string()
198
+ .optional()
199
+ .describe('Editor actor label of an actor with cloth simulation'),
200
+ asset_path: z
201
+ .string()
202
+ .optional()
203
+ .describe("UE asset path to a cloth asset, e.g. '/Game/Characters/Cloth_Cape'"),
204
+ }),
205
+ annotations: {
206
+ readOnlyHint: true,
207
+ destructiveHint: false,
208
+ },
209
+ }, withKnownIssues('ue_read_cloth_params', async (args) => handleReadClothParams(args, b)));
210
+ // --------------------------------------------------------------------------
211
+ // ue_manage_physics_cache (CHAOS-04)
212
+ // --------------------------------------------------------------------------
213
+ server.registerTool('ue_manage_physics_cache', {
214
+ title: 'Manage Physics Cache',
215
+ description: "[requires_plugin] Start, stop, or query Chaos physics cache recording. Use action 'start' to begin recording, 'stop' to end recording, 'query' to check status and frame count.",
216
+ inputSchema: z.object({
217
+ action: z
218
+ .enum(['start', 'stop', 'query'])
219
+ .describe("Cache operation: 'start' to begin recording, 'stop' to end, 'query' to inspect"),
220
+ actor_label: z
221
+ .string()
222
+ .optional()
223
+ .describe('Optional actor label for actor-specific cache operations'),
224
+ }),
225
+ annotations: {
226
+ readOnlyHint: false,
227
+ destructiveHint: false,
228
+ },
229
+ }, withKnownIssues('ue_manage_physics_cache', async (args) => handleManagePhysicsCache(args, b)));
230
+ }
@@ -0,0 +1,4 @@
1
+ // src/tools/chaos/types.ts
2
+ // TypeScript result interfaces for the four Chaos physics MCP tools (Phase 26).
3
+ // These interfaces mirror the JSON shapes returned by the C++ handlers in Plan 26-01.
4
+ export {};
@@ -0,0 +1,211 @@
1
+ // src/tools/collision-physics/index.ts
2
+ // MCP tool implementations for collision and physics configuration (Phase 20).
3
+ // All tools route commands through PluginBridgeClient to the C++ MCPBridge plugin.
4
+ // Returns structured plugin_not_connected errors when the plugin is absent.
5
+ //
6
+ // Tools registered (Phase 20 — PHY-01 through PHY-04):
7
+ // ue_read_collision — Read collision preset, enabled state, object type, and per-channel responses
8
+ // ue_set_collision — Set collision preset and/or individual channel response overrides
9
+ // ue_manage_physical_material — Read or modify physical material properties (friction, restitution, density)
10
+ // ue_inspect_physics_asset — Inspect physics asset per-bone body setup (capsules, spheres, boxes)
11
+ //
12
+ // All tools require MCPBridge plugin (Phase 20 — PHY-01 through PHY-04).
13
+ import { z } from 'zod';
14
+ import { withKnownIssues } from '../known-issues/middleware.js';
15
+ import { PluginBridgeClient, PluginNotConnectedError } from '../../plugin-bridge/client.js';
16
+ // ---------------------------------------------------------------------------
17
+ // sendOrDisconnect helper
18
+ // ---------------------------------------------------------------------------
19
+ /**
20
+ * Sends a command to the bridge and returns a ToolResult.
21
+ *
22
+ * - On success (response.success true): returns data as JSON text.
23
+ * - On command-level failure (response.success false): returns isError:true with error JSON.
24
+ * - On PluginNotConnectedError: returns isError:true with plugin_not_connected JSON.
25
+ * - On other errors: rethrows (withKnownIssues catches and formats).
26
+ *
27
+ * NOTE: sendCommand() overwrites correlationId with crypto.randomUUID() internally;
28
+ * passing an empty string is safe and correct (per STATE.md decision).
29
+ */
30
+ async function sendOrDisconnect(bridge, cmd) {
31
+ try {
32
+ const response = await bridge.sendCommand({ ...cmd, correlationId: '' });
33
+ if (!response.success) {
34
+ return {
35
+ isError: true,
36
+ content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
37
+ };
38
+ }
39
+ return {
40
+ content: [{ type: 'text', text: JSON.stringify(response.data ?? {}) }],
41
+ };
42
+ }
43
+ catch (err) {
44
+ if (err instanceof PluginNotConnectedError) {
45
+ return {
46
+ isError: true,
47
+ content: [{ type: 'text', text: JSON.stringify(err.bridgeError) }],
48
+ };
49
+ }
50
+ throw err; // withKnownIssues catches unexpected errors
51
+ }
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // registerCollisionPhysicsTools
55
+ // ---------------------------------------------------------------------------
56
+ /**
57
+ * Register UE collision and physics configuration tools on the MCP server.
58
+ *
59
+ * All tools in this domain require the MCPBridge editor plugin.
60
+ * When the plugin is not connected, each handler returns:
61
+ * { isError: true, content: [{ type: 'text', text: <plugin_not_connected JSON> }] }
62
+ *
63
+ * Tools registered (Phase 20):
64
+ * ue_read_collision — Read collision preset and channel responses on a component (PHY-01)
65
+ * ue_set_collision — Set collision preset and channel responses (PHY-02)
66
+ * ue_manage_physical_material — Read/set physical material properties (PHY-03)
67
+ * ue_inspect_physics_asset — Inspect physics asset body setup per bone (PHY-04)
68
+ *
69
+ * @param server The McpServer instance to register tools on.
70
+ * @param bridge Optional PluginBridgeClient for testing (defaults to a new instance).
71
+ */
72
+ export function registerCollisionPhysicsTools(server, bridge) {
73
+ const _bridge = bridge ?? new PluginBridgeClient();
74
+ // --------------------------------------------------------------------------
75
+ // ue_read_collision (PHY-01)
76
+ // --------------------------------------------------------------------------
77
+ server.registerTool('ue_read_collision', {
78
+ title: 'Read Collision Settings',
79
+ description: '[requires_plugin] Read collision preset, enabled state, object type, and per-channel response map from a primitive component on an actor.',
80
+ inputSchema: z.object({
81
+ actor_label: z
82
+ .string()
83
+ .describe('Editor actor label'),
84
+ component_name: z
85
+ .string()
86
+ .optional()
87
+ .describe('Component name; defaults to first UPrimitiveComponent if omitted'),
88
+ }),
89
+ annotations: {
90
+ readOnlyHint: true,
91
+ destructiveHint: false,
92
+ },
93
+ }, withKnownIssues('ue_read_collision', async (args) => {
94
+ const payload = { actor_label: args.actor_label };
95
+ if (args.component_name !== undefined)
96
+ payload['component_name'] = args.component_name;
97
+ return sendOrDisconnect(_bridge, { type: 'collision.read', payload });
98
+ }));
99
+ // --------------------------------------------------------------------------
100
+ // ue_set_collision (PHY-02)
101
+ // --------------------------------------------------------------------------
102
+ server.registerTool('ue_set_collision', {
103
+ title: 'Set Collision Settings',
104
+ description: "[requires_plugin] Set collision preset and/or individual channel response overrides on a primitive component. Returns updated collision state.",
105
+ inputSchema: z.object({
106
+ actor_label: z
107
+ .string()
108
+ .describe('Editor actor label'),
109
+ component_name: z
110
+ .string()
111
+ .optional()
112
+ .describe('Component name; defaults to first UPrimitiveComponent if omitted'),
113
+ preset: z
114
+ .string()
115
+ .optional()
116
+ .describe("Collision preset profile name, e.g. 'BlockAll', 'OverlapAll', 'NoCollision'"),
117
+ responses: z
118
+ .array(z.object({
119
+ channel: z.number(),
120
+ response: z.enum(['Ignore', 'Overlap', 'Block']),
121
+ }))
122
+ .optional()
123
+ .describe('Per-channel response overrides; channel is ECollisionChannel int value'),
124
+ }),
125
+ annotations: {
126
+ readOnlyHint: false,
127
+ destructiveHint: false,
128
+ },
129
+ }, withKnownIssues('ue_set_collision', async (args) => {
130
+ const payload = { actor_label: args.actor_label };
131
+ if (args.component_name !== undefined)
132
+ payload['component_name'] = args.component_name;
133
+ if (args.preset !== undefined)
134
+ payload['preset'] = args.preset;
135
+ if (args.responses !== undefined)
136
+ payload['responses'] = args.responses;
137
+ return sendOrDisconnect(_bridge, { type: 'collision.set', payload });
138
+ }));
139
+ // --------------------------------------------------------------------------
140
+ // ue_manage_physical_material (PHY-03)
141
+ // --------------------------------------------------------------------------
142
+ server.registerTool('ue_manage_physical_material', {
143
+ title: 'Read/Set Physical Material Properties',
144
+ description: "[requires_plugin] Read or modify physical material properties (friction, restitution, density, surface type). Use action 'read' to inspect, 'write' to modify.",
145
+ inputSchema: z.object({
146
+ asset_path: z
147
+ .string()
148
+ .describe("UE asset path to the UPhysicalMaterial, e.g. '/Game/PhysMats/PM_Rock'"),
149
+ action: z
150
+ .enum(['read', 'write'])
151
+ .describe("Operation to perform: 'read' to inspect, 'write' to modify"),
152
+ friction: z
153
+ .number()
154
+ .optional(),
155
+ static_friction: z
156
+ .number()
157
+ .optional(),
158
+ restitution: z
159
+ .number()
160
+ .optional(),
161
+ density: z
162
+ .number()
163
+ .optional(),
164
+ surface_type: z
165
+ .number()
166
+ .optional()
167
+ .describe('EPhysicalSurface enum value'),
168
+ }),
169
+ annotations: {
170
+ readOnlyHint: false,
171
+ destructiveHint: false,
172
+ },
173
+ }, withKnownIssues('ue_manage_physical_material', async (args) => {
174
+ const payload = {
175
+ asset_path: args.asset_path,
176
+ action: args.action,
177
+ };
178
+ if (args.friction !== undefined)
179
+ payload['friction'] = args.friction;
180
+ if (args.static_friction !== undefined)
181
+ payload['static_friction'] = args.static_friction;
182
+ if (args.restitution !== undefined)
183
+ payload['restitution'] = args.restitution;
184
+ if (args.density !== undefined)
185
+ payload['density'] = args.density;
186
+ if (args.surface_type !== undefined)
187
+ payload['surface_type'] = args.surface_type;
188
+ return sendOrDisconnect(_bridge, { type: 'physics.material', payload });
189
+ }));
190
+ // --------------------------------------------------------------------------
191
+ // ue_inspect_physics_asset (PHY-04)
192
+ // --------------------------------------------------------------------------
193
+ server.registerTool('ue_inspect_physics_asset', {
194
+ title: 'Inspect Physics Asset Bodies',
195
+ description: "[requires_plugin] Inspect a physics asset's per-bone body setup including primitive shapes (capsules, spheres, boxes), dimensions, and mass configuration.",
196
+ inputSchema: z.object({
197
+ asset_path: z
198
+ .string()
199
+ .describe("UE asset path to the UPhysicsAsset, e.g. '/Game/Characters/SK_Mannequin_PhysicsAsset'"),
200
+ }),
201
+ annotations: {
202
+ readOnlyHint: true,
203
+ destructiveHint: false,
204
+ },
205
+ }, withKnownIssues('ue_inspect_physics_asset', async (args) => {
206
+ return sendOrDisconnect(_bridge, {
207
+ type: 'physics.asset',
208
+ payload: { asset_path: args.asset_path },
209
+ });
210
+ }));
211
+ }