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,226 @@
1
+ // src/tools/worldpartition/index.ts
2
+ // MCP tool implementations for World Partition management (Phase 18).
3
+ // All tools route commands through PluginBridgeClient to the C++ MCPBridge handlers.
4
+ // Returns structured plugin_not_connected errors when the plugin is absent.
5
+ //
6
+ // Tools registered (Phase 18 — WP-01 through WP-04):
7
+ // ue_read_world_partition — Read WP grid size, loading range, streaming config, runtime hash
8
+ // ue_manage_data_layers — List, create, toggle, or assign actors to data layers
9
+ // ue_inspect_streaming_sources — Inspect streaming source components and their configurations
10
+ // ue_trigger_hlod_generation — Trigger HLOD generation or inspect HLOD layer config
11
+ //
12
+ // All tools require MCPBridge plugin (Phase 18 — WP-01 through WP-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 bridge = 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_read_world_partition handler — satisfies WP-01.
60
+ * Sends worldpartition.settings to the plugin; returns WP configuration.
61
+ *
62
+ * @param args Tool arguments (none required for this tool).
63
+ * @param b PluginBridgeClient instance (defaults to module-level singleton).
64
+ */
65
+ export async function handleReadWorldPartition(args, b = bridge) {
66
+ // Response data shape: WorldPartitionSettingsResult
67
+ void args; // No parameters required
68
+ return sendOrDisconnect(b, {
69
+ type: 'worldpartition.settings',
70
+ payload: {},
71
+ });
72
+ }
73
+ /**
74
+ * ue_manage_data_layers handler — satisfies WP-02.
75
+ * Sends worldpartition.dataLayers to the plugin; lists, creates, toggles, or assigns actors to data layers.
76
+ *
77
+ * @param args Tool arguments including action and optional layer/actor parameters.
78
+ * @param b PluginBridgeClient instance (defaults to module-level singleton).
79
+ */
80
+ export async function handleManageDataLayers(args, b = bridge) {
81
+ // Response data shape: DataLayersResult (variant depends on action)
82
+ const payload = { action: args.action };
83
+ if (args.layer_name !== undefined)
84
+ payload['layer_name'] = args.layer_name;
85
+ if (args.layer_type !== undefined)
86
+ payload['layer_type'] = args.layer_type;
87
+ if (args.initial_state !== undefined)
88
+ payload['initial_state'] = args.initial_state;
89
+ if (args.actor_label !== undefined)
90
+ payload['actor_label'] = args.actor_label;
91
+ return sendOrDisconnect(b, {
92
+ type: 'worldpartition.dataLayers',
93
+ payload,
94
+ });
95
+ }
96
+ /**
97
+ * ue_inspect_streaming_sources handler — satisfies WP-03.
98
+ * Sends worldpartition.streamingSources to the plugin; returns streaming source components.
99
+ *
100
+ * @param args Tool arguments including optional actor_label filter.
101
+ * @param b PluginBridgeClient instance (defaults to module-level singleton).
102
+ */
103
+ export async function handleInspectStreamingSources(args, b = bridge) {
104
+ // Response data shape: StreamingSourcesResult
105
+ const payload = {};
106
+ if (args.actor_label !== undefined)
107
+ payload['actor_label'] = args.actor_label;
108
+ return sendOrDisconnect(b, {
109
+ type: 'worldpartition.streamingSources',
110
+ payload,
111
+ });
112
+ }
113
+ /**
114
+ * ue_trigger_hlod_generation handler — satisfies WP-04.
115
+ * Sends worldpartition.hlod to the plugin; inspects HLOD config or triggers HLOD build.
116
+ *
117
+ * @param args Tool arguments including action ("inspect" | "generate").
118
+ * @param b PluginBridgeClient instance (defaults to module-level singleton).
119
+ */
120
+ export async function handleTriggerHlodGeneration(args, b = bridge) {
121
+ // Response data shape: HlodResult (variant depends on action)
122
+ return sendOrDisconnect(b, {
123
+ type: 'worldpartition.hlod',
124
+ payload: { action: args.action },
125
+ });
126
+ }
127
+ // ---------------------------------------------------------------------------
128
+ // registerWorldPartitionTools
129
+ // ---------------------------------------------------------------------------
130
+ /**
131
+ * Register UE World Partition management tools on the MCP server.
132
+ *
133
+ * All tools in this domain require the MCPBridge editor plugin.
134
+ * When the plugin is not connected, each handler returns:
135
+ * { isError: true, content: [{ type: 'text', text: <plugin_not_connected JSON> }] }
136
+ *
137
+ * Tools registered (Phase 18):
138
+ * ue_read_world_partition — WP-01: Read WP configuration (grid size, loading range, streaming)
139
+ * ue_manage_data_layers — WP-02: List, create, toggle data layers; assign actors to layers
140
+ * ue_inspect_streaming_sources — WP-03: Inspect streaming source components and target states
141
+ * ue_trigger_hlod_generation — WP-04: Inspect HLOD layer config or trigger HLOD build
142
+ *
143
+ * @param server The McpServer instance to register tools on.
144
+ * @param _bridge Optional PluginBridgeClient for testing (not used directly — handlers
145
+ * accept bridge injection via their exported function signatures).
146
+ */
147
+ export function registerWorldPartitionTools(server, _bridge) {
148
+ const b = _bridge ?? new PluginBridgeClient();
149
+ // --------------------------------------------------------------------------
150
+ // ue_read_world_partition (WP-01)
151
+ // --------------------------------------------------------------------------
152
+ server.registerTool('ue_read_world_partition', {
153
+ title: 'Read World Partition Settings',
154
+ description: '[requires_plugin] Read World Partition configuration including grid size, loading range, streaming state, and runtime hash.',
155
+ inputSchema: z.object({}),
156
+ annotations: {
157
+ readOnlyHint: true,
158
+ destructiveHint: false,
159
+ },
160
+ }, withKnownIssues('ue_read_world_partition', async (args) => handleReadWorldPartition(args, b)));
161
+ // --------------------------------------------------------------------------
162
+ // ue_manage_data_layers (WP-02)
163
+ // --------------------------------------------------------------------------
164
+ server.registerTool('ue_manage_data_layers', {
165
+ title: 'Manage Data Layers',
166
+ description: '[requires_plugin] List, create, enable/disable data layers, or assign actors to data layers in a World Partition world.',
167
+ inputSchema: z.object({
168
+ action: z
169
+ .enum(['list', 'create', 'toggle', 'assign_actor'])
170
+ .describe('Action to perform on data layers'),
171
+ layer_name: z
172
+ .string()
173
+ .optional()
174
+ .describe('Data layer name (required for create, toggle, assign_actor)'),
175
+ layer_type: z
176
+ .enum(['Runtime', 'Editor'])
177
+ .optional()
178
+ .describe('Layer type (required for create)'),
179
+ initial_state: z
180
+ .enum(['Unloaded', 'Loaded', 'Activated'])
181
+ .optional()
182
+ .describe('Initial runtime state (for toggle action)'),
183
+ actor_label: z
184
+ .string()
185
+ .optional()
186
+ .describe('Actor label to assign to layer (for assign_actor action)'),
187
+ }),
188
+ annotations: {
189
+ readOnlyHint: false,
190
+ destructiveHint: false,
191
+ },
192
+ }, withKnownIssues('ue_manage_data_layers', async (args) => handleManageDataLayers(args, b)));
193
+ // --------------------------------------------------------------------------
194
+ // ue_inspect_streaming_sources (WP-03)
195
+ // --------------------------------------------------------------------------
196
+ server.registerTool('ue_inspect_streaming_sources', {
197
+ title: 'Inspect Streaming Sources',
198
+ description: '[requires_plugin] Inspect World Partition streaming source components, their shapes, priorities, and target states.',
199
+ inputSchema: z.object({
200
+ actor_label: z
201
+ .string()
202
+ .optional()
203
+ .describe('Optional actor label to filter streaming sources'),
204
+ }),
205
+ annotations: {
206
+ readOnlyHint: true,
207
+ destructiveHint: false,
208
+ },
209
+ }, withKnownIssues('ue_inspect_streaming_sources', async (args) => handleInspectStreamingSources(args, b)));
210
+ // --------------------------------------------------------------------------
211
+ // ue_trigger_hlod_generation (WP-04)
212
+ // --------------------------------------------------------------------------
213
+ server.registerTool('ue_trigger_hlod_generation', {
214
+ title: 'HLOD Generation',
215
+ description: '[requires_plugin] Trigger HLOD generation or inspect HLOD layer configuration for World Partition.',
216
+ inputSchema: z.object({
217
+ action: z
218
+ .enum(['inspect', 'generate'])
219
+ .describe('inspect: read HLOD layer config; generate: trigger HLOD build'),
220
+ }),
221
+ annotations: {
222
+ readOnlyHint: false,
223
+ destructiveHint: false,
224
+ },
225
+ }, withKnownIssues('ue_trigger_hlod_generation', async (args) => handleTriggerHlodGeneration(args, b)));
226
+ }
@@ -0,0 +1,4 @@
1
+ // src/tools/worldpartition/types.ts
2
+ // TypeScript result interfaces for the four World Partition MCP tools (Phase 18).
3
+ // These interfaces mirror the JSON shapes returned by the C++ handlers in Plan 01.
4
+ export {};
@@ -0,0 +1,40 @@
1
+ // src/utils/execFileNoThrow.ts
2
+ // Safe subprocess wrapper using array-form execFile — no shell string interpolation.
3
+ // Never throws: non-zero exit codes are returned as { status: N }, not thrown.
4
+ // Use this for ALL subprocess invocations in the codebase.
5
+ //
6
+ // Security: array-form execFile passes args as an array directly to the OS —
7
+ // shell metacharacters (`;`, `|`, `&`, etc.) are inert. Mitigates T-06-04.
8
+ import { execFile } from 'node:child_process';
9
+ /**
10
+ * Invoke a subprocess using array-form execFile and return its output.
11
+ * Never throws — non-zero exit codes are captured in the returned status field.
12
+ *
13
+ * @param cmd Executable name or absolute path. Never a shell string.
14
+ * @param args Arguments array. Shell metacharacters are inert.
15
+ * @param options Optional execution context (cwd, env, timeout).
16
+ */
17
+ export async function execFileNoThrow(cmd, args, options) {
18
+ return new Promise((resolve) => {
19
+ execFile(cmd, args, {
20
+ cwd: options?.cwd,
21
+ env: options?.env,
22
+ timeout: options?.timeoutMs,
23
+ // 50 MB buffer — UBT can produce large compilation logs
24
+ maxBuffer: 50 * 1024 * 1024,
25
+ }, (err, stdout, stderr) => {
26
+ if (!err) {
27
+ resolve({ stdout, stderr, status: 0 });
28
+ }
29
+ else {
30
+ // err.code is the numeric exit status on non-zero exit; null if killed by signal.
31
+ // err.stdout / err.stderr may contain captured output on some Node versions —
32
+ // prefer them when set, fall back to the direct callback params.
33
+ const status = typeof err.code === 'number' ? err.code : null;
34
+ const outStr = err.stdout ?? stdout;
35
+ const errStr = err.stderr ?? stderr;
36
+ resolve({ stdout: outStr, stderr: errStr, status });
37
+ }
38
+ });
39
+ });
40
+ }
@@ -0,0 +1,27 @@
1
+ // Structured logger for the UE MCP server.
2
+ // All output goes to console.error (stderr) — NEVER console.log or console.info.
3
+ // Reason: console.log writes to stdout, which is the MCP JSON-RPC channel.
4
+ // Any stdout output corrupts the protocol stream and disconnects the client.
5
+ // See: PITFALLS.md Pitfall 8, CONTEXT.md locked decision.
6
+ /**
7
+ * Logs an informational message to stderr with the [UE MCP] prefix.
8
+ * Use for normal operational messages (startup, connection status, etc.).
9
+ */
10
+ export function log(message, ...args) {
11
+ console.error(`[UE MCP] ${message}`, ...args);
12
+ }
13
+ /**
14
+ * Logs a warning message to stderr with the [UE MCP WARN] prefix.
15
+ * Use for non-fatal issues that operators should be aware of.
16
+ */
17
+ export function warn(message, ...args) {
18
+ console.error(`[UE MCP WARN] ${message}`, ...args);
19
+ }
20
+ /**
21
+ * Logs an error message to stderr with the [UE MCP ERROR] prefix.
22
+ * Use for caught exceptions and error conditions. The err argument is
23
+ * logged inline — pass an Error object or any useful context.
24
+ */
25
+ export function error(message, err) {
26
+ console.error(`[UE MCP ERROR] ${message}`, err ?? '');
27
+ }
@@ -0,0 +1,26 @@
1
+ // Path traversal guard — validates user-supplied file paths against project root.
2
+ // Implements ASVS V4 access control: resolves path and asserts within project root.
3
+ // Mitigates T-01-04 (path traversal via AI-crafted file path args).
4
+ //
5
+ // Windows compatible: path.resolve() and path.sep handle backslashes correctly.
6
+ // Do NOT use string concatenation with '/' — use path.resolve() + path.sep.
7
+ import * as path from 'path';
8
+ /**
9
+ * Resolves userPath and asserts it is within (or equal to) projectRoot.
10
+ *
11
+ * @param userPath The path supplied by the MCP tool caller (may be relative or absolute).
12
+ * @param projectRoot The project root to validate against (should be absolute).
13
+ * @returns The resolved absolute path on success.
14
+ * @throws Error If the resolved path escapes the project root.
15
+ */
16
+ export function validatePath(userPath, projectRoot) {
17
+ const resolved = path.resolve(userPath);
18
+ const normalizedRoot = path.resolve(projectRoot);
19
+ // Accept paths that are exactly the root or start with root + separator
20
+ // Using path.sep ensures correct behavior on Windows (backslash) and POSIX (slash)
21
+ if (resolved !== normalizedRoot &&
22
+ !resolved.startsWith(normalizedRoot + path.sep)) {
23
+ throw new Error(`Path traversal rejected: "${userPath}" resolves outside project root "${projectRoot}"`);
24
+ }
25
+ return resolved;
26
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "ultimate-unreal-engine-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server giving AI assistants full access to Unreal Engine 5.7 projects",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=22"
8
+ },
9
+ "main": "dist/index.js",
10
+ "bin": {
11
+ "ultimate-unreal-engine-mcp": "dist/cli.js"
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "unreal-plugin"
16
+ ],
17
+ "scripts": {
18
+ "dev": "tsx watch src/index.ts",
19
+ "build": "tsc -p tsconfig.build.json",
20
+ "start": "node dist/index.js",
21
+ "test": "vitest run",
22
+ "test:watch": "vitest",
23
+ "lint": "eslint src/"
24
+ },
25
+ "license": "MIT",
26
+ "dependencies": {
27
+ "@modelcontextprotocol/sdk": "1.29.0",
28
+ "minisearch": "^7.2.0",
29
+ "zod": "^3.25.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "latest",
33
+ "@typescript-eslint/eslint-plugin": "^8.60.0",
34
+ "@typescript-eslint/parser": "^8.60.0",
35
+ "eslint": "^10.4.1",
36
+ "tsx": "^4.22.3",
37
+ "typescript": "^6.0.3",
38
+ "vitest": "^4.1.7"
39
+ }
40
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "FileVersion": 3,
3
+ "Version": 1,
4
+ "VersionName": "1.0",
5
+ "FriendlyName": "MCPBridge",
6
+ "Description": "TCP bridge between the UE 5.7 Editor and the Model Context Protocol (MCP) server. Allows AI assistants to access live editor APIs via JSON-newline commands.",
7
+ "Category": "Editor",
8
+ "CreatedBy": "",
9
+ "CreatedByURL": "",
10
+ "DocsURL": "",
11
+ "MarketplaceURL": "",
12
+ "SupportURL": "",
13
+ "CanContainContent": false,
14
+ "IsBetaVersion": false,
15
+ "IsExperimentalVersion": false,
16
+ "Installed": false,
17
+ "Modules": [
18
+ {
19
+ "Name": "MCPBridgeRuntime",
20
+ "Type": "Runtime",
21
+ "LoadingPhase": "Default"
22
+ },
23
+ {
24
+ "Name": "MCPBridgeEditor",
25
+ "Type": "Editor",
26
+ "LoadingPhase": "PostEngineInit"
27
+ }
28
+ ]
29
+ }
@@ -0,0 +1,68 @@
1
+ // MCPBridgeEditor.Build.cs
2
+ // Editor module: UEditorSubsystem lifecycle, editor API handlers (Phases 8-29).
3
+ // Depends on MCPBridgeRuntime for the TCP server.
4
+ // This module is guarded by WITH_EDITOR -- never ships to cooked builds.
5
+
6
+ using UnrealBuildTool;
7
+
8
+ public class MCPBridgeEditor : ModuleRules
9
+ {
10
+ public MCPBridgeEditor(ReadOnlyTargetRules Target) : base(Target)
11
+ {
12
+ PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
13
+
14
+ PublicDependencyModuleNames.AddRange(new string[]
15
+ {
16
+ "Core",
17
+ "MCPBridgeRuntime",
18
+ });
19
+
20
+ PrivateDependencyModuleNames.AddRange(new string[]
21
+ {
22
+ "CoreUObject",
23
+ "Engine",
24
+ "UnrealEd",
25
+ "EditorSubsystem",
26
+ "Json",
27
+ "Kismet",
28
+ "BlueprintGraph",
29
+ "AssetRegistry",
30
+ "EnhancedInput",
31
+ "LevelEditor",
32
+ "SlateCore",
33
+ "DataValidation",
34
+ "LevelSequence",
35
+ "MovieScene",
36
+ "MovieSceneTracks",
37
+ "LevelSequenceEditor",
38
+ "MaterialEditor",
39
+ "AssetTools",
40
+ "AnimGraph",
41
+ "AnimGraphRuntime",
42
+ "IKRig",
43
+ "WorldPartitionEditor",
44
+ "PhysicsCore",
45
+ "MetasoundEngine",
46
+ "MetasoundFrontend",
47
+ "InterchangeEngine",
48
+ "InterchangePipelines",
49
+ "AIModule",
50
+ "StateTreeModule",
51
+ "NavigationSystem",
52
+ "GameplayAbilities", // Phase 25 - GAS
53
+ "GameplayTags", // Phase 25 - GAS
54
+ "GameplayTasks", // Phase 25 - GAS
55
+ "GeometryCollectionEngine", // Phase 26 - Chaos destruction (UGeometryCollectionComponent)
56
+ "ChaosCloth", // Phase 26 - Chaos cloth simulation parameters
57
+ "LiveLinkInterface", // Phase 27 - ILiveLinkClient, FLiveLinkSubjectKey, FLiveLinkSubjectFrameData
58
+ "LiveLink", // Phase 27 - ULiveLinkSubjectSettings for per-subject enabled state control
59
+ "AvalancheRundown", // Phase 28 - Motion Design Scene State machines (experimental)
60
+ "AvalancheTransition", // Phase 28 - Motion Design Transition Logic trees (experimental)
61
+ "RemoteControl", // Phase 28 - Remote Control preset read/write
62
+ "MovieRenderPipelineCore", // Phase 29 - UMoviePipelineQueue, UMoviePipelineExecutorJob, config/settings types
63
+ "MovieRenderPipelineEditor", // Phase 29 - UMoviePipelineQueueSubsystem
64
+ "OnlineSubsystem", // Phase 30 - IOnlineSubsystem, IOnlineSession, FOnlineSessionSettings
65
+ "OnlineSubsystemUtils", // Phase 30 - Online subsystem helper utilities
66
+ });
67
+ }
68
+ }