flockbay 0.10.15 → 0.10.17

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 (31) hide show
  1. package/dist/codex/flockbayMcpStdioBridge.cjs +339 -0
  2. package/dist/codex/flockbayMcpStdioBridge.mjs +339 -0
  3. package/dist/{index--o4BPz5o.cjs → index-BxBuBx7C.cjs} +2706 -609
  4. package/dist/{index-CUp3juDS.mjs → index-CHm9r89K.mjs} +2707 -611
  5. package/dist/index.cjs +3 -5
  6. package/dist/index.mjs +3 -5
  7. package/dist/lib.cjs +7 -9
  8. package/dist/lib.d.cts +219 -531
  9. package/dist/lib.d.mts +219 -531
  10. package/dist/lib.mjs +7 -9
  11. package/dist/{runCodex-D3eT-TvB.cjs → runCodex-DuCGwO2K.cjs} +264 -43
  12. package/dist/{runCodex-o6PCbHQ7.mjs → runCodex-DudVDqNh.mjs} +263 -42
  13. package/dist/{runGemini-CBxZp6I7.cjs → runGemini-B25LZ4Cw.cjs} +64 -29
  14. package/dist/{runGemini-Bt0oEj_g.mjs → runGemini-Ddu8UCOS.mjs} +63 -28
  15. package/dist/{types-C-jnUdn_.cjs → types-CGQhv7Z-.cjs} +470 -1146
  16. package/dist/{types-DGd6ea2Z.mjs → types-DuhcLxar.mjs} +469 -1142
  17. package/package.json +1 -1
  18. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintCommands.cpp +195 -6
  19. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintNodeCommands.cpp +376 -5
  20. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommandSchema.cpp +731 -0
  21. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommonUtils.cpp +476 -8
  22. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPEditorCommands.cpp +1518 -94
  23. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/MCPServerRunnable.cpp +7 -4
  24. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPBridge.cpp +150 -112
  25. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintCommands.h +2 -1
  26. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintNodeCommands.h +4 -1
  27. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPCommandSchema.h +42 -0
  28. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPEditorCommands.h +21 -0
  29. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/UnrealMCP.Build.cs +4 -1
  30. package/dist/flockbayScreenshotGate-DJX3Is5d.mjs +0 -136
  31. package/dist/flockbayScreenshotGate-DkxU24cR.cjs +0 -138
@@ -56,7 +56,7 @@ uint32 FMCPServerRunnable::Run()
56
56
  ClientSocket->SetSendBufferSize(SocketBufferSize, SocketBufferSize);
57
57
  ClientSocket->SetReceiveBufferSize(SocketBufferSize, SocketBufferSize);
58
58
 
59
- uint8 Buffer[8192];
59
+ uint8 Buffer[8192 + 1];
60
60
  while (bRunning)
61
61
  {
62
62
  int32 BytesRead = 0;
@@ -69,7 +69,9 @@ uint32 FMCPServerRunnable::Run()
69
69
  }
70
70
 
71
71
  // Convert received data to string
72
- Buffer[BytesRead] = '\0';
72
+ // Null-terminate safely (Recv can fill the entire buffer).
73
+ const int32 SafeIndex = FMath::Clamp(BytesRead, 0, 8192);
74
+ Buffer[SafeIndex] = '\0';
73
75
  FString ReceivedText = UTF8_TO_TCHAR(Buffer);
74
76
  UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Received: %s"), *ReceivedText);
75
77
 
@@ -90,8 +92,9 @@ uint32 FMCPServerRunnable::Run()
90
92
  UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Sending response: %s"), *Response);
91
93
 
92
94
  // Send response
95
+ FTCHARToUTF8 Utf8(*Response);
93
96
  int32 BytesSent = 0;
94
- if (!ClientSocket->Send((uint8*)TCHAR_TO_UTF8(*Response), Response.Len(), BytesSent))
97
+ if (!ClientSocket->Send((uint8*)Utf8.Get(), Utf8.Length(), BytesSent))
95
98
  {
96
99
  UE_LOG(LogTemp, Warning, TEXT("MCPServerRunnable: Failed to send response"));
97
100
  }
@@ -318,4 +321,4 @@ void FMCPServerRunnable::ProcessMessage(TSharedPtr<FSocket> Client, const FStrin
318
321
  {
319
322
  UE_LOG(LogTemp, Error, TEXT("MCPServerRunnable: Failed to send response"));
320
323
  }
321
- }
324
+ }
@@ -57,6 +57,7 @@
57
57
  #include "Commands/UnrealMCPProjectCommands.h"
58
58
  #include "Commands/UnrealMCPCommonUtils.h"
59
59
  #include "Commands/UnrealMCPUMGCommands.h"
60
+ #include "Commands/UnrealMCPCommandSchema.h"
60
61
  #include "Interfaces/IPluginManager.h"
61
62
 
62
63
  // Default settings
@@ -215,15 +216,31 @@ FString UUnrealMCPBridge::ExecuteCommand(const FString& CommandType, const TShar
215
216
  {
216
217
  TSharedPtr<FJsonObject> ResponseJson = MakeShareable(new FJsonObject);
217
218
 
218
- try
219
- {
220
- TSharedPtr<FJsonObject> ResultJson;
221
-
222
- if (CommandType == TEXT("ping"))
223
- {
224
- ResultJson = MakeShareable(new FJsonObject);
225
- ResultJson->SetStringField(TEXT("message"), TEXT("pong"));
226
- }
219
+ try
220
+ {
221
+ TSharedPtr<FJsonObject> ResultJson;
222
+
223
+ // Bridge-level helpers (keep these in the bridge so they always match the running plugin build).
224
+ if (CommandType == TEXT("list_capabilities"))
225
+ {
226
+ ResultJson = FUnrealMCPCommandSchemaRegistry::GetCapabilitiesResponse();
227
+ }
228
+ else if (CommandType == TEXT("get_command_schema"))
229
+ {
230
+ FString Requested;
231
+ if (Params.IsValid())
232
+ {
233
+ Params->TryGetStringField(TEXT("command"), Requested);
234
+ Params->TryGetStringField(TEXT("type"), Requested);
235
+ }
236
+ Requested = Requested.TrimStartAndEnd();
237
+ ResultJson = FUnrealMCPCommandSchemaRegistry::GetSchemaResponse(Requested);
238
+ }
239
+ else if (CommandType == TEXT("ping"))
240
+ {
241
+ ResultJson = MakeShareable(new FJsonObject);
242
+ ResultJson->SetStringField(TEXT("message"), TEXT("pong"));
243
+ }
227
244
  else if (CommandType == TEXT("get_plugin_info"))
228
245
  {
229
246
  TSharedPtr<IPlugin> Plugin = IPluginManager::Get().FindPlugin(TEXT("UnrealMCP"));
@@ -245,71 +262,26 @@ FString UUnrealMCPBridge::ExecuteCommand(const FString& CommandType, const TShar
245
262
  ResultJson->SetStringField(TEXT("name"), Plugin->GetName());
246
263
  ResultJson->SetStringField(TEXT("baseDir"), Plugin->GetBaseDir());
247
264
  ResultJson->SetStringField(TEXT("friendlyName"), Descriptor.FriendlyName);
248
- ResultJson->SetStringField(TEXT("createdBy"), Descriptor.CreatedBy);
249
- ResultJson->SetStringField(TEXT("versionName"), Descriptor.VersionName);
250
- ResultJson->SetNumberField(TEXT("version"), Descriptor.Version);
251
- ResultJson->SetBoolField(TEXT("installed"), Descriptor.bInstalled);
252
-
253
- // Keep this list explicit so it always matches the exact build running in the editor.
254
- TArray<TSharedPtr<FJsonValue>> Commands;
255
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("ping"))));
256
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("get_plugin_info"))));
257
-
258
- // Editor commands
259
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("get_actors_in_level"))));
260
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("find_actors_by_name"))));
261
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("spawn_actor"))));
262
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("create_actor"))));
263
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("delete_actor"))));
264
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("set_actor_transform"))));
265
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("get_actor_properties"))));
266
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("set_actor_property"))));
267
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("spawn_blueprint_actor"))));
268
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("focus_viewport"))));
269
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("take_screenshot"))));
270
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("get_play_in_editor_status"))));
271
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("play_in_editor"))));
272
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("play_in_editor_windowed"))));
273
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("stop_play_in_editor"))));
274
-
275
- // Blueprint commands
276
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("create_blueprint"))));
277
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("add_component_to_blueprint"))));
278
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("set_component_property"))));
279
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("set_physics_properties"))));
280
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("compile_blueprint"))));
281
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("set_blueprint_property"))));
282
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("set_static_mesh_properties"))));
283
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("set_pawn_properties"))));
284
-
285
- // Blueprint node commands
286
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("connect_blueprint_nodes"))));
287
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("add_blueprint_get_self_component_reference"))));
288
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("add_blueprint_self_reference"))));
289
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("find_blueprint_nodes"))));
290
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("add_blueprint_event_node"))));
291
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("add_blueprint_input_action_node"))));
292
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("add_blueprint_function_node"))));
293
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("add_blueprint_get_component_node"))));
294
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("add_blueprint_variable"))));
295
-
296
- // Project commands
297
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("create_input_mapping"))));
298
-
299
- // UMG commands
300
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("create_umg_widget_blueprint"))));
301
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("add_text_block_to_widget"))));
302
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("add_button_to_widget"))));
303
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("bind_widget_event"))));
304
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("set_text_block_binding"))));
305
- Commands.Add(MakeShareable(new FJsonValueString(TEXT("add_widget_to_viewport"))));
306
-
307
- ResultJson->SetArrayField(TEXT("commands"), Commands);
308
- }
265
+ ResultJson->SetStringField(TEXT("createdBy"), Descriptor.CreatedBy);
266
+ ResultJson->SetStringField(TEXT("versionName"), Descriptor.VersionName);
267
+ ResultJson->SetNumberField(TEXT("version"), Descriptor.Version);
268
+ ResultJson->SetBoolField(TEXT("installed"), Descriptor.bInstalled);
269
+ ResultJson->SetNumberField(TEXT("schemaVersion"), FUnrealMCPCommandSchemaRegistry::SchemaVersion());
270
+
271
+ // Keep this list explicit so it always matches the exact build running in the editor.
272
+ TArray<TSharedPtr<FJsonValue>> Commands;
273
+ for (const FString& Cmd : FUnrealMCPCommandSchemaRegistry::GetSupportedCommands())
274
+ {
275
+ Commands.Add(MakeShareable(new FJsonValueString(Cmd)));
276
+ }
277
+
278
+ ResultJson->SetArrayField(TEXT("commands"), Commands);
279
+ }
309
280
  // Editor Commands (including actor manipulation)
310
- else if (CommandType == TEXT("get_actors_in_level") ||
311
- CommandType == TEXT("find_actors_by_name") ||
312
- CommandType == TEXT("spawn_actor") ||
281
+ else if (CommandType == TEXT("get_actors_in_level") ||
282
+ CommandType == TEXT("find_actors_by_name") ||
283
+ CommandType == TEXT("spawn_actor") ||
284
+ CommandType == TEXT("create_landscape") ||
313
285
  CommandType == TEXT("create_actor") ||
314
286
  CommandType == TEXT("delete_actor") ||
315
287
  CommandType == TEXT("set_actor_transform") ||
@@ -318,53 +290,113 @@ FString UUnrealMCPBridge::ExecuteCommand(const FString& CommandType, const TShar
318
290
  CommandType == TEXT("spawn_blueprint_actor") ||
319
291
  CommandType == TEXT("focus_viewport") ||
320
292
  CommandType == TEXT("take_screenshot") ||
293
+ CommandType == TEXT("save_all") ||
321
294
  CommandType == TEXT("get_play_in_editor_status") ||
322
295
  CommandType == TEXT("play_in_editor") ||
323
296
  CommandType == TEXT("play_in_editor_windowed") ||
324
- CommandType == TEXT("stop_play_in_editor"))
325
- {
326
- ResultJson = EditorCommands->HandleCommand(CommandType, Params);
327
- }
297
+ CommandType == TEXT("stop_play_in_editor") ||
298
+ CommandType == TEXT("search_assets") ||
299
+ CommandType == TEXT("get_asset_info") ||
300
+ CommandType == TEXT("list_asset_packs") ||
301
+ CommandType == TEXT("place_asset") ||
302
+ CommandType == TEXT("map_check") ||
303
+ CommandType == TEXT("get_editor_context") ||
304
+ CommandType == TEXT("get_player_context") ||
305
+ CommandType == TEXT("raycast_from_camera") ||
306
+ CommandType == TEXT("raycast_down") ||
307
+ CommandType == TEXT("get_actor_transform") ||
308
+ CommandType == TEXT("get_actor_bounds"))
309
+ {
310
+ TSharedPtr<FJsonObject> NormalizedParams;
311
+ TSharedPtr<FJsonObject> SchemaError;
312
+ if (!FUnrealMCPCommandSchemaRegistry::NormalizeParams(CommandType, Params, NormalizedParams, SchemaError))
313
+ {
314
+ ResultJson = SchemaError;
315
+ }
316
+ else
317
+ {
318
+ ResultJson = EditorCommands->HandleCommand(CommandType, NormalizedParams);
319
+ }
320
+ }
328
321
  // Blueprint Commands
329
322
  else if (CommandType == TEXT("create_blueprint") ||
330
323
  CommandType == TEXT("add_component_to_blueprint") ||
331
324
  CommandType == TEXT("set_component_property") ||
332
325
  CommandType == TEXT("set_physics_properties") ||
333
326
  CommandType == TEXT("compile_blueprint") ||
327
+ CommandType == TEXT("compile_blueprints_all") ||
334
328
  CommandType == TEXT("set_blueprint_property") ||
335
- CommandType == TEXT("set_static_mesh_properties") ||
336
- CommandType == TEXT("set_pawn_properties"))
337
- {
338
- ResultJson = BlueprintCommands->HandleCommand(CommandType, Params);
339
- }
340
- // Blueprint Node Commands
341
- else if (CommandType == TEXT("connect_blueprint_nodes") ||
342
- CommandType == TEXT("add_blueprint_get_self_component_reference") ||
343
- CommandType == TEXT("add_blueprint_self_reference") ||
344
- CommandType == TEXT("find_blueprint_nodes") ||
345
- CommandType == TEXT("add_blueprint_event_node") ||
346
- CommandType == TEXT("add_blueprint_input_action_node") ||
347
- CommandType == TEXT("add_blueprint_function_node") ||
348
- CommandType == TEXT("add_blueprint_get_component_node") ||
349
- CommandType == TEXT("add_blueprint_variable"))
350
- {
351
- ResultJson = BlueprintNodeCommands->HandleCommand(CommandType, Params);
352
- }
353
- // Project Commands
354
- else if (CommandType == TEXT("create_input_mapping"))
355
- {
356
- ResultJson = ProjectCommands->HandleCommand(CommandType, Params);
357
- }
329
+ CommandType == TEXT("set_static_mesh_properties") ||
330
+ CommandType == TEXT("set_pawn_properties"))
331
+ {
332
+ TSharedPtr<FJsonObject> NormalizedParams;
333
+ TSharedPtr<FJsonObject> SchemaError;
334
+ if (!FUnrealMCPCommandSchemaRegistry::NormalizeParams(CommandType, Params, NormalizedParams, SchemaError))
335
+ {
336
+ ResultJson = SchemaError;
337
+ }
338
+ else
339
+ {
340
+ ResultJson = BlueprintCommands->HandleCommand(CommandType, NormalizedParams);
341
+ }
342
+ }
343
+ // Blueprint Node Commands
344
+ else if (CommandType == TEXT("connect_blueprint_nodes") ||
345
+ CommandType == TEXT("add_blueprint_get_self_component_reference") ||
346
+ CommandType == TEXT("add_blueprint_self_reference") ||
347
+ CommandType == TEXT("find_blueprint_nodes") ||
348
+ CommandType == TEXT("add_blueprint_event_node") ||
349
+ CommandType == TEXT("add_blueprint_input_action_node") ||
350
+ CommandType == TEXT("add_blueprint_function_node") ||
351
+ CommandType == TEXT("add_blueprint_get_component_node") ||
352
+ CommandType == TEXT("add_blueprint_variable") ||
353
+ CommandType == TEXT("search_blueprint_functions") ||
354
+ CommandType == TEXT("resolve_blueprint_function"))
355
+ {
356
+ TSharedPtr<FJsonObject> NormalizedParams;
357
+ TSharedPtr<FJsonObject> SchemaError;
358
+ if (!FUnrealMCPCommandSchemaRegistry::NormalizeParams(CommandType, Params, NormalizedParams, SchemaError))
359
+ {
360
+ ResultJson = SchemaError;
361
+ }
362
+ else
363
+ {
364
+ ResultJson = BlueprintNodeCommands->HandleCommand(CommandType, NormalizedParams);
365
+ }
366
+ }
367
+ // Project Commands
368
+ else if (CommandType == TEXT("create_input_mapping"))
369
+ {
370
+ TSharedPtr<FJsonObject> NormalizedParams;
371
+ TSharedPtr<FJsonObject> SchemaError;
372
+ if (!FUnrealMCPCommandSchemaRegistry::NormalizeParams(CommandType, Params, NormalizedParams, SchemaError))
373
+ {
374
+ ResultJson = SchemaError;
375
+ }
376
+ else
377
+ {
378
+ ResultJson = ProjectCommands->HandleCommand(CommandType, NormalizedParams);
379
+ }
380
+ }
358
381
  // UMG Commands
359
382
  else if (CommandType == TEXT("create_umg_widget_blueprint") ||
360
383
  CommandType == TEXT("add_text_block_to_widget") ||
361
384
  CommandType == TEXT("add_button_to_widget") ||
362
385
  CommandType == TEXT("bind_widget_event") ||
363
- CommandType == TEXT("set_text_block_binding") ||
364
- CommandType == TEXT("add_widget_to_viewport"))
365
- {
366
- ResultJson = UMGCommands->HandleCommand(CommandType, Params);
367
- }
386
+ CommandType == TEXT("set_text_block_binding") ||
387
+ CommandType == TEXT("add_widget_to_viewport"))
388
+ {
389
+ TSharedPtr<FJsonObject> NormalizedParams;
390
+ TSharedPtr<FJsonObject> SchemaError;
391
+ if (!FUnrealMCPCommandSchemaRegistry::NormalizeParams(CommandType, Params, NormalizedParams, SchemaError))
392
+ {
393
+ ResultJson = SchemaError;
394
+ }
395
+ else
396
+ {
397
+ ResultJson = UMGCommands->HandleCommand(CommandType, NormalizedParams);
398
+ }
399
+ }
368
400
  else
369
401
  {
370
402
  ResponseJson->SetStringField(TEXT("status"), TEXT("error"));
@@ -396,13 +428,19 @@ FString UUnrealMCPBridge::ExecuteCommand(const FString& CommandType, const TShar
396
428
  ResponseJson->SetStringField(TEXT("status"), TEXT("success"));
397
429
  ResponseJson->SetObjectField(TEXT("result"), ResultJson);
398
430
  }
399
- else
400
- {
401
- // Set error status and include the error message
402
- ResponseJson->SetStringField(TEXT("status"), TEXT("error"));
403
- ResponseJson->SetStringField(TEXT("error"), ErrorMessage);
404
- }
405
- }
431
+ else
432
+ {
433
+ // Set error status and include the error message
434
+ ResponseJson->SetStringField(TEXT("status"), TEXT("error"));
435
+ ResponseJson->SetStringField(TEXT("error"), ErrorMessage);
436
+
437
+ // Preserve structured error details when present.
438
+ if (ResultJson.IsValid() && ResultJson->HasTypedField<EJson::Object>(TEXT("details")))
439
+ {
440
+ ResponseJson->SetObjectField(TEXT("details"), ResultJson->GetObjectField(TEXT("details")));
441
+ }
442
+ }
443
+ }
406
444
  catch (const std::exception& e)
407
445
  {
408
446
  ResponseJson->SetStringField(TEXT("status"), TEXT("error"));
@@ -21,6 +21,7 @@ private:
21
21
  TSharedPtr<FJsonObject> HandleSetComponentProperty(const TSharedPtr<FJsonObject>& Params);
22
22
  TSharedPtr<FJsonObject> HandleSetPhysicsProperties(const TSharedPtr<FJsonObject>& Params);
23
23
  TSharedPtr<FJsonObject> HandleCompileBlueprint(const TSharedPtr<FJsonObject>& Params);
24
+ TSharedPtr<FJsonObject> HandleCompileBlueprintsAll(const TSharedPtr<FJsonObject>& Params);
24
25
  TSharedPtr<FJsonObject> HandleSpawnBlueprintActor(const TSharedPtr<FJsonObject>& Params);
25
26
  TSharedPtr<FJsonObject> HandleSetBlueprintProperty(const TSharedPtr<FJsonObject>& Params);
26
27
  TSharedPtr<FJsonObject> HandleSetStaticMeshProperties(const TSharedPtr<FJsonObject>& Params);
@@ -31,4 +32,4 @@ private:
31
32
  const FString& ComponentName, const FString& MeshType,
32
33
  const TArray<float>& Location, const TArray<float>& Rotation,
33
34
  const TArray<float>& Scale, const TSharedPtr<FJsonObject>& ComponentProperties);
34
- };
35
+ };
@@ -18,10 +18,13 @@ private:
18
18
  // Specific blueprint node command handlers
19
19
  TSharedPtr<FJsonObject> HandleConnectBlueprintNodes(const TSharedPtr<FJsonObject>& Params);
20
20
  TSharedPtr<FJsonObject> HandleAddBlueprintGetSelfComponentReference(const TSharedPtr<FJsonObject>& Params);
21
+ TSharedPtr<FJsonObject> HandleAddBlueprintGetComponentNode(const TSharedPtr<FJsonObject>& Params);
21
22
  TSharedPtr<FJsonObject> HandleAddBlueprintEvent(const TSharedPtr<FJsonObject>& Params);
22
23
  TSharedPtr<FJsonObject> HandleAddBlueprintFunctionCall(const TSharedPtr<FJsonObject>& Params);
23
24
  TSharedPtr<FJsonObject> HandleAddBlueprintVariable(const TSharedPtr<FJsonObject>& Params);
24
25
  TSharedPtr<FJsonObject> HandleAddBlueprintInputActionNode(const TSharedPtr<FJsonObject>& Params);
25
26
  TSharedPtr<FJsonObject> HandleAddBlueprintSelfReference(const TSharedPtr<FJsonObject>& Params);
26
27
  TSharedPtr<FJsonObject> HandleFindBlueprintNodes(const TSharedPtr<FJsonObject>& Params);
27
- };
28
+ TSharedPtr<FJsonObject> HandleSearchBlueprintFunctions(const TSharedPtr<FJsonObject>& Params);
29
+ TSharedPtr<FJsonObject> HandleResolveBlueprintFunction(const TSharedPtr<FJsonObject>& Params);
30
+ };
@@ -0,0 +1,42 @@
1
+ #pragma once
2
+
3
+ #include "CoreMinimal.h"
4
+ #include "Dom/JsonObject.h"
5
+
6
+ struct FUnrealMCPParamSchema
7
+ {
8
+ FString Name;
9
+ FString Type;
10
+ bool bRequired = false;
11
+ FString Description;
12
+ TArray<FString> Aliases;
13
+ TArray<FString> EnumValues;
14
+ TMap<FString, FString> ValueAliases;
15
+
16
+ TSharedPtr<FJsonObject> ToJson() const;
17
+ };
18
+
19
+ struct FUnrealMCPCommandSchema
20
+ {
21
+ FString Command;
22
+ FString Title;
23
+ FString Description;
24
+ TArray<FUnrealMCPParamSchema> Params;
25
+ TSharedPtr<FJsonObject> ExampleParams;
26
+
27
+ TSharedPtr<FJsonObject> ToJson() const;
28
+ };
29
+
30
+ class UNREALMCP_API FUnrealMCPCommandSchemaRegistry
31
+ {
32
+ public:
33
+ static int32 SchemaVersion();
34
+ static const FUnrealMCPCommandSchema* FindSchema(const FString& CommandType);
35
+ static TArray<FString> GetSupportedCommands();
36
+
37
+ // Returns { success:false, error, details:{...} } on validation issues.
38
+ static bool NormalizeParams(const FString& CommandType, const TSharedPtr<FJsonObject>& InParams, TSharedPtr<FJsonObject>& OutParams, TSharedPtr<FJsonObject>& OutError);
39
+ static TSharedPtr<FJsonObject> GetSchemaResponse(const FString& CommandTypeOrEmpty);
40
+ static TSharedPtr<FJsonObject> GetCapabilitiesResponse();
41
+ };
42
+
@@ -20,6 +20,7 @@ private:
20
20
  TSharedPtr<FJsonObject> HandleGetActorsInLevel(const TSharedPtr<FJsonObject>& Params);
21
21
  TSharedPtr<FJsonObject> HandleFindActorsByName(const TSharedPtr<FJsonObject>& Params);
22
22
  TSharedPtr<FJsonObject> HandleSpawnActor(const TSharedPtr<FJsonObject>& Params);
23
+ TSharedPtr<FJsonObject> HandleCreateLandscape(const TSharedPtr<FJsonObject>& Params);
23
24
  TSharedPtr<FJsonObject> HandleDeleteActor(const TSharedPtr<FJsonObject>& Params);
24
25
  TSharedPtr<FJsonObject> HandleSetActorTransform(const TSharedPtr<FJsonObject>& Params);
25
26
  TSharedPtr<FJsonObject> HandleGetActorProperties(const TSharedPtr<FJsonObject>& Params);
@@ -32,9 +33,29 @@ private:
32
33
  TSharedPtr<FJsonObject> HandleFocusViewport(const TSharedPtr<FJsonObject>& Params);
33
34
  TSharedPtr<FJsonObject> HandleTakeScreenshot(const TSharedPtr<FJsonObject>& Params);
34
35
 
36
+ // Editor save commands
37
+ TSharedPtr<FJsonObject> HandleSaveAll(const TSharedPtr<FJsonObject>& Params);
38
+
35
39
  // Editor play/preview commands
36
40
  TSharedPtr<FJsonObject> HandleGetPlayInEditorStatus(const TSharedPtr<FJsonObject>& Params);
37
41
  TSharedPtr<FJsonObject> HandlePlayInEditor(const TSharedPtr<FJsonObject>& Params);
38
42
  TSharedPtr<FJsonObject> HandlePlayInEditorWindowed(const TSharedPtr<FJsonObject>& Params);
39
43
  TSharedPtr<FJsonObject> HandleStopPlayInEditor(const TSharedPtr<FJsonObject>& Params);
44
+
45
+ // Asset discovery + placement
46
+ TSharedPtr<FJsonObject> HandleSearchAssets(const TSharedPtr<FJsonObject>& Params);
47
+ TSharedPtr<FJsonObject> HandleGetAssetInfo(const TSharedPtr<FJsonObject>& Params);
48
+ TSharedPtr<FJsonObject> HandleListAssetPacks(const TSharedPtr<FJsonObject>& Params);
49
+ TSharedPtr<FJsonObject> HandlePlaceAsset(const TSharedPtr<FJsonObject>& Params);
50
+
51
+ // Verify (editor diagnostics)
52
+ TSharedPtr<FJsonObject> HandleMapCheck(const TSharedPtr<FJsonObject>& Params);
53
+
54
+ // Context + spatial primitives
55
+ TSharedPtr<FJsonObject> HandleGetEditorContext(const TSharedPtr<FJsonObject>& Params);
56
+ TSharedPtr<FJsonObject> HandleGetPlayerContext(const TSharedPtr<FJsonObject>& Params);
57
+ TSharedPtr<FJsonObject> HandleRaycastFromCamera(const TSharedPtr<FJsonObject>& Params);
58
+ TSharedPtr<FJsonObject> HandleRaycastDown(const TSharedPtr<FJsonObject>& Params);
59
+ TSharedPtr<FJsonObject> HandleGetActorTransform(const TSharedPtr<FJsonObject>& Params);
60
+ TSharedPtr<FJsonObject> HandleGetActorBounds(const TSharedPtr<FJsonObject>& Params);
40
61
  };
@@ -44,8 +44,10 @@ public class UnrealMCP : ModuleRules
44
44
  "UnrealEd",
45
45
  "EditorScriptingUtilities",
46
46
  "EditorSubsystem",
47
+ "Landscape",
47
48
  "Slate",
48
49
  "SlateCore",
50
+ "MessageLog",
49
51
  "UMG",
50
52
  "Kismet",
51
53
  "KismetCompiler",
@@ -60,6 +62,7 @@ public class UnrealMCP : ModuleRules
60
62
  PrivateDependencyModuleNames.AddRange(
61
63
  new string[]
62
64
  {
65
+ "LandscapeEditor",
63
66
  "PropertyEditor", // For widget property editing
64
67
  "ToolMenus", // For editor UI
65
68
  "BlueprintEditorLibrary", // For Blueprint utilities
@@ -75,4 +78,4 @@ public class UnrealMCP : ModuleRules
75
78
  }
76
79
  );
77
80
  }
78
- }
81
+ }
@@ -1,136 +0,0 @@
1
- import path from 'node:path';
2
-
3
- function uniqPush(into, seen, value) {
4
- const v = value.trim();
5
- if (!v) return;
6
- if (seen.has(v)) return;
7
- seen.add(v);
8
- into.push(v);
9
- }
10
- function normalizeFilePathToken(token) {
11
- return token.trim().replace(/^['"`]+/, "").replace(/['"`]+$/, "").replace(/[),.;:'"`]+$/, "").trim();
12
- }
13
- function resolveCandidatePath(candidate, cwd) {
14
- const raw = normalizeFilePathToken(candidate);
15
- if (!raw) return raw;
16
- if (raw.startsWith("~/")) {
17
- const home = process.env.HOME || process.env.USERPROFILE || "";
18
- if (home) return path.join(home, raw.slice(2));
19
- }
20
- return path.isAbsolute(raw) ? raw : path.resolve(cwd, raw);
21
- }
22
- function isImageBlock(block) {
23
- if (!block || typeof block !== "object") return false;
24
- if (block.type !== "image") return false;
25
- if (typeof block.data === "string" && block.data.length > 0) return true;
26
- if (block.source && typeof block.source === "object" && typeof block.source.data === "string" && block.source.data.length > 0) return true;
27
- return false;
28
- }
29
- function tryParseJsonObjectWithViews(text) {
30
- const trimmed = text.trim();
31
- if (!trimmed) return null;
32
- try {
33
- const direct = JSON.parse(trimmed);
34
- if (direct && typeof direct === "object" && Array.isArray(direct.views)) return direct;
35
- } catch {
36
- }
37
- for (let i = trimmed.length - 1; i >= 0; i -= 1) {
38
- if (trimmed[i] !== "{") continue;
39
- const candidate = trimmed.slice(i);
40
- try {
41
- const parsed = JSON.parse(candidate);
42
- if (parsed && typeof parsed === "object" && Array.isArray(parsed.views)) return parsed;
43
- } catch {
44
- }
45
- }
46
- return null;
47
- }
48
- function extractScreenshotViewsFromText(text, cwd) {
49
- const out = [];
50
- const seen = /* @__PURE__ */ new Set();
51
- const re = /(?:^|[\s"'(])(?:-\s*)?([^\s"'()]*Saved[\\/]+Screenshots[\\/]+Flockbay[\\/]+[^\s"'()]+\.(?:png|jpg|jpeg))/gi;
52
- for (const match of text.matchAll(re)) {
53
- const token = String(match[1] || "");
54
- const resolved = resolveCandidatePath(token, cwd);
55
- if (!resolved) continue;
56
- if (!resolved.includes(`${path.sep}Saved${path.sep}Screenshots${path.sep}Flockbay${path.sep}`) && !resolved.includes("Saved/Screenshots/Flockbay/") && !resolved.includes("Saved\\Screenshots\\Flockbay\\")) {
57
- continue;
58
- }
59
- uniqPush(out, seen, resolved);
60
- }
61
- if (out.length === 0 && (text.includes("Saved/Screenshots/Flockbay") || text.includes("Saved\\Screenshots\\Flockbay"))) {
62
- const filenameRe = /(?:^|[\s"'(\\/])(?:-\s*)?(Flockbay_[A-Za-z0-9_.-]+\.(?:png|jpg|jpeg))/gi;
63
- for (const match of text.matchAll(filenameRe)) {
64
- const filename = normalizeFilePathToken(String(match[1] || ""));
65
- if (!filename) continue;
66
- const rel = path.join("Saved", "Screenshots", "Flockbay", filename);
67
- const resolved = resolveCandidatePath(rel, cwd);
68
- uniqPush(out, seen, resolved);
69
- }
70
- }
71
- return out;
72
- }
73
- function extractViewsFromParsedJson(parsed, cwd) {
74
- const out = [];
75
- const seen = /* @__PURE__ */ new Set();
76
- const views = Array.isArray(parsed?.views) ? parsed.views : [];
77
- for (const v of views) {
78
- const p = typeof v?.path === "string" ? v.path : "";
79
- if (!p.trim()) continue;
80
- uniqPush(out, seen, resolveCandidatePath(p, cwd));
81
- }
82
- return out;
83
- }
84
- function extractFromContentBlocks(content, cwd) {
85
- const texts = [];
86
- let hasImages = false;
87
- for (const block of content) {
88
- if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
89
- texts.push(block.text);
90
- }
91
- if (!hasImages && isImageBlock(block)) hasImages = true;
92
- }
93
- const text = texts.join("\n");
94
- const parsed = tryParseJsonObjectWithViews(text);
95
- const jsonPaths = parsed ? extractViewsFromParsedJson(parsed, cwd) : [];
96
- const pathMatches = extractScreenshotViewsFromText(text, cwd);
97
- const combined = [];
98
- const seen = /* @__PURE__ */ new Set();
99
- for (const p of jsonPaths) uniqPush(combined, seen, p);
100
- for (const p of pathMatches) uniqPush(combined, seen, p);
101
- return { paths: combined, hasImages };
102
- }
103
- function detectScreenshotsForGate(args) {
104
- const cwd = args.cwd && args.cwd.trim().length > 0 ? args.cwd : process.cwd();
105
- const output = args.output;
106
- if (Array.isArray(output)) {
107
- const extracted = extractFromContentBlocks(output, cwd);
108
- return { paths: extracted.paths, hasImageBlocks: extracted.hasImages };
109
- }
110
- if (output && typeof output === "object" && Array.isArray(output.content)) {
111
- const extracted = extractFromContentBlocks(output.content, cwd);
112
- return { paths: extracted.paths, hasImageBlocks: extracted.hasImages };
113
- }
114
- if (output && typeof output === "object" && Array.isArray(output.views)) {
115
- return { paths: extractViewsFromParsedJson(output, cwd), hasImageBlocks: false };
116
- }
117
- const candidates = [
118
- typeof output === "string" ? output : null,
119
- typeof output?.stdout === "string" ? output.stdout : null,
120
- typeof output?.stderr === "string" ? output.stderr : null,
121
- typeof output?.output === "string" ? output.output : null,
122
- typeof output?.message === "string" ? output.message : null
123
- ];
124
- const combinedText = candidates.filter((v) => typeof v === "string" && v.trim().length > 0).join("\n");
125
- if (!combinedText) return { paths: [], hasImageBlocks: false };
126
- const parsed = tryParseJsonObjectWithViews(combinedText);
127
- const jsonPaths = parsed ? extractViewsFromParsedJson(parsed, cwd) : [];
128
- const pathMatches = extractScreenshotViewsFromText(combinedText, cwd);
129
- const out = [];
130
- const seen = /* @__PURE__ */ new Set();
131
- for (const p of jsonPaths) uniqPush(out, seen, p);
132
- for (const p of pathMatches) uniqPush(out, seen, p);
133
- return { paths: out, hasImageBlocks: false };
134
- }
135
-
136
- export { detectScreenshotsForGate as d };