ue-mcp 1.2.4 → 1.3.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 (243) hide show
  1. package/README.md +4 -3
  2. package/dist/action-class.js +56 -3
  3. package/dist/action-class.js.map +1 -1
  4. package/dist/bridge-timeouts.d.ts +64 -0
  5. package/dist/bridge-timeouts.js +118 -0
  6. package/dist/bridge-timeouts.js.map +1 -0
  7. package/dist/bridge.js +10 -2
  8. package/dist/bridge.js.map +1 -1
  9. package/dist/editor-control.d.ts +72 -5
  10. package/dist/editor-control.js +164 -140
  11. package/dist/editor-control.js.map +1 -1
  12. package/dist/editor-target.d.ts +55 -1
  13. package/dist/editor-target.js +107 -10
  14. package/dist/editor-target.js.map +1 -1
  15. package/dist/engine-observer.d.ts +59 -5
  16. package/dist/engine-observer.js +249 -29
  17. package/dist/engine-observer.js.map +1 -1
  18. package/dist/engine-root.d.ts +91 -0
  19. package/dist/engine-root.js +448 -0
  20. package/dist/engine-root.js.map +1 -0
  21. package/dist/epic-enrich.js +16 -1
  22. package/dist/epic-enrich.js.map +1 -1
  23. package/dist/feedback-cli.js +4 -0
  24. package/dist/feedback-cli.js.map +1 -1
  25. package/dist/feedback-deferred.d.ts +9 -0
  26. package/dist/feedback-deferred.js +2 -0
  27. package/dist/feedback-deferred.js.map +1 -1
  28. package/dist/feedback-fallback.d.ts +99 -0
  29. package/dist/feedback-fallback.js +173 -0
  30. package/dist/feedback-fallback.js.map +1 -0
  31. package/dist/flow/write-methods.js +20 -0
  32. package/dist/flow/write-methods.js.map +1 -1
  33. package/dist/lean-context.js +8 -3
  34. package/dist/lean-context.js.map +1 -1
  35. package/dist/locking.js +11 -2
  36. package/dist/locking.js.map +1 -1
  37. package/dist/project.d.ts +11 -0
  38. package/dist/project.js +23 -2
  39. package/dist/project.js.map +1 -1
  40. package/dist/python-gate.d.ts +95 -0
  41. package/dist/python-gate.js +175 -0
  42. package/dist/python-gate.js.map +1 -0
  43. package/dist/tool-counts.json +16 -16
  44. package/dist/tools/animation.js +288 -24
  45. package/dist/tools/animation.js.map +1 -1
  46. package/dist/tools/asset.js +79 -14
  47. package/dist/tools/asset.js.map +1 -1
  48. package/dist/tools/audio.js +59 -5
  49. package/dist/tools/audio.js.map +1 -1
  50. package/dist/tools/blueprint.js +29 -12
  51. package/dist/tools/blueprint.js.map +1 -1
  52. package/dist/tools/chooser.js +4 -1
  53. package/dist/tools/chooser.js.map +1 -1
  54. package/dist/tools/editor.js +81 -43
  55. package/dist/tools/editor.js.map +1 -1
  56. package/dist/tools/feedback.js +214 -48
  57. package/dist/tools/feedback.js.map +1 -1
  58. package/dist/tools/foliage.js +27 -1
  59. package/dist/tools/foliage.js.map +1 -1
  60. package/dist/tools/gameplay.js +38 -11
  61. package/dist/tools/gameplay.js.map +1 -1
  62. package/dist/tools/gas.js +17 -5
  63. package/dist/tools/gas.js.map +1 -1
  64. package/dist/tools/landscape.js +22 -7
  65. package/dist/tools/landscape.js.map +1 -1
  66. package/dist/tools/level.js +322 -51
  67. package/dist/tools/level.js.map +1 -1
  68. package/dist/tools/material.js +10 -4
  69. package/dist/tools/material.js.map +1 -1
  70. package/dist/tools/niagara.js +3 -2
  71. package/dist/tools/niagara.js.map +1 -1
  72. package/dist/tools/pcg.js +6 -5
  73. package/dist/tools/pcg.js.map +1 -1
  74. package/dist/tools/project.js +47 -20
  75. package/dist/tools/project.js.map +1 -1
  76. package/dist/types.d.ts +21 -0
  77. package/dist/types.js +46 -3
  78. package/dist/types.js.map +1 -1
  79. package/dist/ue-mcp.default.yml +493 -125
  80. package/package.json +2 -2
  81. package/plugin/ue_mcp_bridge/NATIVE_RUNTIME_VISIBILITY.md +53 -0
  82. package/plugin/ue_mcp_bridge/NATIVE_STATIC_MESH_USAGE_PROGRESS.md +115 -0
  83. package/plugin/ue_mcp_bridge/README_MassHandlers.md +97 -0
  84. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/BridgeServer.cpp +14 -0
  85. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.cpp +21 -4
  86. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.h +9 -0
  87. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerJsonProperty.h +395 -69
  88. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.cpp +79 -3
  89. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.h +25 -0
  90. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRig.cpp +3 -3
  91. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRigSequencer.cpp +3061 -0
  92. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRetargeterAuthoring.cpp +961 -0
  93. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRigAuthoring.cpp +900 -0
  94. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Pose.cpp +769 -0
  95. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Sequence.cpp +44 -3
  96. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_SkeletalLive.cpp +217 -11
  97. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_StateMachine.cpp +551 -24
  98. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Validation.cpp +735 -0
  99. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.cpp +352 -73
  100. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.h +8 -0
  101. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkProperties.cpp +1 -1
  102. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.cpp +503 -0
  103. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.h +21 -0
  104. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkUpsert.cpp +2 -2
  105. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Enum.cpp +2 -2
  106. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.cpp +902 -0
  107. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.h +33 -0
  108. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Import.cpp +478 -134
  109. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Mesh.cpp +5 -5
  110. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.cpp +933 -0
  111. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.h +35 -0
  112. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Redirectors.cpp +478 -0
  113. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_RenderTarget.cpp +1 -1
  114. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Sockets.cpp +4 -4
  115. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Struct.cpp +2 -2
  116. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Subobject.cpp +319 -0
  117. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_SoundCue.cpp +3 -3
  118. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.cpp +482 -35
  119. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.h +10 -0
  120. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.cpp +502 -0
  121. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.h +43 -0
  122. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Functions.cpp +89 -7
  123. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Graph.cpp +17 -51
  124. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Internal.h +107 -0
  125. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Properties.cpp +10 -10
  126. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Search.cpp +648 -0
  127. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.cpp +5 -1
  128. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.cpp +252 -1
  129. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.h +10 -2
  130. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.cpp +252 -41
  131. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.h +4 -0
  132. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +250 -27
  133. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIE.cpp +303 -125
  134. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIERuntime.cpp +73 -50
  135. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_RuntimeVisibility.cpp +757 -0
  136. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.cpp +11 -2
  137. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.h +3 -0
  138. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers_Batch.cpp +419 -0
  139. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.cpp +39 -161
  140. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.h +66 -1
  141. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BTAuthoring.cpp +1323 -0
  142. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BehaviorTree.cpp +1211 -0
  143. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.cpp +2 -0
  144. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +60 -0
  145. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers_Runtime.cpp +363 -12
  146. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/HandlerEditorState.h +84 -0
  147. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +1288 -36
  148. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.h +3 -0
  149. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +41 -16
  150. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.cpp +959 -213
  151. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.h +66 -0
  152. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_BatchWrite.cpp +1571 -0
  153. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Convert.cpp +316 -0
  154. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Inspection.cpp +280 -0
  155. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection.cpp +666 -0
  156. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection_Internal.h +63 -0
  157. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Lights.cpp +43 -12
  158. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_MultiLevel.cpp +13 -47
  159. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_PostProcess.cpp +527 -0
  160. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Query.cpp +1169 -0
  161. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Refresh.cpp +723 -0
  162. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Save.cpp +325 -0
  163. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Spatial.cpp +360 -0
  164. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Trace.cpp +178 -58
  165. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Transient.cpp +337 -0
  166. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Volumes.cpp +25 -12
  167. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartition.cpp +10 -9
  168. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartitionSettings.cpp +686 -0
  169. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.cpp +467 -0
  170. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.h +22 -0
  171. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.cpp +452 -175
  172. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.h +5 -0
  173. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Build.cpp +597 -0
  174. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers.cpp +17 -15
  175. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PCGHandlers.cpp +38 -168
  176. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.cpp +39 -30
  177. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +392 -78
  178. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.h +2 -0
  179. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers_Internal.h +83 -0
  180. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.cpp +200 -0
  181. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.h +15 -0
  182. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.cpp +19 -12
  183. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers.cpp +31 -1
  184. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.cpp +307 -69
  185. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.h +84 -0
  186. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Extraction.cpp +8 -41
  187. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Properties.cpp +33 -52
  188. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/ActorSelectorTests.cpp +344 -0
  189. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationControlRigTimelineTests.cpp +60 -0
  190. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationPoseTests.cpp +115 -0
  191. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetBulkReadTests.cpp +177 -0
  192. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetDeleteGuardTests.cpp +276 -0
  193. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPathResolutionTests.cpp +243 -0
  194. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPropertyPersistTests.cpp +213 -0
  195. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetSubobjectTests.cpp +235 -0
  196. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AutomationRunnerTests.cpp +72 -0
  197. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeAuthoringTests.cpp +526 -0
  198. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeNodeTests.cpp +334 -0
  199. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BlueprintHandlerSurfaceTests.cpp +362 -0
  200. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BridgeProtocolTests.cpp +14 -0
  201. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/CollisionQueryTests.cpp +288 -0
  202. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/DataTableRowWriteTests.cpp +453 -0
  203. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/EditorFunctionCallTests.cpp +223 -0
  204. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/FoliageBatchTests.cpp +147 -0
  205. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GameThreadGateTests.cpp +82 -0
  206. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GasLiveAttributeTests.cpp +183 -0
  207. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LandscapeSampleTests.cpp +119 -0
  208. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelBatchWriteTests.cpp +176 -0
  209. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelComponentTreeInstanceCountTests.cpp +189 -0
  210. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelConvertBrushesTests.cpp +100 -0
  211. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelInstanceProjectionTests.cpp +265 -0
  212. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelPostProcessOverrideTests.cpp +258 -0
  213. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelQueryComponentsTests.cpp +195 -0
  214. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelRefreshTests.cpp +142 -0
  215. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelSaveReportTests.cpp +125 -0
  216. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelScriptHandlersTests.cpp +42 -0
  217. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelStaticMeshUsageTests.cpp +412 -0
  218. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTraceWorldScopeTests.cpp +133 -0
  219. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTransientActorTests.cpp +205 -0
  220. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelWorldPartitionSettingsTests.cpp +168 -0
  221. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTestTypes.h +51 -0
  222. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTests.cpp +379 -0
  223. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MaterialBuildTests.cpp +238 -0
  224. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshBooleanTests.cpp +170 -0
  225. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshGeometryTests.cpp +116 -0
  226. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageSaveExtensionTests.cpp +161 -0
  227. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageWriteGuardTests.cpp +253 -0
  228. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/RuntimeVisibilityTests.cpp +143 -0
  229. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerHandlerTests.cpp +660 -0
  230. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerScrubTests.cpp +50 -0
  231. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SkeletonDiffTests.cpp +685 -0
  232. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/WidgetBlueprintResolveTests.cpp +145 -0
  233. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/UE_MCP_Bridge.cpp +80 -0
  234. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerFunctionCall.h +509 -0
  235. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerQuery.h +407 -0
  236. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerUtils.h +1008 -77
  237. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/UE_MCP_Bridge.Build.cs +87 -0
  238. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/MCPEngineStatus.cpp +152 -14
  239. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/Tests/MCPEngineStatusTests.cpp +65 -0
  240. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Public/MCPEngineStatus.h +32 -1
  241. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/UE_MCP_BridgeStatus.Build.cs +2 -0
  242. package/skills/ue-mcp-animation/SKILL.md +154 -0
  243. package/skills/ue-mcp-blueprint/SKILL.md +71 -0
@@ -98,11 +98,9 @@ tasks:
98
98
  options:
99
99
  method: set_config
100
100
  project.build:
101
- class_path: ue-mcp.bridge
101
+ class_path: project.build
102
102
  group: project
103
- description: "Build C++ project. Params: configuration?, platform?, clean?"
104
- options:
105
- method: build_project
103
+ description: "Build the project's C++ out of process with UnrealBuildTool. Works with the editor STOPPED, which a full rebuild requires (UBT cannot link while an editor holds the module DLLs). Blocks until the build finishes and returns the compiler output. Params: configuration? (default Development), platform? (default the host platform), clean? (#958)"
106
104
  project.generate_project_files:
107
105
  class_path: ue-mcp.bridge
108
106
  group: project
@@ -145,6 +143,12 @@ tasks:
145
143
  description: Report Live Coding availability/state (available, started, enabledForSession, compiling). Helps choose between live_coding_compile and build_project.
146
144
  options:
147
145
  method: live_coding_status
146
+ project.resolve_collision_profile:
147
+ class_path: ue-mcp.bridge
148
+ group: project
149
+ description: "Read one collision profile's resolved per-channel responses: collisionEnabled, objectType, and every channel with Block/Overlap/Ignore. This is the project-side half of blueprint(get_component_collision) (#925): a component's ResponseArray only lists the channels it OVERRIDES, so the profile is where an inherited response actually comes from. Project trace and object channels appear under their configured names, with enumName (ECC_GameTraceChannel1) alongside so a caller can key on something stable. By default the eight engine channels plus every channel the project configured are returned; includeAllChannels=true adds the unused slots. channel narrows it to one. A profile that does not exist lists the ones that do. Params: profileName, channel?, includeAllChannels?"
150
+ options:
151
+ method: resolve_collision_profile
148
152
  project.write_cpp_file:
149
153
  class_path: project.write_cpp_file
150
154
  group: project
@@ -220,9 +224,15 @@ tasks:
220
224
  asset.bulk_rename:
221
225
  class_path: ue-mcp.bridge
222
226
  group: asset
223
- description: "Batched rename using IAssetTools::RenameAssets - single transaction with one redirector-fixup pass (matches Content Browser drag). Use this over looped rename for scene-referenced assets. World assets are rejected (status=rejected_world); use rename_asset which handles WP externals atomically (#409). Params: renames[] where each entry is {sourcePath, destinationPath} OR {assetPath, newName}."
227
+ description: "Batched rename using IAssetTools::RenameAssets - single transaction with one redirector-fixup pass (matches Content Browser drag). Use this over looped rename for scene-referenced assets. World assets are rejected (status=rejected_world); use rename_asset which handles WP externals atomically (#409). The fix-up pass cannot see a referencer that is not loaded, so each renamed item reports redirectorLeft and the result carries redirectorsLeft/redirectorsRemoved plus redirectorPackages, which feeds straight into fixup_redirectors (#908). Params: renames[] where each entry is {sourcePath, destinationPath} OR {assetPath, newName}."
224
228
  options:
225
229
  method: bulk_rename_assets
230
+ asset.fixup_redirectors:
231
+ class_path: ue-mcp.bridge
232
+ group: asset
233
+ description: "Clean up ObjectRedirectors left at the old paths after a move, bounded to exactly the packages you name. Preflights each redirector, its destination, and its hard AND soft referencers, then reports packagesToLoad/packagesToSave before touching anything; dryRun=true stops there. The real run loads only those referencers (a soft reference in an unloaded package is what the rename's own fix-up pass misses), rewrites them, saves them, RE-QUERIES the asset registry, and deletes a redirector only when nothing references it any more, reporting kept vs deleted per package with the referencers that survived. Naming a whole content root is refused unless allowProjectWide=true, so this can never turn into a project-wide resave. Protected mounts are refused outright. dryRun is the way to preview: save=false only skips the explicit save pass, because the editor's own fix-up writes what it can regardless. Params: paths[] (redirector packages or the folders holding them), dryRun? (default false), save? (default true), allowProjectWide? (default false) (#908)"
234
+ options:
235
+ method: fixup_redirectors
226
236
  asset.move:
227
237
  class_path: ue-mcp.bridge
228
238
  group: asset
@@ -232,13 +242,13 @@ tasks:
232
242
  asset.delete:
233
243
  class_path: ue-mcp.bridge
234
244
  group: asset
235
- description: "Delete asset. On failure returns reason (open_in_editor / has_referencers / in_memory_referenced / package_read_only / package_dirty / unknown) plus referencers, inMemoryReferencers, packageReadOnly, packageDirty diagnostics (#601). Pass force=true to auto-close any open asset editors before deleting (#278). Params: assetPath, force?"
245
+ description: "Delete asset. force defaults to false and is a REAL guard: the bridge asks the Asset Registry for referencers first and refuses with success=false, reason='has_referencers' and the full referencers list rather than destroying an asset other packages point at (#976). force=true takes the force-delete path, which also auto-closes open asset editors (#278). On a delete the editor attempted and could not finish, the reason is open_in_editor / has_referencers / in_memory_referenced / package_read_only / package_dirty / unknown, with referencers, inMemoryReferencers, packageReadOnly and packageDirty diagnostics (#601). Params: assetPath, force?"
236
246
  options:
237
247
  method: delete_asset
238
248
  asset.delete_batch:
239
249
  class_path: ue-mcp.bridge
240
250
  group: asset
241
- description: "Batch-delete assets. Per-path status (deleted/absent/failed) plus reason+referencers on failed entries (#278). Params: assetPaths[], force?"
251
+ description: "Batch-delete assets. Per-path status is deleted | absent | protected | refused | failed, plus reason+referencers on refused and failed entries. A referenced asset is refused per entry with force=false and the rest of the batch still runs, so one guarded asset never hides behind a bare failed count (#976, #278). Result carries deleted/absent/refused/failed/protected/total. Params: assetPaths[], force?"
242
252
  options:
243
253
  method: delete_asset_batch
244
254
  asset.create_data_asset:
@@ -253,6 +263,12 @@ tasks:
253
263
  description: "Create an asset of ANY concrete UObject class (not just UDataAsset) - physical-material subclasses, curves, settings objects. className accepts the C++ spelling with or without the A/U/F/E prefix, a /Script/Module.ClassName path, or a loaded class name (#823). Params: name, className, packagePath?, properties? (key/value map), onConflict? (skip|replace|rename). Actors/components and specialized assets (Blueprint/Material) have dedicated actions (#726)"
254
264
  options:
255
265
  method: create_asset_by_class
266
+ asset.create_subobject:
267
+ class_path: ue-mcp.bridge
268
+ group: asset
269
+ description: "Create a named subobject OWNED by an existing asset, inside that asset's package, and return its object path for later property writes. This is the missing half of editing a data asset whose payload is named subobjects referenced from a struct array: set_property, bulk_set_properties and append_array_elements can edit the entries, and this makes a new one. Component classes are accepted, unlike create_asset_by_class; Actors are refused because they are spawned into a level. className takes a /Script/Module.Class path, which is how you name a plugin class the Python `unreal` module never exposes. The new object is created RF_Standalone and the package is saved in the same call, so it survives the garbage collection that used to eat a fresh object within one call and is reachable by path from the next one. properties are applied to a throwaway instance first, so a bad path or value creates nothing. outer='asset' (default) gives '<asset>.<name>'; outer='package' puts it beside the asset in the package. Params: assetPath, className, name, properties?, outer? (asset|package), onConflict? (reuse|error), save? (default true) (#975)"
270
+ options:
271
+ method: create_subobject
256
272
  asset.bulk_upsert_data_assets:
257
273
  class_path: ue-mcp.bridge
258
274
  group: asset
@@ -541,6 +557,12 @@ tasks:
541
557
  description: "Import StringTable entries from CSV. Params: assetPath, filePath (or csvPath)"
542
558
  options:
543
559
  method: import_stringtable
560
+ asset.import_stringtable_csv:
561
+ class_path: ue-mcp.bridge
562
+ group: asset
563
+ description: "Import or refresh a String Table from a CSV that is the canonical source, using Unreal's own String Table CSV importer. The CSV is parsed into a throwaway table and checked against expectedKeys FIRST, so a malformed file or a key set that does not match leaves the asset untouched and comes back with missingKeys/unexpectedKeys instead. replaceExisting=true prunes entries the CSV no longer carries, which is what makes the CSV canonical rather than additive; the prune runs after a successful merge so a bad parse can never empty the table. Returns addedKeys, updatedKeys, removedKeys, entry counts and an explicit persisted/saved plus persistError, so a write that did not reach disk is never reported as a success. A relative csvPath is read against the project directory. Params: assetPath, csvPath (or filePath), expectedKeys? (string[]), requireExactKeys? (default false), replaceExisting? (default false), save? (default true) (#978)"
564
+ options:
565
+ method: import_stringtable_csv
544
566
  asset.add_input_mapping:
545
567
  class_path: ue-mcp.bridge
546
568
  group: asset
@@ -586,13 +608,13 @@ tasks:
586
608
  asset.set_property:
587
609
  class_path: ue-mcp.bridge
588
610
  group: asset
589
- description: "Set a UPROPERTY on any loaded asset (Material, DataAsset, DataTable, SubsurfaceProfile, etc.) using a dotted path. Blueprint paths resolve to the generated-class CDO so you can author its defaults + Instanced sub-object arrays (#568). Walks nested structs, array elements by index, and instanced subobjects internally - no more read-modify-write copies (e.g. `settings.mean_free_path_distance` on a UMaterial, or `Config.Traits[1].Params.Field` on a config asset #527). Value goes through MCPJsonProperty::SetJsonOnProperty so JSON null clears object refs, structs accept {x,y,z}, arrays/maps round-trip. TMap values take { \"Key\": value } or, for struct keys, [{ key: {...}, value: ... }]; a write that cannot store every entry fails and leaves the old value untouched (#820). Params: assetPath, propertyName (dotted path), value (#420)"
611
+ description: "Set a UPROPERTY on any loaded asset (Material, DataAsset, DataTable, SubsurfaceProfile, etc.) using a dotted path. Blueprint paths resolve to the generated-class CDO so you can author its defaults + Instanced sub-object arrays (#568). Walks nested structs, array elements by index, and instanced subobjects internally - no more read-modify-write copies (e.g. `settings.mean_free_path_distance` on a UMaterial, or `Config.Traits[1].Params.Field` on a config asset #527). Value goes through MCPJsonProperty::SetJsonOnProperty so JSON null clears object refs, structs accept {x,y,z}, arrays/maps round-trip. TMap values take { \"Key\": value } or, for struct keys, [{ key: {...}, value: ... }]; a write that cannot store every entry fails and leaves the old value untouched (#820). The write is saved to the package by default and the result reports persisted plus the package name; a write that could not reach disk (save=false, a protected mount, a read-only file, a refused save) comes back with persisted=false and persistError naming the reason instead of a bare success that reverts on the next editor start (#931). Params: assetPath, propertyName (dotted path), value, save? (default true) (#420)"
590
612
  options:
591
613
  method: set_asset_property
592
614
  asset.append_array_elements:
593
615
  class_path: ue-mcp.bridge
594
616
  group: asset
595
- description: "Append one or more JSON values to a reflected TArray without replacing existing entries. Supports dotted property paths plus native and user-defined USTRUCT elements. All elements are validated before mutation; returns appended indices and rollback data, and leaves the package dirty without saving. Params: assetPath, propertyName, elements"
617
+ description: "Append one or more JSON values to a reflected TArray without replacing existing entries. Supports dotted property paths plus native and user-defined USTRUCT elements. All elements are validated before mutation; returns appended indices and rollback data. The append is saved to the package by default and reports persisted / persistError the same way set_property does (#931). Params: assetPath, propertyName, elements, save? (default true)"
596
618
  options:
597
619
  method: append_asset_array_elements
598
620
  asset.bulk_set_properties:
@@ -601,6 +623,12 @@ tasks:
601
623
  description: "Set dotted UPROPERTY paths on as many as 500 assets in one preflighted batch. Every asset, path, and value is validated before anything is mutated, and every submitted item comes back with its own ok/status/error, so a bad path in item 300 never hides the other 499 verdicts. Default is all-or-nothing: any preflight rejection aborts before a single UObject is touched. Pass continueOnError to apply the items that did pass and keep the rejects reported alongside them. Returns per-property readback, aggregate counts, targeted save results, and a replayable rollback payload covering only the writes that landed. Params: items ([{assetPath, properties}]), save? (default true), dryRun? (default false), continueOnError? (default false)"
602
624
  options:
603
625
  method: bulk_set_asset_properties
626
+ asset.bulk_read_properties:
627
+ class_path: ue-mcp.bridge
628
+ group: asset
629
+ description: "Read the SAME properties off many assets in one call, filtered and aggregated in the editor. read_properties answers one asset per call, which turns a library-wide question (concurrency settings across 582 sound assets, cull distances across 201 foliage types) into a loop. Select with assetPaths[] or directory + classNames[]; propertyNames accepts dotted paths into nested structs (e.g. 'CullDistance.Max'), and a Blueprint path reads its generated-class CDO. Predicates, groupBy and countBy all evaluate here: filtering happens before anything crosses the wire. Absent and null are reported separately, because 'this class has no such property' and 'this property is unset' are different findings; suspect is true for either, and suspectOnly returns just those rows. Never writes, and reports dirtiedPackages. Params: assetPaths? (string[]) OR directory? (+ recursive?, default true), classNames? (string[]), matchSubclasses? (default true), propertyNames (string[], required, max 32), where? ([{field, op, value}] over props.<name>, className, suspect; same operators as level(query_components)), whereMode? (all|any), suspectOnly?, groupBy?, countBy? (string[]), sampleLimit?, countOnly?, limit? (default 200, max 2000), startIndex?, maxAssets? (default 2000, max 20000), outputPath? (write every matched row to a JSON file and return the path instead of the rows) (#909)"
630
+ options:
631
+ method: bulk_read_asset_properties
604
632
  asset.set_texture_settings_by_type:
605
633
  class_path: ue-mcp.bridge
606
634
  group: asset
@@ -709,6 +737,24 @@ tasks:
709
737
  description: "Inspect StaticMesh collision setup. Params: assetPath. Returns collisionTraceFlag, hasSimple/ComplexCollision, element counts (#177)"
710
738
  options:
711
739
  method: get_mesh_collision
740
+ asset.get_mesh_geometry:
741
+ class_path: ue-mcp.bridge
742
+ group: asset
743
+ description: "Read actual vertex data off a StaticMesh OR SkeletalMesh: per-section positions, uvs, normals and triangle indices, from the engine's render data (no ProceduralMeshComponent plugin needed). Triangle indices are section-local, so they index that section's own positions array; add baseVertexIndex for LOD-global indices. Over 20000 vertices inline is refused - pass dumpToFile to write the full data to a JSON file instead, or narrow with sectionIndex. Params: assetPath, lodIndex? (default 0), sectionIndex? (omit for all sections), include? ([positions|uvs|normals|triangles], omit for all), uvChannel? (default 0), dumpToFile?, outputPath? (#948/#926/#953)"
744
+ options:
745
+ method: get_mesh_geometry
746
+ asset.measure_mesh_geometry:
747
+ class_path: ue-mcp.bridge
748
+ group: asset
749
+ description: "Measure a StaticMesh OR SkeletalMesh LOD: bounds, dimensions, surfaceArea, volume, triangleCount, vertexCount, isClosed, isManifold, boundaryEdgeCount, nonManifoldEdgeCount. surfaceArea and volume are NAMED fields, never a positional pair (the engine's get_mesh_volume_area returns them in the order opposite to its name, #938). Vertices are welded by position before topology analysis so a UV seam does not read as a hole. Params: assetPath, lodIndex? (default 0), sectionIndex? (omit to measure the whole LOD) (#938/#953)"
750
+ options:
751
+ method: measure_mesh_geometry
752
+ asset.mesh_boolean:
753
+ class_path: ue-mcp.bridge
754
+ group: asset
755
+ description: "Boolean CSG between two StaticMeshes: union, subtract, intersect, trimInside, trimOutside, newPolyGroupInside, newPolyGroupOutside. The target is the mesh being cut and the tool is what cuts it, each placed by its own optional transform. Writes to a SEPARATE output asset by default (outputPath, or '<targetPath>_<Operation>' when omitted); inPlace=true opts into overwriting the target and is the only destructive form. An existing outputPath is refused unless onConflict='replace'. An empty result is refused and nothing is written unless allowEmptyResult=true, because two meshes that never overlap otherwise report success having deleted everything. Returns triangle and vertex counts for both inputs and the result, plus the written asset's triangles, vertices, LOD count, material slots and bounds, so the operation can be verified rather than trusted. dryRun runs the boolean and reports those counts without writing. Materials and simple collision are copied from the target by default; nanite is inherit (match the target) | enable | disable. Needs the Geometry Script engine plugin: without it the call returns reason='geometry_scripting_unavailable' naming what to enable, rather than failing opaquely. Params: operation, targetPath, toolPath, outputPath?, inPlace?, targetTransform?, toolTransform?, lodType? (MaxAvailable|HiResSourceModel|SourceModel|RenderData), lodIndex?, fillHoles? (default true), simplifyOutput? (default true), simplifyPlanarTolerance? (default 0.01), allowEmptyResult?, recomputeNormals?, recomputeTangents?, removeDegenerates?, copyCollisionFromTarget? (default true), copyMaterialsFromTarget? (default true), nanite?, onConflict? (error|replace), dryRun?, save? (default true) (#916)"
756
+ options:
757
+ method: mesh_boolean
712
758
  asset.migrate:
713
759
  class_path: asset.migrate
714
760
  group: asset
@@ -800,7 +846,7 @@ tasks:
800
846
  asset.diff:
801
847
  class_path: ue-mcp.bridge
802
848
  group: asset
803
- description: "Semantic structural diff between two assets of any type, dispatching on the asset's class. Blueprints are diffed structurally (parent class, variables, functions, components, per-graph node and connection deltas); other asset types report that diffing is not supported yet rather than failing opaquely. Params: assetPath, otherPath"
849
+ description: "Semantic structural diff between two assets, dispatching on the asset's class. Blueprints: parent class, variables, functions, components, per-graph node and connection deltas. Skeleton and SkeletalMesh: raw bone additions and removals, reparenting (bone, fromParent, toParent), raw-index changes (bone, fromIndex, toIndex), and declared virtual-bone additions and removals, with hierarchyCompatible and editorCompatible reported SEPARATELY. That separation is the point: it answers whether two skeletons are bone-compatible enough to register as Compatible Skeletons or whether a retarget is required, because appending bones (virtual ones especially) leaves the shared hierarchy intact while reparenting an existing bone does not (#879). Deliberately OUT of scope and reported as such: reference-pose transforms (referencePoseCompared=false), export names (exportNamesCompared=false), sockets and retarget sources; structureScope spells the boundary out in the result. Both paths must be the same class. Other asset types report that diffing is not supported yet rather than failing opaquely. Params: assetPath, otherPath"
804
850
  options:
805
851
  method: diff_asset
806
852
 
@@ -808,13 +854,13 @@ tasks:
808
854
  blueprint.read:
809
855
  class_path: ue-mcp.bridge
810
856
  group: blueprint
811
- description: "Read BP structure incl. SCS components AND inherited native components from the CDO (CharacterMesh0, CharMoveComp, etc.). Params: assetPath, includeComponentProperties? (dump UPROPERTY name/type/value per component template; off by default) (#353/#370)"
857
+ description: "Read BP structure incl. SCS components AND inherited native components from the CDO (CharacterMesh0, CharMoveComp, etc.). assetPath also accepts a World/umap path such as /Game/Maps/SomeLevel, which resolves to that map's level script Blueprint at PersistentLevel.<MapName>; the result reports blueprintPath and isLevelScript so you can see what answered (#942). Params: assetPath, includeComponentProperties? (dump UPROPERTY name/type/value per component template; off by default) (#353/#370)"
812
858
  options:
813
859
  method: read_blueprint
814
860
  blueprint.list_variables:
815
861
  class_path: ue-mcp.bridge
816
862
  group: blueprint
817
- description: "List variables with name, type, guid, category, tooltip, exposeOnSpawn, blueprintReadOnly, private, and editFlag ('EditAnywhere'|'EditDefaultsOnly'|'EditInstanceOnly'|'none'). instanceEditable is true only for EditAnywhere and EditInstanceOnly - EditDefaultsOnly is class-defaults-only and reports false (#744). private is reported separately because it is a Blueprint-graph access flag, not a details-panel one. Params: assetPath"
863
+ description: "List variables with name, type, guid, category, tooltip, exposeOnSpawn, blueprintReadOnly, private, and editFlag ('EditAnywhere'|'EditDefaultsOnly'|'EditInstanceOnly'|'none'). instanceEditable is true only for EditAnywhere and EditInstanceOnly - EditDefaultsOnly is class-defaults-only and reports false (#744). private is reported separately because it is a Blueprint-graph access flag, not a details-panel one. Pass includeValues to add each variable's RESOLVED default from the generated-class CDO (value, valueText, cppType, declaringClass, inherited) plus one packageDirty/persisted verdict for the listing; off by default so the declaration list stays small (#902). Params: assetPath, includeValues?"
818
864
  options:
819
865
  method: list_blueprint_variables
820
866
  blueprint.list_functions:
@@ -826,19 +872,19 @@ tasks:
826
872
  blueprint.read_graph:
827
873
  class_path: ue-mcp.bridge
828
874
  group: blueprint
829
- description: "Read graph nodes. Supports pagination, file dumps, and title/class node filters. With includeDefaults, literal FText pin values are returned inline (defaultValue falls back to the pin's text literal, plus an explicit defaultTextValue) and object-ref pins report defaultObject (#743). Params: assetPath, graphName, offset?, limit?, includePins?, includeDefaults?, includeComments?, dumpToFile?, outputPath?, titleFilter?, classFilter? (#560)"
875
+ description: "Read graph nodes. Supports pagination, file dumps, and title/class node filters. assetPath accepts a World/umap path, resolved to that map's level script Blueprint (#942). With includeDefaults, literal FText pin values are returned inline (defaultValue falls back to the pin's text literal, plus an explicit defaultTextValue) and object-ref pins report defaultObject (#743). Params: assetPath, graphName, offset?, limit?, includePins?, includeDefaults?, includeComments?, dumpToFile?, outputPath?, titleFilter?, classFilter? (#560)"
830
876
  options:
831
877
  method: read_blueprint_graph
832
878
  blueprint.read_graph_summary:
833
879
  class_path: ue-mcp.bridge
834
880
  group: blueprint
835
- description: "Lightweight graph summary (nodes+edges only, ~10KB). Filterable node list. Params: assetPath, graphName?, titleFilter?, classFilter? (#560)"
881
+ description: "Lightweight graph summary (~10KB). Returns nodes plus wires split across two arrays, execEdges and dataEdges, not a single combined edges array. Filterable node list. assetPath accepts a World/umap path, resolved to that map's level script Blueprint (#942). Params: assetPath, graphName?, titleFilter?, classFilter? (#560)"
836
882
  options:
837
883
  method: read_blueprint_graph_summary
838
884
  blueprint.get_execution_flow:
839
885
  class_path: ue-mcp.bridge
840
886
  group: blueprint
841
- description: "Trace exec pins from an entry point. Params: assetPath, graphName?, entryPoint?"
887
+ description: "Trace exec pins from an entry point. assetPath accepts a World/umap path, resolved to that map's level script Blueprint (#942). Params: assetPath, graphName?, entryPoint?"
842
888
  options:
843
889
  method: get_blueprint_execution_flow
844
890
  blueprint.get_dependencies:
@@ -979,6 +1025,12 @@ tasks:
979
1025
  description: "Set default value on a BP variable. Params: assetPath, name, value"
980
1026
  options:
981
1027
  method: set_variable_default
1028
+ blueprint.get_variable_default:
1029
+ class_path: ue-mcp.bridge
1030
+ group: blueprint
1031
+ description: "Read the RESOLVED default of a BP variable off the generated-class CDO, which is what a write-compile-readback loop has to compare against (list_variables alone only proves the variable exists). Returns value (typed JSON), valueText (UE export text), cppType, declaringClass/declaringClassPath and inherited. It also states whether that value is on DISK: packageDirty is the package's own unsaved-changes flag and persisted is its inverse, so a value written into the CDO but never saved reports persisted=false with a persistenceNote instead of reading back as if it had landed (#931). authoredDefault/matchesAuthoredDefault appear when the variable carries a non-empty authored default string that the next recompile could apply. Params: assetPath, name (#902)"
1032
+ options:
1033
+ method: get_blueprint_variable_default
982
1034
  blueprint.compile:
983
1035
  class_path: ue-mcp.bridge
984
1036
  group: blueprint
@@ -991,6 +1043,12 @@ tasks:
991
1043
  description: "List node types. Params: category?, includeFunctions?"
992
1044
  options:
993
1045
  method: list_node_types
1046
+ blueprint.search_call_sites:
1047
+ class_path: ue-mcp.bridge
1048
+ group: blueprint
1049
+ description: "Find authored call-site NODES for named functions across a whole directory in ONE call, including nested and collapsed graphs. Replaces the enumerate-every-Blueprint / read-every-graph sweep that overwhelms the bridge on a large project. Narrowing is done by the Asset Registry BEFORE any package is loaded: candidates come from a recursive Blueprint filter over `directory`, then every candidate whose package does not depend on a package declaring one of `functionNames` is ruled out unloaded. That step is reported (stats.narrowedByRegistry, stats.blueprintsSkippedByRegistry) and can be turned off with narrowByRegistry=false; it is also skipped automatically when a requested name has no resolvable declaring class, so a filter never silently drops a hit. Each hit carries assetPath, packageName, graphName + graphSelector (the same selector list_graphs reports, so it is unambiguous for duplicate nested graph names) + graphObjectPath, nodeId, nodeTitle, memberName, resolvedFunction (absent with unresolvedTarget=true when the function is gone, which is itself an audit finding), declaringClass/declaringClassPath, parentCall, and pinDefaults for unlinked input pins. Pass includeNeighbours for the immediate execution and data neighbours of each call. Level script Blueprints are NOT registry assets (they live inside their map package), so they are excluded unless you pass includeLevelScripts, which sweeps the World assets under the directory and costs a full map load each. Bounded and paginated: limit (default 200, max 1000) + offset, maxBlueprints (default 2000) caps package loads, and dumpToFile writes the whole result set to a JSON file the way read_graph does. Params: functionNames[], className?, directory? (default /Game), includeNestedGraphs? (default true), includeLevelScripts?, includeNeighbours?, narrowByRegistry?, offset?, limit?, maxBlueprints?, dumpToFile?, outputPath? (#945)"
1050
+ options:
1051
+ method: search_blueprint_call_sites
994
1052
  blueprint.search_node_types:
995
1053
  class_path: ue-mcp.bridge
996
1054
  group: blueprint
@@ -1012,7 +1070,7 @@ tasks:
1012
1070
  blueprint.override_function:
1013
1071
  class_path: ue-mcp.bridge
1014
1072
  group: blueprint
1015
- description: "Override an inherited interface implementation (inherited via the parent class) or an overridable parent virtual function, with the matching signature so it actually binds as the override (create_function makes a blank, non-binding graph). Returns kind ('function' with a graphName, or 'event' with a nodeId in EventGraph). Event-shaped functions become override events unless preferFunction=true. Pass interfacePath to also implement the interface first if it is not present. Then wire the body with add_node (use nodeClass='CallParent' to chain to the base implementation). Params: assetPath, functionName, source? ('auto'|'interface'|'parent', advisory), preferFunction?, interfacePath? (#688)"
1073
+ description: "Override an inherited interface implementation (inherited via the parent class) or an overridable parent virtual function, with the matching signature so it actually binds as the override (create_function makes a blank, non-binding graph). Returns kind ('function' with a graphName, or 'event' with a nodeId in EventGraph). Event-shaped functions become override events unless preferFunction=true. This is the path for BehaviorTree TASK Blueprint entry points: ReceiveExecuteAI and ReceiveAbortAI on a UBTTask_BlueprintBase child come back as kind='event' in EventGraph, and their FinishExecute / FinishAbort terminators are placed with add_node nodeClass='CallFunction', className='/Script/AIModule.BTTask_BlueprintBase' (#886). Pass interfacePath to also implement the interface first if it is not present. Then wire the body with add_node (use nodeClass='CallParent' to chain to the base implementation). An animation layer override in a child Anim BP is created as an AnimationGraph on the animation schema, mirrored from the graph that declared the layer, so it actually binds instead of compiling to an inert K2 function graph; the result reports graphClass, schemaClass and animationGraph (#894). Params: assetPath, functionName, source? ('auto'|'interface'|'parent', advisory), preferFunction?, interfacePath? (#688)"
1016
1074
  options:
1017
1075
  method: override_function
1018
1076
  blueprint.list_overridable_functions:
@@ -1024,13 +1082,13 @@ tasks:
1024
1082
  blueprint.list_graphs:
1025
1083
  class_path: ue-mcp.bridge
1026
1084
  group: blueprint
1027
- description: "List all graphs in a blueprint. Returns selector/objectPath plus duplicateIndex/duplicateCount; pass selector back as graphName for unambiguous nested graph edits. Params: assetPath"
1085
+ description: "List all graphs in a blueprint. Returns selector/objectPath plus duplicateIndex/duplicateCount; pass selector back as graphName for unambiguous nested graph edits. assetPath accepts a World/umap path, resolved to that map's level script Blueprint (#942). Params: assetPath"
1028
1086
  options:
1029
1087
  method: list_blueprint_graphs
1030
1088
  blueprint.resolve_graph:
1031
1089
  class_path: ue-mcp.bridge
1032
1090
  group: blueprint
1033
- description: "Resolve a Blueprint graph name to selectors accepted by read_graph/add_node/connect_pins and other graph actions. Duplicate nested AnimBP names such as Locomotion return every match with selectors like Locomotion[3], object paths, and ambiguity metadata. Params: assetPath, graphName"
1091
+ description: "Resolve a Blueprint graph name to selectors accepted by read_graph/add_node/connect_pins and other graph actions. assetPath accepts a World/umap path, resolved to that map's level script Blueprint (#942). Duplicate nested AnimBP names such as Locomotion return every match with selectors like Locomotion[3], object paths, and ambiguity metadata. Params: assetPath, graphName"
1034
1092
  options:
1035
1093
  method: resolve_blueprint_graph
1036
1094
  blueprint.add_event_dispatcher:
@@ -1069,6 +1127,12 @@ tasks:
1069
1127
  description: "Dump ALL UPROPERTYs on a BP component template incl. array contents (#105). Params: assetPath, componentName"
1070
1128
  options:
1071
1129
  method: read_component_properties
1130
+ blueprint.get_component_collision:
1131
+ class_path: ue-mcp.bridge
1132
+ group: blueprint
1133
+ description: "Read a component's EFFECTIVE collision: enabled mode, object type, profile name, and the resolved Block/Overlap/Ignore per channel. read_component_properties cannot answer this - it exports BodyInstance as text, and that text carries only CollisionProfileName plus the responses that DIFFER from the profile, so a response INHERITED from the profile (the Pawn profile blocking Camera) is invisible in it. Each channel reports response (what GetCollisionResponseToChannel actually returns), profileResponse, and overridesProfile, so you can see whether an answer came from the profile or from the component. assetPath takes a Blueprint path OR a native class (/Script/MyGame.MyCharacter or 'MyCharacter'), which is how you verify a C++ constructor's SetCollisionResponseToChannel really landed in the CDO after a rebuild. Project trace and object channels appear under their configured names with enumName alongside. channel narrows it to one; includeAllChannels adds the unused GameTraceChannel slots. Params: assetPath, componentName, channel?, includeAllChannels? (#925)"
1134
+ options:
1135
+ method: get_component_collision
1072
1136
  blueprint.read_node_property:
1073
1137
  class_path: ue-mcp.bridge
1074
1138
  group: blueprint
@@ -1078,13 +1142,13 @@ tasks:
1078
1142
  blueprint.reparent_component:
1079
1143
  class_path: ue-mcp.bridge
1080
1144
  group: blueprint
1081
- description: "Reparent an SCS component under a new parent (#115). Params: assetPath, componentName, newParent"
1145
+ description: "Reparent an SCS component under a new parent, recompile and save (#115). Refuses before touching anything when the Blueprint's .uasset is read-only on disk (not checked out) or on a protected mount, and reports saved plus saveError when the write did not reach disk (#932). Params: assetPath, componentName, newParent"
1082
1146
  options:
1083
1147
  method: reparent_component
1084
1148
  blueprint.reparent:
1085
1149
  class_path: ue-mcp.bridge
1086
1150
  group: blueprint
1087
- description: "Change a Blueprint's ParentClass and recompile (#138). Params: assetPath, parentClass (short name or full path)."
1151
+ description: "Change a Blueprint's ParentClass, recompile and save (#138). The save is part of the operation, so writability is checked FIRST: a read-only .uasset (never checked out of source control) or a protected mount returns reason='package_not_writable' naming the file, with nothing reparented, instead of taking the editor down with a fatal save error (#932). A write that still did not reach disk comes back with saved=false and saveError. Params: assetPath, parentClass (short name or full path)."
1088
1152
  options:
1089
1153
  method: reparent_blueprint
1090
1154
  blueprint.flush_ich:
@@ -1093,6 +1157,12 @@ tasks:
1093
1157
  description: "Flush orphaned InheritableComponentHandler override records (invalid component-override entries invisible to read/remove_component). Recompiles + saves. Params: assetPath. Returns recordsBefore/After/Removed (#580)"
1094
1158
  options:
1095
1159
  method: flush_inheritable_component_handler
1160
+ blueprint.flush_component_templates:
1161
+ class_path: ue-mcp.bridge
1162
+ group: blueprint
1163
+ description: "Flush orphaned UBlueprint::ComponentTemplates left by deleted Add Component nodes using Unreal's native maintenance routine. Live Add Component templates are preserved. Recompiles + saves only when changed. Params: assetPath. Returns recordsBefore/After/Removed and removed template identities."
1164
+ options:
1165
+ method: flush_blueprint_component_templates
1096
1166
  blueprint.set_actor_tick_settings:
1097
1167
  class_path: ue-mcp.bridge
1098
1168
  group: blueprint
@@ -1168,7 +1238,7 @@ tasks:
1168
1238
  level.get_outliner:
1169
1239
  class_path: ue-mcp.bridge
1170
1240
  group: level
1171
- description: "List actors (each row includes editorHidden - hidden in the viewport but still rendering in game). Params: classFilter?, nameFilter?, editorHidden? (filter to only hidden/only visible), world? (editor|pie|auto), limit?, includeStreaming? (#717)"
1241
+ description: "List actors (each row includes editorHidden - hidden in the viewport but still rendering in game, and folderPath). classFilter is a case-sensitive SUBSTRING over the class name by default; pass exactClass=true to require the exact class instead. folderPath matches one World Outliner folder exactly and folderPathPrefix matches that folder and everything nested under it, so narrowing a folder to a single class no longer needs a get_actor_details round trip per entry (#911). Params: classFilter?, exactClass?, nameFilter? (case-sensitive substring over the internal name OR the label), folderPath?, folderPathPrefix?, editorHidden? (filter to only hidden/only visible), world? (editor|pie|auto), limit?, includeStreaming? (#717)"
1172
1242
  options:
1173
1243
  method: get_world_outliner
1174
1244
  level.set_editor_visibility:
@@ -1186,25 +1256,25 @@ tasks:
1186
1256
  level.delete_actor:
1187
1257
  class_path: ue-mcp.bridge
1188
1258
  group: level
1189
- description: "Remove actor. Params: actorLabel"
1259
+ description: "Remove actor. Params: actorLabel OR actorPath. A label matching several actors is refused with the candidates rather than deleting one of them (#983)"
1190
1260
  options:
1191
1261
  method: delete_actor
1192
1262
  level.get_actor_details:
1193
1263
  class_path: ue-mcp.bridge
1194
1264
  group: level
1195
- description: "Inspect actor. Params: actorLabel OR actorPath, includeProperties?, propertyName?, world? (editor|pie)"
1265
+ description: "Inspect actor. With includeProperties=true, a UPROPERTY declared as a C-style FIXED ARRAY (int32 Foo[3], one FProperty with ArrayDim 3) comes back as a JSON ARRAY of its elements plus arrayDim, instead of element 0 presented as the whole value. That mattered on RecastNavMesh NavMeshResolutionParams, whose three entries are the Low, Default and High generation tiers, and where reporting only Low sent a user tuning cell sizes against numbers the engine was not using (#927). Params: actorLabel OR actorPath, includeProperties?, propertyName?, world? (editor|pie)"
1196
1266
  options:
1197
1267
  method: get_actor_details
1198
1268
  level.move_actor:
1199
1269
  class_path: ue-mcp.bridge
1200
1270
  group: level
1201
- description: "Transform actor. Pass world:pie to move a live PIE actor (resolves labels/names from get_outliner {world:pie}) (#586). Params: actorLabel, location?, rotation?, scale?, world? (editor|pie)"
1271
+ description: "Transform actor. Pass world:pie to move a live PIE actor (resolves labels/names from get_outliner {world:pie}) (#586). Params: actorLabel OR actorPath, location?, rotation?, scale?, world? (editor|pie)"
1202
1272
  options:
1203
1273
  method: move_actor
1204
1274
  level.aim_actor_at:
1205
1275
  class_path: ue-mcp.bridge
1206
1276
  group: level
1207
- description: "Rotate an actor so its forward (+X) points at a target. Params: actorLabel, targetPoint (Vec3) OR targetActor (label), roll? (default 0), world? (editor|pie) (#566)"
1277
+ description: "Rotate an actor so its forward (+X) points at a target. Params: actorLabel OR actorPath, targetPoint (Vec3) OR targetActor (label) OR targetActorPath, roll? (default 0), world? (editor|pie) (#566/#983)"
1208
1278
  options:
1209
1279
  method: aim_actor_at
1210
1280
  level.nav_project_point:
@@ -1216,7 +1286,7 @@ tasks:
1216
1286
  level.select:
1217
1287
  class_path: ue-mcp.bridge
1218
1288
  group: level
1219
- description: "Select actors. Params: actorLabels[]"
1289
+ description: "Select actors. A label naming several actors selects all of them; selectedPaths reports exactly which. Params: actorLabels[] and/or actorPaths[] (#983)"
1220
1290
  options:
1221
1291
  method: select_actors
1222
1292
  level.get_selected:
@@ -1228,25 +1298,31 @@ tasks:
1228
1298
  level.add_component:
1229
1299
  class_path: ue-mcp.bridge
1230
1300
  group: level
1231
- description: "Add component to actor. Params: actorLabel, componentClass, componentName?"
1301
+ description: "Add component to actor. Params: actorLabel OR actorPath, componentClass, componentName?"
1232
1302
  options:
1233
1303
  method: add_component_to_actor
1234
1304
  level.remove_component:
1235
1305
  class_path: ue-mcp.bridge
1236
1306
  group: level
1237
- description: "Remove instance component from a level actor by name. Idempotent: returns alreadyDeleted=true if no matching component exists. Params: actorLabel, componentName (#426)"
1307
+ description: "Remove instance component from a level actor by name. Idempotent: returns alreadyDeleted=true if no matching component exists. Params: actorLabel OR actorPath, componentName (#426)"
1238
1308
  options:
1239
1309
  method: remove_component_from_actor
1240
1310
  level.set_component_property:
1241
1311
  class_path: ue-mcp.bridge
1242
1312
  group: level
1243
- description: "Set component prop. Pass value=null to clear a TObjectPtr/SoftObject/WeakObject/UClass/Interface reference (#420). Resolves inherited/SCS components on placed Blueprint instances case-insensitively, and refreshes the scene transform after RelativeLocation/RelativeRotation/RelativeScale3D writes (#539). Pass world='pie' (with optional pieInstance) to write to a LIVE PIE component rather than the editor one (#763). Params: actorLabel, componentName, propertyName, value, world?, pieInstance?"
1313
+ description: "Set component prop. A C-style FIXED ARRAY element is addressed by index in the dotted path ('Foo[2].Bar'); without an index every write lands on element 0 (#927). Pass value=null to clear a TObjectPtr/SoftObject/WeakObject/UClass/Interface reference (#420). Resolves inherited/SCS components on placed Blueprint instances case-insensitively, and refreshes the scene transform after RelativeLocation/RelativeRotation/RelativeScale3D writes (#539). Pass world='pie' (with optional pieInstance) to write to a LIVE PIE component rather than the editor one (#763). Params: actorLabel OR actorPath, componentName, propertyName, value, world?, pieInstance?"
1244
1314
  options:
1245
1315
  method: set_component_property
1316
+ level.nudge_component:
1317
+ class_path: ue-mcp.bridge
1318
+ group: level
1319
+ description: "Make a small spatial adjustment to an exact named SceneComponent without editing raw relative Euler angles. For visual tuning, normalize the user's request as target + reference frame + viewpoint + operation + amount + constraints. Character left/right means actor-relative; viewer-relative directions must be stated explicitly; clockwise/counterclockwise requires a viewpoint. Infer obvious context and echo the normalized interpretation before applying; ask one concise question only when the frame or viewpoint cannot be resolved. Translation uses forward/right/up centimetres in frame=world|actor|parent|component. Rotation is one axis-angle quaternion delta in that frame, so attached/socketed components avoid gimbal-like pitch/roll drift. Unspecified location, rotation and scale are preserved. After a visual nudge, verify with a fixed-pose close packet: for character body attachments, stop actor/root movement and freeze the parent skeletal pose before the baseline, then hold both across every probe and capture; light the contact area from the front, capture front/side/top/three-quarter views with the target filling roughly 50-75% of the frame, and reject dark or wide-only evidence. Returns before/after relative and world transforms, resolved world deltas, and exact rollback data. Params: actorLabel OR actorPath, componentName, frame? (default actor), translationDelta? ({forwardCm?,rightCm?,upCm?}), axisRotation? ({axis:forward|right|up,degrees}), scaleMultiplier? (>0), world? (editor|pie), pieInstance?"
1320
+ options:
1321
+ method: nudge_component
1246
1322
  level.get_component_details:
1247
1323
  class_path: ue-mcp.bridge
1248
1324
  group: level
1249
- description: "Read a placed actor's component transforms. With componentName returns that component's relative+world location/rotation/scale, class, and attach parent; without it lists every component. With includeValues=true also dumps arbitrary UPROPERTY values (custom fields, CharacterMovement MaxWalkSpeed, etc.); world='pie' reads the live PIE instance (#539/#584). Params: actorLabel, componentName?, includeValues?, propertyNames? (filter), world? (editor|pie)"
1325
+ description: "Read a placed actor's component transforms. With componentName returns that component's relative+world location/rotation/scale, class, and attach parent; without it lists every component. With includeValues=true also dumps arbitrary UPROPERTY values (custom fields, CharacterMovement MaxWalkSpeed, etc.); world='pie' reads the live PIE instance (#539/#584). Params: actorLabel OR actorPath, componentName?, includeValues?, propertyNames? (filter), world? (editor|pie)"
1250
1326
  options:
1251
1327
  method: get_component_details
1252
1328
  level.get_current:
@@ -1261,12 +1337,18 @@ tasks:
1261
1337
  description: "Load level. Params: levelPath"
1262
1338
  options:
1263
1339
  method: load_level
1340
+ level.clear_level_script:
1341
+ class_path: ue-mcp.bridge
1342
+ group: level
1343
+ description: "Preview or remove every node and member variable from the currently loaded persistent level's Level Blueprint. Defaults to dryRun=true. Actors are untouched; save=true saves only the current level after a successful compile. Params: dryRun?, save?"
1344
+ options:
1345
+ method: clear_level_script
1264
1346
  level.save:
1265
1347
  class_path: ue-mcp.bridge
1266
1348
  group: level
1267
- description: Save current level
1349
+ description: "Save the level currently being edited, and say what happened to each package. Takes the same package path editor(save_dirty) uses, so the two can no longer disagree about whether one package was written: the old action returned a bare {success:false, error:'Failed to save current level'} on a map that save_dirty then wrote seconds later, and a false failure makes an agent redo work that was already on disk (#964). On a World Partition or one-file-per-actor map the actors live in their own packages, so those are saved too and each is reported separately. A package that was already clean is reported as skipped, not as a failure. On failure the error names the package, the resolved file, whether that file exists and is read-only, the engine's ESavePackageResult and the error/warning lines the save itself emitted. Saving during PIE is refused by name rather than failing silently. Params: force? (write even a clean package, default false), includeExternalActors? (default true)"
1268
1350
  options:
1269
- method: save_current_level
1351
+ method: save_level
1270
1352
  level.list:
1271
1353
  class_path: ue-mcp.bridge
1272
1354
  group: level
@@ -1294,7 +1376,7 @@ tasks:
1294
1376
  level.set_volume_properties:
1295
1377
  class_path: ue-mcp.bridge
1296
1378
  group: level
1297
- description: "Edit volume. Params: actorLabel, properties"
1379
+ description: "Edit volume. Params: actorLabel OR actorPath, properties"
1298
1380
  options:
1299
1381
  method: set_volume_properties
1300
1382
  level.spawn_light:
@@ -1306,13 +1388,13 @@ tasks:
1306
1388
  level.set_light_properties:
1307
1389
  class_path: ue-mcp.bridge
1308
1390
  group: level
1309
- description: "Edit a light OR SkyLight (intensity/color now work on SkyLight too, #608). Params: actorLabel, intensity?, color?, rotation? (DirectionalLight sun angle), mobility? (static|stationary|movable), recaptureSky?, volumetricScatteringIntensity?, sourceRadius? (point/spot), innerConeAngle?/outerConeAngle? (spot)"
1391
+ description: "Edit a light OR SkyLight (intensity/color now work on SkyLight too, #608). Params: actorLabel OR actorPath, intensity?, color?, rotation? (DirectionalLight sun angle), mobility? (static|stationary|movable), recaptureSky?, volumetricScatteringIntensity?, sourceRadius? (point/spot), innerConeAngle?/outerConeAngle? (spot)"
1310
1392
  options:
1311
1393
  method: set_light_properties
1312
1394
  level.set_fog_properties:
1313
1395
  class_path: ue-mcp.bridge
1314
1396
  group: level
1315
- description: "Edit ExponentialHeightFog incl. volumetric fog (#608). Params: actorLabel?, fogDensity?, fogHeightFalloff?, startDistance?, fogInscatteringColor?, enableVolumetricFog?, volumetricFogScatteringDistribution?, volumetricFogExtinctionScale?, volumetricFogDistance?, volumetricFogAlbedo?"
1397
+ description: "Edit ExponentialHeightFog incl. volumetric fog (#608). Params: actorLabel? OR actorPath?, fogDensity?, fogHeightFalloff?, startDistance?, fogInscatteringColor?, enableVolumetricFog?, volumetricFogScatteringDistribution?, volumetricFogExtinctionScale?, volumetricFogDistance?, volumetricFogAlbedo?"
1316
1398
  options:
1317
1399
  method: set_fog_properties
1318
1400
  level.get_actors_by_class:
@@ -1324,9 +1406,15 @@ tasks:
1324
1406
  level.get_actors_by_component_class:
1325
1407
  class_path: ue-mcp.bridge
1326
1408
  group: level
1327
- description: "List actors that own a component of a given class (exact or substring match). Returns each actor plus its matchedComponents. Params: componentClass, world? (editor|pie) (#582)"
1409
+ description: "List actors that own a component of a given class (exact or substring match). Returns each actor plus its matchedComponents. For a whole-map question use level(query_components), which filters and counts in the editor instead of returning every candidate. Params: componentClass, world? (editor|pie) (#582)"
1328
1410
  options:
1329
1411
  method: get_actors_by_component_class
1412
+ level.query_components:
1413
+ class_path: ue-mcp.bridge
1414
+ group: level
1415
+ description: "Ask one level-wide question about components and get the answer, not the candidates. Selection, projection, predicates, grouping and counts all evaluate in the editor, so a 4,000 actor map costs one call instead of thousands. Computed (not raw) values: shadow.effectiveCastShadow crosses CastShadow with visibility, bHiddenInGame, owner hidden and bCastHiddenShadow, so a hidden debug marker with CastShadow=true is correctly NOT a shadow caster; every mobility and collision enum comes back as a clean name (Movable, QueryAndPhysics), never as EComponentMobility.MOVABLE; navigation.effectiveNavRelevant crosses bCanEverAffectNavigation with collision and custom navigable geometry. Never writes, and reports dirtiedPackages so you can see that. Field groups for 'fields' and for dot paths: transform, bounds, localBounds (unscaled, includes UBoxComponent BoxExtent), shadow, nanite, navigation, tick, materials (per slot: effective path, componentOverride vs meshDefault, slot name/index, isNull, isWorldGrid), mesh (adds instanceCount + hierarchical for an ISM/HISM, #986), decal, health (roll-up incl. suspect). A dot path used in where/groupBy/countBy turns its own group on. groupBy and countBy COUNT COMPONENTS, not instances: one HISM holding 5,000 instances counts as 1, so for per-mesh placement totals use level(summarize_static_mesh_usage), which sums instances and counts distinct actors. Params: componentClass?, actorClass?, matchSubclasses? (default true), componentNameContains?, actorLabelPrefix?, actorLabelContains?, actorTag?, folderPath?, folderPathPrefix?, fields? (string[]), propertyNames? (string[], projected component UPROPERTYs under props.*), where? ([{field, op, value}]; ops eq/ne/lt/lte/gt/gte/contains/notContains/startsWith/endsWith/in/notIn/exists/notExists/isNull/isNotNull/isTrue/isFalse), whereMode? (all|any, default all), suspectOnly?, groupBy?, countBy? (string[]), sampleLimit?, countOnly?, limit? (default 200, max 2000), startIndex?, duplicateTransformTolerance? (cm; reports duplicateTransformGroups), levelPath? (temporarily opens another map: refuses if anything is dirty and restores the map that was open), world? (editor|pie) (#910/#943/#912)"
1416
+ options:
1417
+ method: query_components
1330
1418
  level.count_actors_by_class:
1331
1419
  class_path: ue-mcp.bridge
1332
1420
  group: level
@@ -1342,7 +1430,7 @@ tasks:
1342
1430
  level.set_water_body_property:
1343
1431
  class_path: ue-mcp.bridge
1344
1432
  group: level
1345
- description: "Set a property on an actor's WaterBodyComponent (ShapeDilation, WaterLevel, etc.). Params: actorLabel, propertyName, value. Requires Water plugin. For spline edits use level(set_spline_points) (#151)"
1433
+ description: "Set a property on an actor's WaterBodyComponent (ShapeDilation, WaterLevel, etc.). Params: actorLabel OR actorPath, propertyName, value. Requires Water plugin. For spline edits use level(set_spline_points) (#151)"
1346
1434
  options:
1347
1435
  method: set_water_body_property
1348
1436
  level.build_lighting:
@@ -1354,19 +1442,19 @@ tasks:
1354
1442
  level.get_spline_info:
1355
1443
  class_path: ue-mcp.bridge
1356
1444
  group: level
1357
- description: "Read a spline component's points, closedLoop, length, and per-point tangents/types. Works in editor or PIE (#553). Optional componentName picks a specific (custom) spline; projectPoint (Vec3) returns the closest location, inputKey, distanceAlongSpline, distanceToSpline, and tangent (#555). Params: actorLabel, componentName?, world? (editor|pie), projectPoint?"
1445
+ description: "Read a spline component's points, closedLoop, length, and per-point tangents/types. Works in editor or PIE (#553). Optional componentName picks a specific (custom) spline; projectPoint (Vec3) returns the closest location, inputKey, distanceAlongSpline, distanceToSpline, and tangent (#555). Params: actorLabel OR actorPath, componentName?, world? (editor|pie), projectPoint?"
1358
1446
  options:
1359
1447
  method: get_spline_info
1360
1448
  level.set_spline_points:
1361
1449
  class_path: ue-mcp.bridge
1362
1450
  group: level
1363
- description: "Set spline points. Params: actorLabel, points[], closedLoop?"
1451
+ description: "Set spline points. Params: actorLabel OR actorPath, points[], closedLoop?"
1364
1452
  options:
1365
1453
  method: set_spline_points
1366
1454
  level.set_actor_material:
1367
1455
  class_path: ue-mcp.bridge
1368
1456
  group: level
1369
- description: "Set material on actor. Params: actorLabel, materialPath, slotIndex?"
1457
+ description: "Set material on actor. Params: actorLabel OR actorPath, materialPath, slotIndex?"
1370
1458
  options:
1371
1459
  method: set_actor_material
1372
1460
  level.get_world_settings:
@@ -1390,13 +1478,13 @@ tasks:
1390
1478
  level.get_component_tree:
1391
1479
  class_path: ue-mcp.bridge
1392
1480
  group: level
1393
- description: "Deep component-tree dump for an actor. Returns per-component: name, class, attachParent, attachSocket, mobility, visibility, relative+world transforms, tags. For PrimitiveComponents adds collisionProfile/collisionEnabled/bounds/castShadow. For StaticMeshComponent adds staticMesh + materials[]. For SkeletalMeshComponent adds skeletalMesh + skeleton + materials[]. For NiagaraComponent adds niagara{asset,active,visible} and for AudioComponent audio{sound,playing} - runtime FX state in PIE (#581). Params: actorLabel | actorPath, world? (editor|pie), componentClass? (substring filter), includeProperties? (dump UPROPERTY name/type/value per component) (#240/#241/#302/#320/#370/#353/#581)"
1481
+ description: "Deep component-tree dump for an actor. Returns per-component: name, class, attachParent, attachSocket, mobility, visibility, relative+world transforms, tags. For PrimitiveComponents adds collisionProfile/collisionEnabled/bounds/castShadow. For StaticMeshComponent adds staticMesh + materials[], and for an ISM/HISM also instanceCount plus instanced{hierarchical,numCustomDataFloats} - the number you need before deciding whether to touch an ISM at all, since a component holding three instances and one holding three hundred thousand were otherwise the same row (#986). For SkeletalMeshComponent adds skeletalMesh + skeleton + materials[]. For NiagaraComponent adds niagara{asset,active,visible} and for AudioComponent audio{sound,playing} - runtime FX state in PIE (#581). Params: actorLabel OR actorPath, world? (editor|pie), componentClass? (substring filter), includeProperties? (dump UPROPERTY name/type/value per component) (#240/#241/#302/#320/#370/#353/#581)"
1394
1482
  options:
1395
1483
  method: get_component_tree
1396
1484
  level.get_relative_transform:
1397
1485
  class_path: ue-mcp.bridge
1398
1486
  group: level
1399
- description: "Compute target's transform in reference's local space (location/rotation/scale). Common dungeon/calibration workflow. Params: target (actor label), reference (actor label), world? (#386/#387)"
1487
+ description: "Compute target's transform in reference's local space (location/rotation/scale). Common dungeon/calibration workflow. Params: target/targetLabel (actor label) OR targetPath, reference/referenceLabel OR referencePath, world? (#386/#387/#983)"
1400
1488
  options:
1401
1489
  method: get_relative_transform
1402
1490
  level.resolve_actor:
@@ -1408,37 +1496,37 @@ tasks:
1408
1496
  level.set_actor_property:
1409
1497
  class_path: ue-mcp.bridge
1410
1498
  group: level
1411
- description: "Set per-instance UPROPERTY on a level actor. Params: actorLabel ('WorldSettings' targets the world settings actor), propertyName (dotted paths like 'Foo.Bar' supported), value (string/number/bool/object/array; a label string resolves to an AActor* ref, and a JSON array of labels populates a TArray of actor refs #538), force? (bypass EditDefaultsOnly), world? (editor|pie) (#202/#230)"
1499
+ description: "Set per-instance UPROPERTY on a level actor. Params: actorLabel OR actorPath ('WorldSettings' as the label targets the world settings actor), propertyName (dotted paths like 'Foo.Bar' supported, and a C-style FIXED ARRAY element is addressed by index: 'NavMeshResolutionParams[1].CellSize' reaches the Default tier rather than always writing element 0 (#927)), value (string/number/bool/object/array; a label string resolves to an AActor* ref, and a JSON array of labels populates a TArray of actor refs #538), force? (bypass EditDefaultsOnly), world? (editor|pie) (#202/#230)"
1412
1500
  options:
1413
1501
  method: set_actor_property
1414
1502
  level.read_actor_motion:
1415
1503
  class_path: ue-mcp.bridge
1416
1504
  group: level
1417
- description: "Snapshot motion telemetry for one or many actors: location, rotation, velocity, scale, angularVelocity (when simulating physics), grounded + distanceToGround (downward 200u trace). Defaults to the PIE world with editor fallback. Loop at your sample interval for long telemetry probes. Params: actorLabel? OR actorLabels (string[]), world? ('pie'|'editor'), pieInstance? (#453)"
1505
+ description: "Snapshot motion telemetry for one or many actors: location, rotation, velocity, scale, angularVelocity (when simulating physics), grounded + distanceToGround (downward 200u trace). Defaults to the PIE world with editor fallback. Loop at your sample interval for long telemetry probes. Params: actorLabel? OR actorLabels (string[]) OR actorPath? OR actorPaths (string[]), world? ('pie'|'editor'), pieInstance? (#453)"
1418
1506
  options:
1419
1507
  method: read_actor_motion
1420
1508
  level.add_hismc_instances:
1421
1509
  class_path: ue-mcp.bridge
1422
1510
  group: level
1423
- description: "Bulk-add transforms to a HISMC / ISMC component on an actor (Python add_instance crashes on UE 5.7; this is the C++ path). Params: actorLabel, componentName? (default: first ISMC/HISMC found), transforms ([{location: {x,y,z}, rotation?: {pitch,yaw,roll}, scale?: {x,y,z}}]), worldSpace? (default true) (#434)"
1511
+ description: "Bulk-add transforms to a HISMC / ISMC component on an actor (Python add_instance crashes on UE 5.7; this is the C++ path). Params: actorLabel OR actorPath, componentName? (default: first ISMC/HISMC found), transforms ([{location: {x,y,z}, rotation?: {pitch,yaw,roll}, scale?: {x,y,z}}]), worldSpace? (default true) (#434)"
1424
1512
  options:
1425
1513
  method: add_hismc_instances
1426
1514
  level.get_instance_transforms:
1427
1515
  class_path: ue-mcp.bridge
1428
1516
  group: level
1429
- description: "Read every instance transform on an actor's ISMC/HISMC. Params: actorLabel, componentName? (default first), worldSpace? (default true). Returns instances[{index, location, rotation, scale}] (#697)"
1517
+ description: "Read every instance transform on an actor's ISMC/HISMC. Params: actorLabel OR actorPath, componentName? (default first), worldSpace? (default true). Returns instances[{index, location, rotation, scale}] (#697)"
1430
1518
  options:
1431
1519
  method: get_instance_transforms
1432
1520
  level.update_instance_transform:
1433
1521
  class_path: ue-mcp.bridge
1434
1522
  group: level
1435
- description: "Update a single ISMC/HISMC instance by index; unspecified location/rotation/scale are preserved. Params: actorLabel, componentName?, index, location?, rotation?, scale?, worldSpace? (default true) (#697)"
1523
+ description: "Update a single ISMC/HISMC instance by index; unspecified location/rotation/scale are preserved. Params: actorLabel OR actorPath, componentName?, index, location?, rotation?, scale?, worldSpace? (default true) (#697)"
1436
1524
  options:
1437
1525
  method: update_instance_transform
1438
1526
  level.remove_instance:
1439
1527
  class_path: ue-mcp.bridge
1440
1528
  group: level
1441
- description: "Remove a single ISMC/HISMC instance by index. Params: actorLabel, componentName?, index (#697)"
1529
+ description: "Remove a single ISMC/HISMC instance by index. Params: actorLabel OR actorPath, componentName?, index (#697)"
1442
1530
  options:
1443
1531
  method: remove_instance
1444
1532
  level.set_nanite_settings:
@@ -1456,25 +1544,43 @@ tasks:
1456
1544
  level.add_post_process_blendable:
1457
1545
  class_path: ue-mcp.bridge
1458
1546
  group: level
1459
- description: "Add a material blendable (post-process material or MID, e.g. a toon/outline pass) to a PostProcessVolume's WeightedBlendables. Params: actorLabel (the PPV), materialPath, weight? (default 1) (#666)"
1547
+ description: "Add a material blendable (post-process material or MID, e.g. a toon/outline pass) to a PostProcessVolume's WeightedBlendables. Params: actorLabel OR actorPath (the PPV), materialPath, weight? (default 1) (#666)"
1460
1548
  options:
1461
1549
  method: add_post_process_blendable
1550
+ level.set_post_process_settings:
1551
+ class_path: ue-mcp.bridge
1552
+ group: level
1553
+ description: "Write post-process settings AND enable the bOverride_<Name> flag for every key given. Inside FPostProcessSettings each value is gated by its own override bit, so writing AutoExposureMinBrightness through the generic property setter stores the number, leaves the bit off, and the engine keeps using the default while the details panel shows the value you asked for. Nothing errors. That is the trap this closes: the auto-enable IS the action. Works off the struct's reflected fields, so every setting is reachable, not just exposure, and a key that has no override bit (WeightedBlendables) says so instead of implying one was enabled. Every key is resolved BEFORE anything is written, so a typo fails the call rather than half-applying it, and each key reports previousValue, newValue, overrideWasEnabled and overrideEnabled read back from the struct. Finds the settings on the actor or on one of its components; a camera with several camera components needs componentName (or propertyName) and is refused by listing the candidates rather than by picking one. The level is left dirty and is NOT saved. Params: actorLabel OR actorPath, settings (object of settingName -> value), enableOverrides? (default true), componentName?, propertyName? (#950)"
1554
+ options:
1555
+ method: set_post_process_settings
1556
+ level.get_post_process_settings:
1557
+ class_path: ue-mcp.bridge
1558
+ group: level
1559
+ description: "Read post-process settings with the override bit that decides whether each one applies. onlyOverridden answers 'is this volume actually overriding exposure' directly, instead of dumping the whole FPostProcessSettings as one ExportText blob to parse. Each row is name, type, value, overridden (the bOverride_<Name> bit) and hasOverrideFlag; the bits themselves are not listed as settings of their own, because a caller who writes the bit without the value has changed nothing. Also returns totalSettings and overriddenCount, so 'nothing is overridden here' is a fact rather than an empty list. Params: actorLabel OR actorPath, onlyOverridden? (default false), names? (string[] exact names), nameContains? (substring filter), componentName?, propertyName? (#950)"
1560
+ options:
1561
+ method: get_post_process_settings
1562
+ level.set_fixed_exposure:
1563
+ class_path: ue-mcp.bridge
1564
+ group: level
1565
+ description: "Pin exposure on a post-process volume or camera in one call. Writes the same value to AutoExposureMinBrightness and AutoExposureMaxBrightness, which is how the engine disables eye adaptation, and enables both override flags so the values actually apply. Params: actorLabel OR actorPath, exposure (the fixed adaptation brightness), bias? (AutoExposureBias, also override-enabled), componentName?, propertyName? (#950)"
1566
+ options:
1567
+ method: set_fixed_exposure
1462
1568
  level.export_actor_fbx:
1463
1569
  class_path: ue-mcp.bridge
1464
1570
  group: level
1465
- description: "Export an actor's skeletal/static mesh to FBX and write a metadata sidecar JSON (actor transform, mesh, materials, skeleton) for a downstream bridge (e.g. MetaTailor). Params: actorLabel, outputPath (.fbx). Returns fbx + metadata paths (#637)"
1571
+ description: "Export an actor's skeletal/static mesh to FBX and write a metadata sidecar JSON (actor transform, mesh, materials, skeleton) for a downstream bridge (e.g. MetaTailor). Params: actorLabel OR actorPath, outputPath (.fbx). Returns fbx + metadata paths (#637)"
1466
1572
  options:
1467
1573
  method: export_actor_fbx
1468
1574
  level.spawn_skeletal_mesh_actor:
1469
1575
  class_path: ue-mcp.bridge
1470
1576
  group: level
1471
- description: "Spawn a SkeletalMeshActor for visual/deform verification. Optional per-slot materials and single-node animation preview (animSequence + loop). Returns actorLabel + boxExtent. The animSequence is written to the component's editable AnimationData, so it persists across a level save/reload instead of only driving the runtime preview and coming back in A-pose (#790). Params: skeletalMesh, label?, location?, rotation?, scale?, materials? (path[]), animSequence?, loop? (#679/#677)"
1577
+ description: "Spawn a SkeletalMeshActor for visual/deform verification. Optional per-slot COMPONENT material overrides (they write the component's OverrideMaterials, not the mesh ASSET's slots, which material(build_material) writes) and single-node animation preview (animSequence + loop). Each entry in materials[] comes back with ok, and a path that does not load or a slot index past the mesh's slot count is reported rather than silently dropped, because a silently dropped assignment reads as one that worked. To dress an actor that is already placed, or to put one material on every slot, use level(set_component_materials) (#946). Returns actorLabel + boxExtent + materialSlotCount. The animSequence is written to the component's editable AnimationData, so it persists across a level save/reload instead of only driving the runtime preview and coming back in A-pose (#790). Params: skeletalMesh, label?, location?, rotation?, scale?, materials? (path[]), animSequence?, loop? (#679/#677)"
1472
1578
  options:
1473
1579
  method: spawn_skeletal_mesh_actor
1474
1580
  level.delete_actors:
1475
1581
  class_path: ue-mcp.bridge
1476
1582
  group: level
1477
- description: "Bulk-delete actors. Params: at least one of labelPrefix, className, tag; dryRun? to preview. Returns matched/deleted/labels (#220)"
1583
+ description: "Bulk-delete actors. The filter names say exactly what they match, because two level actions taking similar-sounding filters with different semantics is how a caller ends up trusting a wrong zero (#963): labelPrefix is a CASE-SENSITIVE PREFIX over the EDITOR LABEL, labelContains a case-insensitive SUBSTRING over the label, nameContains a case-insensitive substring over the INTERNAL name, className a case-sensitive substring over the class name. get_outliner's nameFilter is looser than any of them (label OR internal name, substring), so a string that selects a set there can select a different set here. When nothing matches, the response explains it rather than returning a bare zero: zeroMatchHint reports how many actors the same string WOULD have matched under the other semantics with samples, and a World Partition map says that only loaded actors were enumerated. classPathContains is a case-insensitive substring of the generated UClass path (e.g. /SurvivalGameKitV2/), so a whole vendor folder can be selected without listing every Blueprint class, and classPathContainsAny is the same match against any of several substrings (#924). Params: at least one of labelPrefix, labelContains, nameContains, className, tag, classPathContains, classPathContainsAny; dryRun? to preview. Returns matched/deleted/labels/classPaths (#220/#924/#963)"
1478
1584
  options:
1479
1585
  method: delete_actors
1480
1586
  level.delete_exact_labeled_actors_in_levels:
@@ -1495,6 +1601,30 @@ tasks:
1495
1601
  description: "World Partition ONLY: pin matched actors so they become resident and the normal actor actions can reach them, or unpin to release. Pinning is used rather than transient streaming because a transient load is dropped again by the streaming system mid-measurement. Takes the same filters as list_actor_descs and refuses to act on more than maxActors (default 256) so an unfiltered call cannot pin a whole map by accident. Reports residentAfter, read back from the world rather than assumed. Needs UE 5.5 or newer. Params: mode? (pin|unpin, default pin), filter?, className?, guids?, bounds?, maxActors?, dryRun? (#746)"
1496
1602
  options:
1497
1603
  method: load_actor_descs
1604
+ level.get_world_partition_settings:
1605
+ class_path: ue-mcp.bridge
1606
+ group: level
1607
+ description: "World Partition ONLY: the streaming knobs on the open map, plus the runtime cell transformer stack. Returns the world partition and runtime hash classes, whether streaming is enabled, the default HLOD layer, and grids[] with each grid's name, CellSize, LoadingRange and a dotted path rooted at the world partition. Grids are found by REFLECTION rather than against a fixed class, so this answers for the RuntimeHashSet layout and the older spatial hash alike. cellTransformers[] lists each stack entry with its class, its instancePath and the current values of the instanced transformer object's editable properties, which no read exposed. Params: none (#985)"
1608
+ options:
1609
+ method: get_world_partition_settings
1610
+ level.set_world_partition_settings:
1611
+ class_path: ue-mcp.bridge
1612
+ group: level
1613
+ description: "World Partition ONLY: write the streaming knobs. cellSize and loadingRange are the shorthand for the primary tuning pair and pick the map's only grid automatically, or name one with grid (its name) or gridPath (the dotted path from get_world_partition_settings). settings takes any dotted path rooted at the world partition, which is how the INSTANCED runtime cell transformer object is configured ('RuntimeCellsTransformerStack[0].Instance.SomeProperty') - that object is read-only through Python and was previously set by hand in the editor UI. Every path is resolved BEFORE anything is written, so a bad path fails the call rather than leaving the map streaming on a mixture nobody asked for, and each write reports previousValue and the value read back. Streaming settings only apply to cells generated after the change, so rebuild the streaming data before measuring. The map package is left dirty and is NOT saved. Params: cellSize?, loadingRange?, grid? (name), gridPath?, settings? (object of dotted path -> value) (#985)"
1614
+ options:
1615
+ method: set_world_partition_settings
1616
+ level.add_runtime_cell_transformer:
1617
+ class_path: ue-mcp.bridge
1618
+ group: level
1619
+ description: "World Partition ONLY: append a WorldPartitionRuntimeCellTransformer to RuntimeCellsTransformerStack and configure its instanced object in the same call. Adding the entry without being able to write the instance would leave the manual editor step exactly where it was, so the instance is created here and properties are applied to it. skipIfPresent (default true) makes a rerun a no-op that reports the existing index instead of stacking duplicates. position inserts at an index rather than appending, because the stack is ordered. Params: transformerClass (short name, Module.Class or /Script path), properties? (object applied to the instance), position? (default -1 = append), skipIfPresent? (default true) (#985)"
1620
+ options:
1621
+ method: add_runtime_cell_transformer
1622
+ level.set_actor_hlod_layer:
1623
+ class_path: ue-mcp.bridge
1624
+ group: level
1625
+ description: "Assign (or clear) the per-actor HLODLayer override across every actor a selector picks. Assigning one across 295 InstancedFoliageActors was a Python loop. Goes through the engine's own AActor::SetHLODLayer rather than writing the private property directly, so the result behaves like an edit made in the details panel. hlodLayer=null clears the override. An actor already carrying the requested layer is reported as unchanged rather than counted as an update, so a rerun is readable. Optionally sets bEnableAutoLODGeneration in the same pass, since the layer only matters when the actor is allowed to build HLODs at all. On a World Partition map this dirties one package per actor and does NOT save. Params: hlodLayer (asset path or null), at least one of actorLabels[]/labelPrefix/labelContains/tag/classFilter/folderPath/folderPathPrefix, matchSubclasses? (default true), enableAutoLODGeneration?, dryRun?, transactionLabel? (#985)"
1626
+ options:
1627
+ method: set_actor_hlod_layer
1498
1628
  level.set_actor_folder_path:
1499
1629
  class_path: ue-mcp.bridge
1500
1630
  group: level
@@ -1504,55 +1634,55 @@ tasks:
1504
1634
  level.add_actor_tag:
1505
1635
  class_path: ue-mcp.bridge
1506
1636
  group: level
1507
- description: "Append a tag to an actor's Tags array. Params: actorLabel, tag (#219)"
1637
+ description: "Append a tag to an actor's Tags array. Params: actorLabel OR actorPath, tag (#219)"
1508
1638
  options:
1509
1639
  method: add_actor_tag
1510
1640
  level.remove_actor_tag:
1511
1641
  class_path: ue-mcp.bridge
1512
1642
  group: level
1513
- description: "Remove a tag from an actor's Tags array. Params: actorLabel, tag (#219)"
1643
+ description: "Remove a tag from an actor's Tags array. Params: actorLabel OR actorPath, tag (#219)"
1514
1644
  options:
1515
1645
  method: remove_actor_tag
1516
1646
  level.set_actor_tags:
1517
1647
  class_path: ue-mcp.bridge
1518
1648
  group: level
1519
- description: "Replace an actor's Tags array. Params: actorLabel, tags[] (#219)"
1649
+ description: "Replace an actor's Tags array. Params: actorLabel OR actorPath, tags[] (#219)"
1520
1650
  options:
1521
1651
  method: set_actor_tags
1522
1652
  level.list_actor_tags:
1523
1653
  class_path: ue-mcp.bridge
1524
1654
  group: level
1525
- description: "List an actor's Tags. Params: actorLabel (#219)"
1655
+ description: "List an actor's Tags. Params: actorLabel OR actorPath (#219/#983)"
1526
1656
  options:
1527
1657
  method: list_actor_tags
1528
1658
  level.attach_actor:
1529
1659
  class_path: ue-mcp.bridge
1530
1660
  group: level
1531
- description: "Attach actor as child. Params: childLabel, parentLabel, attachRule? (KeepWorld|KeepRelative|SnapToTarget; default KeepWorld), socketName? (#205)"
1661
+ description: "Attach actor as child. Params: childLabel OR childPath, parentLabel OR parentPath, attachRule? (KeepWorld|KeepRelative|SnapToTarget; default KeepWorld), socketName? (#205)"
1532
1662
  options:
1533
1663
  method: attach_actor
1534
1664
  level.detach_actor:
1535
1665
  class_path: ue-mcp.bridge
1536
1666
  group: level
1537
- description: "Detach actor from parent. Params: childLabel (#205)"
1667
+ description: "Detach actor from parent. Params: childLabel OR childPath (#205/#983)"
1538
1668
  options:
1539
1669
  method: detach_actor
1540
1670
  level.attach_component:
1541
1671
  class_path: ue-mcp.bridge
1542
1672
  group: level
1543
- description: "Attach an actor root or exact named child SceneComponent to an actor root or exact named parent SceneComponent. A non-root child changes only component hierarchy, not actor parentage. An already-matching attachment is a no-op and does not reapply transform rules. Returns verified resolved component and socket details; native attachment failure is an error. Params: childLabel, parentLabel, childComponentName? (default child root), parentComponentName? (default parent root), socketName?, attachRule? (KeepWorld|KeepRelative|SnapToTarget; default KeepWorld), weldSimulatedBodies? (default false)"
1673
+ description: "Attach an actor root or exact named child SceneComponent to an actor root or exact named parent SceneComponent. A non-root child changes only component hierarchy, not actor parentage. An already-matching attachment is a no-op and does not reapply transform rules. Returns verified resolved component and socket details; native attachment failure is an error. Params: childLabel OR childPath, parentLabel OR parentPath, childComponentName? (default child root), parentComponentName? (default parent root), socketName?, attachRule? (KeepWorld|KeepRelative|SnapToTarget; default KeepWorld), weldSimulatedBodies? (default false)"
1544
1674
  options:
1545
1675
  method: attach_component
1546
1676
  level.detach_component:
1547
1677
  class_path: ue-mcp.bridge
1548
1678
  group: level
1549
- description: "Detach an actor root or exact named child SceneComponent while preserving world transform. Omitted childComponentName selects the actor root. An already-detached component is a verified no-op. Returns previous parent component/socket details plus alreadyDetached and detachmentChanged. Params: childLabel, childComponentName?"
1679
+ description: "Detach an actor root or exact named child SceneComponent while preserving world transform. Omitted childComponentName selects the actor root. An already-detached component is a verified no-op. Returns previous parent component/socket details plus alreadyDetached and detachmentChanged. Params: childLabel OR childPath, childComponentName?"
1550
1680
  options:
1551
1681
  method: detach_component
1552
1682
  level.set_actor_mobility:
1553
1683
  class_path: ue-mcp.bridge
1554
1684
  group: level
1555
- description: "Set actor root component Mobility. Params: actorLabel, mobility (static|stationary|movable) (#205)"
1685
+ description: "Set actor root component Mobility. Params: actorLabel OR actorPath, mobility (static|stationary|movable) (#205)"
1556
1686
  options:
1557
1687
  method: set_actor_mobility
1558
1688
  level.get_current_edit_level:
@@ -1600,7 +1730,7 @@ tasks:
1600
1730
  level.batch_translate:
1601
1731
  class_path: ue-mcp.bridge
1602
1732
  group: level
1603
- description: "Translate a set of actors by an offset. Params: offset (Vec3), actorLabels[] OR tag (#203)"
1733
+ description: "Translate a set of actors by an offset. Params: offset (Vec3), actorLabels[] and/or actorPaths[] OR tag (#203/#983)"
1604
1734
  options:
1605
1735
  method: batch_translate
1606
1736
  level.place_actors_batch:
@@ -1609,16 +1739,106 @@ tasks:
1609
1739
  description: "Bulk-spawn StaticMeshActors with per-instance mesh + transform. Params: actors[]: [{staticMesh, location?, rotation?, scale?, label?}]. Mesh loads cached per path. Returns spawned/failedMesh/failedSpawn counts + labels (#264)"
1610
1740
  options:
1611
1741
  method: place_actors_batch
1742
+ level.batch_set_properties:
1743
+ class_path: ue-mcp.bridge
1744
+ group: level
1745
+ description: "Set the same properties on every actor an editor-side SELECTOR picks. batch_translate needs an explicit label list, which for auto-numbered labels is a payload you have to generate first; this takes tag / classFilter / labelPrefix / labelContains / folderPath instead, so '190 SpotLights tagged LichtTest' is one call. Property writes delegate to set_actor_property, so dotted paths, actor-label object references and TArray-of-actor-labels all behave identically to the single-actor action. The whole batch is ONE undo transaction. dryRun resolves every property against every matched actor's class and reports currentValue without writing. The level is left dirty and is NOT saved. Params: properties (object of propertyName -> value, max 32), at least one of actorLabels[]/labelPrefix/labelContains/tag/classFilter/folderPath/folderPathPrefix, matchSubclasses? (default true), dryRun?, force? (bypass EditDefaultsOnly), transactionLabel? (#984)"
1746
+ options:
1747
+ method: batch_set_actor_properties
1748
+ level.bulk_set_component_property:
1749
+ class_path: ue-mcp.bridge
1750
+ group: level
1751
+ description: "Set one property on the SAME NAMED COMPONENT across every actor a selector picks (the real case: NavModifierComponent.AreaClass on dozens of placed StaticMeshActors). Delegates to set_component_property per actor, so value semantics match exactly, including JSON null to clear an object reference. An actor that has no component of that name is reported as no_such_component rather than counted as a failure or silently skipped. One undo transaction. The level is left dirty and is NOT saved. Params: componentName, propertyName, value, at least one of actorLabels[]/labelPrefix/labelContains/tag/classFilter/folderPath/folderPathPrefix, matchSubclasses? (default true), dryRun?, transactionLabel? (#941)"
1752
+ options:
1753
+ method: bulk_set_component_property
1754
+ level.remove_components_by_class:
1755
+ class_path: ue-mcp.bridge
1756
+ group: level
1757
+ description: "Remove every instance component of a class across the actors a selector picks. remove_component takes one name at a time, which cannot reach 230 orphaned SplineMeshComponents whose names are auto-generated (SplineMeshComponent_0, _1, ...). dryRun DEFAULTS TO TRUE here, unlike delete_actors: this deletes components you cannot enumerate by name, so you see the list first. Only INSTANCE components are removed; a native or SCS component belongs to the class and is reported under skippedNonInstanceComponents rather than destroyed, because destroying it would come back on the next construction rerun. Omitting every actor selector means every loaded actor, which is a legitimate request and the reason for the dryRun default. One undo transaction. Params: componentClass, actorClassFilter? (or classFilter), componentNameContains?, matchComponentSubclasses? (default true), actorLabels?/labelPrefix?/labelContains?/tag?/folderPath?/folderPathPrefix?, dryRun? (default TRUE), save? (default false; the level is otherwise left dirty), transactionLabel? (#907)"
1758
+ options:
1759
+ method: remove_components_by_class
1760
+ level.spawn_actors_batch:
1761
+ class_path: ue-mcp.bridge
1762
+ group: level
1763
+ description: "Bulk-spawn actors of ANY class with per-instance properties, from explicit transforms or from positions DERIVED in the editor. place_actors_batch is StaticMeshActor only and spawn_light takes one position. Exactly one source: instances[] ({location?, rotation?, scale?, label?, properties?}); fromComponents ({componentClass?, componentNameContains?, actor selector, offset?, extentFraction?, space?, inheritRotation?}) which places one actor per matched component at boundsOrigin + boxExtent*extentFraction + offset; or alongSpline ({actorLabel, componentName?, spacing (cm), startDistance?, endDistance?, offset?, alignToTangent? (default true)}). fromComponents defaults to space='local' on purpose: a component's WORLD bounds are axis-aligned, so 'the top of the mesh' computed from them is not on a rotated lamp post, while local bounds carry the component's own orientation. That is what makes 'a SpotLight at 72 percent of each of 190 lamp posts' one call instead of 190 bounds reads and 190 spawns. dryRun returns every computed transform without spawning. maxSpawn (default 500) refuses a plan bigger than you meant. The level is left dirty and is NOT saved. Params: actorClass, exactly one of instances[]/fromComponents/alongSpline, properties? (applied to every spawn; per-instance properties win), labelPrefix?, dryRun?, maxSpawn?, transactionLabel? (#987)"
1764
+ options:
1765
+ method: spawn_actors_batch
1766
+ level.set_component_materials:
1767
+ class_path: ue-mcp.bridge
1768
+ group: level
1769
+ description: "Set per-slot COMPONENT material overrides on placed actors. This is the other half of material assignment and the half that had no action: material(build_material) and asset(set_property) write the mesh ASSET's slots, while a placed actor usually needs the instance override the details panel edits (OverrideMaterials). set_actor_material does one slot on whichever primitive component it finds first, so dressing a placed skeletal mesh meant a Python loop over get_num_materials(). Exactly one of: materials[] (index = slot; a null or empty entry clears just that slot's override), material (one path applied to EVERY slot), clearOverrides=true (drop every override so the asset's own slots show through). Every slot comes back with its previous and new path AND whether each is a componentOverride or the meshDefault, read back rather than echoed. Every material path is resolved before anything is written, so a bad path fails the call instead of half-applying it. Works on any UMeshComponent (static or skeletal). One undo transaction; the LEVEL is dirtied and NOT saved, the mesh asset is untouched. Params: at least one of actorLabels[]/labelPrefix/labelContains/tag/classFilter/folderPath/folderPathPrefix, componentName? (default the actor's first mesh component), materials? OR material? OR clearOverrides?, dryRun?, transactionLabel? (#946)"
1770
+ options:
1771
+ method: set_component_materials
1772
+ level.spawn_transient_actor:
1773
+ class_path: ue-mcp.bridge
1774
+ group: level
1775
+ description: "Spawn an actor for VERIFICATION that cannot be saved into the map. Checking anything that only exists on a live actor needs a subject, and spawning a normal one and forgetting to delete it is how a SceneCapture2D ended up committed to source control. So this actor is transient by construction: RF_Transient (the package serializer skips it), bTemporaryEditorActor (an editor preview actor, kept out of the level's persistent actor list), no external actor package on a World Partition map, and its label is set with bMarkDirty=false because SetActorLabel dirties the map by default. It carries a UEMCP_TransientVerification tag so it can be listed and so destroy refuses anything it did not create, and the response reports dirtiedPackages rather than promising nothing was dirtied. initialize controls how far towards a running state it is taken, because the EDITOR WORLD HAS NOT BEGUN PLAY and a spawned actor therefore gets neither InitializeComponent nor BeginPlay: 'none' spawns only, 'construction' (default) reruns construction scripts, 'beginPlay' also registers components and dispatches the begin-play cycle on this actor, which is what a component doing its setup in BeginPlay (a GAS ability system component's attribute-set scan, for one) needs before it can be read. Each returned component reports registered and initialized so the caller can see what actually happened. Destroy it with destroy_transient_actor. Params: actorClass, location?, rotation?, scale?, label?, initialize? (none|construction|beginPlay), hideFromOutliner?, world? (editor|pie) (#956)"
1776
+ options:
1777
+ method: spawn_transient_actor
1778
+ level.destroy_transient_actor:
1779
+ class_path: ue-mcp.bridge
1780
+ group: level
1781
+ description: "Destroy an actor created by spawn_transient_actor. It will ONLY destroy an actor carrying the UEMCP_TransientVerification tag and RF_Transient: a label or path that resolves to a real level actor is refused by name rather than deleted, because this is the cleanup call and a mistyped label at cleanup time is how real work disappears. Use delete_actor or delete_actors for a real level actor. Params: actorPath OR actorLabel OR all=true (every transient verification actor in this world), world? (editor|pie) (#956)"
1782
+ options:
1783
+ method: destroy_transient_actor
1784
+ level.list_transient_actors:
1785
+ class_path: ue-mcp.bridge
1786
+ group: level
1787
+ description: "List the verification actors spawned by spawn_transient_actor that are still in the world, so nothing is left behind by accident. They cannot be saved into the map and do not survive a map reload, but they are live until destroyed. Params: world? (editor|pie) (#956)"
1788
+ options:
1789
+ method: list_transient_actors
1790
+ level.convert_brushes_to_static_mesh:
1791
+ class_path: ue-mcp.bridge
1792
+ group: level
1793
+ description: "Convert BSP brushes into StaticMeshActors via UEditorActorSubsystem::ConvertActors, generating the static meshes into destinationPath. Finishing a blockout pass otherwise meant doing it by hand. dryRun DEFAULTS TO TRUE, because conversion DESTROYS the source brushes and there is no way back to a builder brush once the map is saved. Every candidate the selector picked comes back with a verdict, so nothing is silently dropped: the default builder brush, brush shapes, volumes (both derive from ABrush and neither is geometry a player sees) and subtractive brushes (they carve space and have no surface, so converting one yields an empty mesh that looks like success) are all excluded unless you opt in by name. classFilter is EXACT by default here. Reports convertedFrom (recorded before the call, since the actors are gone after it), newActorLabels and newStaticMeshes. Params: actorLabels[] OR folderPath (+ recursiveFolder?, default true), classFilter?, exactClass? (default true), destinationPath? (default /Game/Meshes/Converted), dryRun? (default TRUE), allowSubtractive?, includeVolumes? (#911)"
1794
+ options:
1795
+ method: convert_brushes_to_static_mesh
1796
+ level.rerun_construction:
1797
+ class_path: ue-mcp.bridge
1798
+ group: level
1799
+ description: "Re-run the construction script on PLACED actor instances, so an SCS or construction-script change reaches the copies already in the level instead of only new ones. blueprint(run_construction_script) builds a TEMPORARY actor and throws it away, and Python cannot do this at all because Actor.rerun_construction_scripts() is missing from the wrapper. Requires actorLabels or className: this destroys and rebuilds every generated component on each match, so it will not run against a whole level implicitly. Reports reran, failed[], samples[], and how many matches have no user construction script (their generated components are still rebuilt, but a caller expecting a script change to land needs to know). Leaves the level dirty and does NOT save. Params: actorLabels? (string[]) and/or className? (Blueprint or native class), matchSubclasses? (default true), world? (editor|pie) (#944)"
1800
+ options:
1801
+ method: rerun_construction_scripts
1802
+ level.recreate_physics_state:
1803
+ class_path: ue-mcp.bridge
1804
+ group: level
1805
+ description: "Rebuild the physics and collision state on the components a selector picks, after the mesh data underneath them changed. Stale collision makes line_trace report a MISS through solid geometry, which is the worst kind of wrong answer because nothing about it looks wrong. dryRun DEFAULTS TO TRUE and is the preflight: it lists which components would be rebuilt and what their collision enabled state and profile are right now. Requires at least one bound (actorLabels, labelPrefix, tag, classFilter, componentClass, componentNameContains) and never refreshes a whole world implicitly. Returns per-component before/after collision state plus a post-refresh collisionSummary histogram. Params: actorLabels?, labelPrefix?, tag?, classFilter?, componentClass?, componentNameContains?, dryRun? (default TRUE), maxComponents? (default 2000), world? (editor|pie) (#915)"
1806
+ options:
1807
+ method: recreate_physics_state
1808
+ level.test_component_overlap:
1809
+ class_path: ue-mcp.bridge
1810
+ group: level
1811
+ description: "Do two placed components overlap? Returns the boolean plus both sides' local bounds, world bounds and world transforms, and separation (when apart) or penetration depth (when overlapping). For a UBoxComponent it also returns boxExtentUnscaled, the authored BoxExtent the details panel shows, which no other read exposed. method=OBB (default) runs a separating-axis test on the components' oriented local bounds, so a rotated box is tested as a rotated box; method=AABB compares the axis-aligned world bounds and adds a per-axis gap. Deliberately geometric rather than a physics overlap query: a physics answer depends on collision state, and stale collision state is what makes a trace lie (see recreate_physics_state). Omitting a componentName selects that actor's root component. Params: actorLabelA OR actorPathA, actorLabelB OR actorPathB, componentNameA?, componentNameB?, method? (OBB|AABB), world? (editor|pie) (#914)"
1812
+ options:
1813
+ method: test_component_overlap
1612
1814
  level.line_trace:
1613
1815
  class_path: ue-mcp.bridge
1614
1816
  group: level
1615
- description: "Line trace in the editor world. Traces simple collision by default, the same as a gameplay trace, so the result matches what the running game hits; pass traceComplex to trace per-triangle instead. channel picks the collision channel, including channels this project renamed in its collision settings. The response echoes traceComplex and channel, and faceIndex is only present on a complex hit. Returns hit + actorLabel/actorClass/componentName/componentClass/location/impactPoint/normal/distance/faceIndex/boneName/physicalMaterial. Params: start (Vec3), end? (Vec3) OR direction? (Vec3) + distance? (default 200000), traceComplex? (default false), channel? (default Visibility), ignoreActors? (array of labels) (#420, #807)"
1817
+ description: "Line trace. world selects which world is traced: 'editor' (default) or 'pie' for the LIVE running PIE world, which is the only way to check geometry that exists once play has begun (#933). Traces simple collision by default, the same as a gameplay trace, so the result matches what the running game hits; pass traceComplex to trace per-triangle instead. channel picks the collision channel, including channels this project renamed in its collision settings. The response echoes traceComplex, channel and the world that actually answered, and faceIndex is only present on a complex hit. Returns hit + actorLabel/actorClass/componentName/componentClass/location/impactPoint/normal/distance/faceIndex/boneName/physicalMaterial. Params: start (Vec3), end? (Vec3) OR direction? (Vec3) + distance? (default 200000), traceComplex? (default false), channel? (default Visibility), ignoreActors? (array of labels), world? (editor|pie), pieInstance? (#420, #807, #933)"
1616
1818
  options:
1617
1819
  method: line_trace
1820
+ level.bulk_line_trace:
1821
+ class_path: ue-mcp.bridge
1822
+ group: level
1823
+ description: "Batch of line traces. Each traces[] item uses the same semantics as line_trace (start + end or direction+distance, simple collision by default, optional traceComplex/channel/ignoreActors). The top-level world applies to the WHOLE batch, so one call cannot straddle the editor and PIE worlds and present the results as comparable. Caps at 256. Returns results[] in traces[] order, one per item, each with the same fields as line_trace (or success=false + error for that item). Params: traces[], world? (editor|pie), pieInstance? (#933)"
1824
+ options:
1825
+ method: bulk_line_trace
1826
+ level.snap_instances_to_surface:
1827
+ class_path: ue-mcp.bridge
1828
+ group: level
1829
+ description: "Project ISMC/HISMC instances down onto surface geometry, preserving each instance's rotation and scale. Dry-run by default: preflights every requested instance and reports what would move before anything does, then applies successful projections in one transaction with rollback. Filter the surfaces traced against with surfaceActorClass/surfaceActorLabels so instances do not snap onto each other. onMiss controls whether a miss aborts the batch or is skipped. Does not save packages. Params: actorLabel OR actorPath, componentName?, instanceIndices? (omit for all), maxInstances?, traceStartOffset?, traceDistance?, surfaceOffset?, channel?, traceComplex?, surfaceActorClass?, surfaceActorLabels?, onMiss? ('abort'|'skip'), dryRun? (default true) (#905)"
1830
+ options:
1831
+ method: snap_instances_to_surface
1832
+ level.summarize_static_mesh_usage:
1833
+ class_path: ue-mcp.bridge
1834
+ group: level
1835
+ description: "Read-only inventory of which static meshes are actually placed in the loaded world, aggregated in one game-thread scan instead of walking every actor and component. This is the action for placement counts, and query_components is not a substitute for it: grouping there only increments, so one HISM holding 5,000 instances counts as 1, while this SUMS real ISM/HISM instances and counts distinct actors per mesh, and it sorts every aggregate before truncating so the top N is the true top N with an exact totalUniqueMeshes. Distinguishes actors, components and placements. Results are bounded; full-scan totals are preserved alongside the truncated rows. Loads nothing and saves nothing. Params: world? (editor|pie), maxResults?, includeOccurrences?, maxOccurrences? (#903)"
1836
+ options:
1837
+ method: summarize_static_mesh_usage
1618
1838
  level.snap_actor_to_floor:
1619
1839
  class_path: ue-mcp.bridge
1620
1840
  group: level
1621
- description: "Snap an actor's bounds-bottom to the first downward line-trace hit. Equivalent of the End-key shortcut, works on arbitrary geometry (not just Landscape). Params: actorLabel, floorOffset? (added to impact Z, default 0), maxDistance? (default 100000) (#419)"
1841
+ description: "Snap an actor's bounds-bottom to the first downward line-trace hit. Equivalent of the End-key shortcut, works on arbitrary geometry (not just Landscape). The actor lookup and the downward trace both run in the world named by world, so a PIE snap measures against PIE geometry (#933). Params: actorLabel OR actorPath, floorOffset? (added to impact Z, default 0), maxDistance? (default 100000), world? (editor|pie), pieInstance? (#419, #933)"
1622
1842
  options:
1623
1843
  method: snap_actor_to_floor
1624
1844
 
@@ -1626,19 +1846,19 @@ tasks:
1626
1846
  material.read:
1627
1847
  class_path: ue-mcp.bridge
1628
1848
  group: material
1629
- description: "Read material structure. Params: assetPath"
1849
+ description: "Read material structure. Accepts a Material or a MaterialInstance; an instance answers with its lineage, shading setup and resolved parameters instead of a graph (#952). Params: assetPath"
1630
1850
  options:
1631
1851
  method: read_material
1632
1852
  material.list_parameters:
1633
1853
  class_path: ue-mcp.bridge
1634
1854
  group: material
1635
- description: "List overridable parameters. Params: assetPath"
1855
+ description: "List parameters. On a MaterialInstance each entry carries the resolved value, the parent's defaultValue and whether this instance overrides it (#952). Params: assetPath"
1636
1856
  options:
1637
1857
  method: list_material_parameters
1638
1858
  material.set_parameter:
1639
1859
  class_path: ue-mcp.bridge
1640
1860
  group: material
1641
- description: "Set parameter on MaterialInstance. Params: assetPath, parameterName, parameterType, value"
1861
+ description: "Set parameter on MaterialInstance. Params: assetPath, parameterName, parameterType? (scalar|vector|texture, auto-detected when omitted), value, association?. A vector/colour value may be passed as value OR color, shaped {r,g,b,a}, [r,g,b,a] or '(R=..,G=..,B=..,A=..)'. Saves the instance and returns readBack + saved so a set/verify round trip needs no second call (#952)"
1642
1862
  options:
1643
1863
  method: set_material_parameter
1644
1864
  material.read_instance:
@@ -1680,7 +1900,7 @@ tasks:
1680
1900
  material.set_expression_value:
1681
1901
  class_path: ue-mcp.bridge
1682
1902
  group: material
1683
- description: "Set a value on an expression node. Common typed knobs: value (constant/param default), texturePath (TextureSample/TextureSampleParameter2D default texture). For any OTHER UPROPERTY on the expression (e.g. SamplerType, SamplerSource, Group), pass propertyName + value to hit the generic reflection setter. Params: materialPath, expressionIndex, value?, texturePath?, propertyName? (#663)"
1903
+ description: "Set a value on an expression node. Common typed knobs: value (constant/param default), texturePath (TextureSample/TextureSampleParameter2D default texture). Constant2Vector/3Vector/4Vector and VectorParameter all take value (or color) as {r,g,b,a}, {x,y,z,w}, [r,g,b,a] or '(R=..,G=..)'; Constant2Vector reads the first two components (#979). Saves the material and reports saved. For any OTHER UPROPERTY on the expression (e.g. SamplerType, SamplerSource, Group), pass propertyName + value to hit the generic reflection setter. Params: materialPath, expressionIndex, value?, color?, texturePath?, propertyName? (#663)"
1684
1904
  options:
1685
1905
  method: set_expression_value
1686
1906
  material.set_custom_expression:
@@ -1731,6 +1951,12 @@ tasks:
1731
1951
  description: "List expression nodes inside a MaterialFunction. Params: functionPath (#463)"
1732
1952
  options:
1733
1953
  method: list_expressions_in_function
1954
+ material.build_material:
1955
+ class_path: ue-mcp.bridge
1956
+ group: material
1957
+ description: "Build a PBR material from a texture set in one call: creates a TextureSample per entry, picks each sampler type FROM THE TEXTURE (a virtual/UDIM texture silently loses its material connection on recompile unless it samples through the Virtual* variant), wires them, recompiles, saves, and reports which connections survived the recompile. Params: name + packagePath? (create) OR materialPath (build into an existing material); textures = {baseColor, normal, roughness, metallic, specular, emissive, opacity, opacityMask, ambientOcclusion, ...} plus packed keys orm (R=AO,G=Roughness,B=Metallic) and rma; samplerTypes? = per-key override (e.g. {normal: 'VirtualNormal'}); clearExisting?; assignToMesh? (StaticMesh or SkeletalMesh asset) with meshSlots? (names or indices, default all) (#946)"
1958
+ options:
1959
+ method: build_material
1734
1960
  material.create_simple:
1735
1961
  class_path: ue-mcp.bridge
1736
1962
  group: material
@@ -1958,7 +2184,7 @@ tasks:
1958
2184
  animation.add_notify:
1959
2185
  class_path: ue-mcp.bridge
1960
2186
  group: animation
1961
- description: "Add notify. For PlayMontageNotify the notifyName is also written onto the spawned notify object so OnPlayMontageNotifyBegin broadcasts it (not 'None'), and montage branching-point markers refresh (#528). notifyProperties writes EditAnywhere fields onto the spawned notify object and therefore requires a notifyClass that resolves. Params: assetPath, notifyName, triggerTime, notifyClass?, notifyProperties?"
2187
+ description: "Add notify. For PlayMontageNotify the notifyName is also written onto the spawned notify object so OnPlayMontageNotifyBegin broadcasts it (not 'None'), and montage branching-point markers refresh (#528/#880). On a montage the PlayMontageNotify classes are added as BRANCHING POINT notifies, which is the only tick type UAnimNotify_PlayMontageNotify::BranchingPointNotify runs at, so OnPlayMontageNotifyBegin broadcasts without a montage reload; pass branchingPoint to force it either way, and read branchingPointMarkerCount in the response to see what the montage cached. notifyProperties writes EditAnywhere fields onto the spawned notify object and therefore requires a notifyClass that resolves. Params: assetPath, notifyName, triggerTime, notifyClass?, notifyProperties?"
1962
2188
  options:
1963
2189
  method: add_anim_notify
1964
2190
  animation.remove_notify:
@@ -2144,9 +2370,15 @@ tasks:
2144
2370
  animation.read_ik_rig:
2145
2371
  class_path: ue-mcp.bridge
2146
2372
  group: animation
2147
- description: "Read IK Rig chains, solvers, skeleton. Params: assetPath"
2373
+ description: "Read an IK Rig's preview mesh, skeleton roots/bones, ancestry-validated chains and goal assignments, concrete goals, exclusions, and structured solver/FBIK effector state. Params: assetPath"
2148
2374
  options:
2149
2375
  method: read_ik_rig
2376
+ animation.configure_ik_rig:
2377
+ class_path: ue-mcp.bridge
2378
+ group: animation
2379
+ description: "UE 5.8 only. Author an existing IK Rig through UIKRigController with strict bone, ancestry, goal, and setting validation, native readback, one transaction, and checked save; older engines return unsupported_engine_version. autoSetup='retarget' installs the native retarget definition; 'full_body' installs the retarget definition then Full Body IK before requested desired-state upserts. Params: rigPath, autoSetup? ('retarget'|'full_body'), retargetRoot?, rootMotionBone?, chains?: [{name,startBone,endBone,goal?}], fullBodyIK?: {solverIndex?,rootBone,enabled?,goals:[{name,bone,positionAlpha?,rotationAlpha?,chainDepth?,strengthAlpha?,pullChainAlpha?,pinRotation?}]}, exclusions?: [{bone,excluded}]."
2380
+ options:
2381
+ method: configure_ik_rig
2150
2382
  animation.list_control_rig_variables:
2151
2383
  class_path: ue-mcp.bridge
2152
2384
  group: animation
@@ -2165,6 +2397,36 @@ tasks:
2165
2397
  description: "Read a Control Rig's per-element hierarchy metadata: each element's name, type (Bone|Control|Null|Curve...), index, and parent. Params: assetPath (#619)"
2166
2398
  options:
2167
2399
  method: read_control_rig_hierarchy
2400
+ animation.begin_control_rig_edit:
2401
+ class_path: ue-mcp.bridge
2402
+ group: animation
2403
+ description: "UE 5.8 only. Create a Sequencer Control Rig editing session over a source AnimSequence; native returns unsupported_engine_version on older engines. Baseline first: before this call, reuse or create a Control Rig for the target character, bind/import the exact target skeleton, add the intended controls, author Forward Solve, add Backward/Inverse Solve, verify it with read_control_rig_hierarchy/read_control_rig_graph, and pass an unchanged source round-trip. For a new baseline, the bundled Epic 5.8 controlrig actions include epic_create, epic_import_bones_from_asset, epic_add_control, and epic_add_backward_solve_graph; epic_create alone is not a usable rig. There is no silent fallback to raw bone-key authoring. rigMode='fk' uses UFKControlRig only when generated FK controls are sufficient; rigMode='asset' requires the verified controlRigPath and rejects rigs without inverse execution. bindingTag is the stable natural key for replay. onConflict is skip|error (default error); existing sessions are never modified. layered defaults false. startFrame is inclusive and endFrame is exclusive. Params: sequencePath, skeletalMeshPath, sourceAnimationPath, rigMode ('fk'|'asset'), controlRigPath?, layered?, startFrame?, endFrame?, displayRate?, bindingTag?, onConflict?. Returns the resolved bindingTag/binding GUID, rig, frame range, controls and created/existed status."
2404
+ options:
2405
+ method: begin_control_rig_edit
2406
+ animation.read_control_rig_edit:
2407
+ class_path: ue-mcp.bridge
2408
+ group: animation
2409
+ description: "UE 5.8 only. Read transform, bool, float/scale-float, and integer/enum controls from a Control Rig editing session without changing editor state; native returns unsupported_engine_version on older engines and has no silent fallback. Params: sequencePath, bindingTag, controlNames?, frames?, space? ('local'|'global'). Scalar samples return value instead of transform. Control metadata includes native controlType, animatable, and enum path/options where applicable. Returns session identity, layered mode, range/rate, filtered control metadata, and requested frame samples."
2410
+ options:
2411
+ method: read_control_rig_edit
2412
+ animation.apply_control_rig_edits:
2413
+ class_path: ue-mcp.bridge
2414
+ group: animation
2415
+ description: "UE 5.8 only. Apply typed Control Rig edits in one transaction; native returns unsupported_engine_version on older engines. There is no silent fallback to raw bone tracks. set_keys writes strictly ordered full per-frame transforms from normalized quaternions and preserves shortest-arc quaternion continuity. A set operation writes one full absolute transform at frame or frames. An offset operation applies translation/rotation/scale deltas across an inclusive frame range with optional edge blends. contact_lock densely constrains a translatable driver control, or an optional driven bone/socket reference, to a fixed component-space target with smooth edge blends and optional pole/control stabilization. Driver and stabilizer keys are read back transactionally. A drivenReference contact returns verification='bake_and_analyze_required'; bake it and analyze every constrained frame before accepting the bone/socket result. set_bool, set_float, and set_int key matching scalar controls; enum controls use set_int with one of the integer values reported in enumOptions. Params: sequencePath, bindingTag, operations[] where set_keys={op:'set_keys',control,keys:[{frame,transform:{translation,rotationQuaternion,scale}}],space?}, set={op:'set',control,frame|frames,transform:{translation,rotationDegrees,scale},space?}, offset={op:'offset',control,startFrame,endFrame,translationCm?,rotationDegrees?,scaleMultiplier?,space?,blendInFrames?,blendOutFrames?}, contact_lock={op:'contact_lock',control,drivenReference?,startFrame,endFrame,target:{translation,rotationQuaternion?},blendInFrames?,blendOutFrames?,stabilizeControls?,positionToleranceCm?,rotationToleranceDegrees?}, set_bool={op:'set_bool',control,frame|frames,value}, set_float={op:'set_float',control,frame|frames,value}, or set_int={op:'set_int',control,frame|frames,value}. Sequencer's current interpolation mode is retained. Returns per-operation counts, affected controls/frames, and contactQa summaries; a failed key/readback batch is undone."
2416
+ options:
2417
+ method: apply_control_rig_edits
2418
+ animation.bake_control_rig_edit:
2419
+ class_path: ue-mcp.bridge
2420
+ group: animation
2421
+ description: "UE 5.8 only. Bake the evaluated Control Rig session to a new AnimSequence asset; native returns unsupported_engine_version on older engines and has no raw-track fallback. The source LevelSequence remains unchanged. outputAssetPath is the output natural key; onConflict is skip|error (default error), never overwrite. Key reduction and Sequencer links are not supported yet, so reduceKeys/createLink must be false or omitted. Params: sequencePath, bindingTag, outputAssetPath, frameRate?, reduceKeys?, tolerance?, createLink?, onConflict?. Returns output asset metadata, frame/rate counts, status, and delete-created-asset rollback."
2422
+ options:
2423
+ method: bake_control_rig_edit
2424
+ animation.analyze_animation:
2425
+ class_path: ue-mcp.bridge
2426
+ group: animation
2427
+ description: "Cross-version, data-driven AnimSequence inspection using the native animation APIs available in the compiled engine. Samples an AnimSequence and reports deterministic numeric motion diagnostics without Python or viewport inference. Params: assetPath (required AnimSequence), skeletalMeshPath?, boneNames?, frames?, sampleRate?, loop?, outputDirectory? (must resolve under Project/Saved/Codex/AnimationQA and must not already contain artifacts). Returns source/rate/range metadata, sampled local/component transforms, root-motion and continuity metrics, and any written analysis artifacts."
2428
+ options:
2429
+ method: analyze_animation
2168
2430
  animation.set_root_motion:
2169
2431
  class_path: ue-mcp.bridge
2170
2432
  group: animation
@@ -2204,9 +2466,15 @@ tasks:
2204
2466
  animation.read_ik_retargeter:
2205
2467
  class_path: ue-mcp.bridge
2206
2468
  group: animation
2207
- description: "Read IKRetargeter: source/target rigs and chain mappings. Params: assetPath (#246)"
2469
+ description: "Read an IK Retargeter's source/target rigs and preview meshes, flattened and per-op chain mappings, typed op stack, and all named/current pose offsets when the compiled engine exposes them. Params: assetPath (#246)"
2208
2470
  options:
2209
2471
  method: read_ik_retargeter
2472
+ animation.configure_ik_retargeter:
2473
+ class_path: ue-mcp.bridge
2474
+ group: animation
2475
+ description: "UE 5.8 only. Configure an existing IK Retargeter through UIKRetargeterController with the correct default-op and per-op rig assignment order, auto/manual chain mappings, named pose authoring, processor validation, native readback, transaction rollback, and checked save; older engines return unsupported_engine_version. Whole-pose auto-align resets that pose first: create a new pose or pass pose.reset=true to acknowledge replacement, then manual offsets are applied. Params: retargeterPath, sourceRig?, targetRig?, sourcePreviewMesh?, targetPreviewMesh?, ensureDefaultOps? (default true), autoMapMode? ('exact'|'fuzzy'|'clear'), forceRemap? (default false), chainMappings?: [{targetChain,sourceChain?:string|null}], pose?: {side,name,create?,reset?,autoAlign?,bones?,rotationOffsets?:[{bone,rotationQuaternion}],rootOffsetZ?,snapBoneToGround?}."
2476
+ options:
2477
+ method: configure_ik_retargeter
2210
2478
  animation.set_ik_rig_mesh:
2211
2479
  class_path: ue-mcp.bridge
2212
2480
  group: animation
@@ -2234,7 +2502,7 @@ tasks:
2234
2502
  animation.batch_retarget_animations:
2235
2503
  class_path: ue-mcp.bridge
2236
2504
  group: animation
2237
- description: "Bake a set of source AnimSequences onto the target skeleton through an IK Retargeter (RunBatchRetarget). Params: retargeterPath, sourceMesh, targetMesh, animPaths[], outputPath? (default: alongside source), prefix?, suffix? (default _Retargeted), overwrite? (#701)"
2505
+ description: "Bake validated source AnimSequences onto the target skeleton through an IK Retargeter (RunBatchRetarget), save every output, and roll back newly created outputs if the batch is incomplete or unsavable. Overwrite is rejected. Returns mapping completeness and every unmapped target chain so partial retargets are explicit; pass requireCompleteMapping=true only when the target should have no intentional extra chains. Params: retargeterPath, sourceMesh, targetMesh, animPaths[], outputPath? (default: alongside source), prefix?, suffix? (default _Retargeted), overwrite? (must be false), requireCompleteMapping? (default false) (#701)"
2238
2506
  options:
2239
2507
  method: batch_retarget_animations
2240
2508
  animation.set_anim_blueprint_skeleton:
@@ -2378,25 +2646,43 @@ tasks:
2378
2646
  animation.get_bone_transform:
2379
2647
  class_path: ue-mcp.bridge
2380
2648
  group: animation
2381
- description: "Read a bone or socket transform on a live actor's SkeletalMeshComponent. Wraps GetBoneTransform / GetSocketTransform. Params: actorLabel, boneName (or socket name), componentName? (default: CharacterMesh0 / Mesh / first SK component), world? (auto|pie|game|editor, default auto), space? (world|component|local, default world). Returns location, rotation, scale (#420)"
2649
+ description: "Read a bone or socket transform on a live actor's SkeletalMeshComponent. Wraps GetBoneTransform / GetSocketTransform. Params: actorLabel OR actorPath, boneName (or socket name), componentName? (default: CharacterMesh0 / Mesh / first SK component), world? (auto|pie|game|editor, default auto), space? (world|component|local, default world). Returns location, rotation, scale (#420)"
2382
2650
  options:
2383
2651
  method: get_bone_transform
2384
2652
  animation.list_bones:
2385
2653
  class_path: ue-mcp.bridge
2386
2654
  group: animation
2387
- description: "List bones in a live actor's SkeletalMeshComponent ref skeleton (name, index, parent). Params: actorLabel, componentName?, world? (auto|pie|game|editor, default auto) (#420)"
2655
+ description: "List bones in a live actor's SkeletalMeshComponent ref skeleton (name, index, parent). Params: actorLabel OR actorPath, componentName?, world? (auto|pie|game|editor, default auto) (#420)"
2388
2656
  options:
2389
2657
  method: list_bones
2390
2658
  animation.rebind_leader_pose:
2391
2659
  class_path: ue-mcp.bridge
2392
2660
  group: animation
2393
- description: "Re-bind every secondary SkeletalMeshComponent on an actor to a body component (default CharacterMesh0 / Mesh). One-call fix for the 'character explodes after rotating the actor' failure mode. Params: actorLabel, bodyComponent? (#419)"
2661
+ description: "Re-bind every secondary SkeletalMeshComponent on an actor to a body component (default CharacterMesh0 / Mesh). One-call fix for the 'character explodes after rotating the actor' failure mode. Params: actorLabel OR actorPath, bodyComponent? (#419)"
2394
2662
  options:
2395
2663
  method: rebind_leader_pose
2664
+ animation.sample_pose:
2665
+ class_path: ue-mcp.bridge
2666
+ group: animation
2667
+ description: "Evaluate an AnimSequence (or a BlendSpace at a blend position) and return COMPOSED bone transforms, which read_bone_track (raw local space) and get_bone_transforms (reference pose only) cannot give. Params: assetPath, boneNames? (omit for every bone), frames? or times? (omit for every sampled key), space? (component default | local | world), skeletalMeshPath? (evaluate with that mesh's proportions), incorporateRootMotion? (default true), blendPosition? {x,y,z} (BlendSpace only). Returns samples:[{frame, time, bones:[{name, location, rotation, scale}]}]. A montage is refused with a pointer to its segments, because a montage has no pose of its own (#923/#926/#922)"
2668
+ options:
2669
+ method: sample_pose
2670
+ animation.get_live_bone_transforms:
2671
+ class_path: ue-mcp.bridge
2672
+ group: animation
2673
+ description: "Read the EVALUATED pose off a live SkeletalMeshComponent in the editor world or PIE, for many bones at once. This is the read that tells 'standing' from 'prone' when the reference pose cannot (#922). Also returns componentTransform and an evaluation block (animationMode, animInstanceClass, componentSpaceTransformCount) so a clean component transform sitting on a dead anim instance is visible in one call. Params: actorLabel OR actorPath, componentName? (default CharacterMesh0 / Mesh), boneNames? (omit for every bone, max 1000), space? (world default | component | local), world? (auto|pie|game|editor) (#922/#926)"
2674
+ options:
2675
+ method: get_live_bone_transforms
2676
+ animation.measure_natural_speed:
2677
+ class_path: ue-mcp.bridge
2678
+ group: animation
2679
+ description: "Measure a locomotion clip's planted-foot speed, in cm/s, by evaluating the pose and tracking the lowest foot's horizontal travel while it is in contact. Every retarget changes natural speed by the target skeleton's leg-length ratio, so a BlendSpace built on retargeted clips has to re-measure per clip per character (#923). Params: assetPath, footBones[] (e.g. ['foot_l','foot_r']), contactThreshold? (contact height in cm; omit to derive it from the clip), skeletalMeshPath?, frames?/times?, blendPosition? (BlendSpace only). Returns naturalSpeed, plantedDistance, plantedTime, contactThreshold, per-foot breakdown"
2680
+ options:
2681
+ method: measure_natural_speed
2396
2682
  animation.preview_animation:
2397
2683
  class_path: ue-mcp.bridge
2398
2684
  group: animation
2399
- description: "Toggle bUpdateAnimationInEditor + VisibilityBasedAnimTickOption=AlwaysTickPoseAndRefreshBones on every SkeletalMeshComponent of an actor. Bypasses the 'cannot be edited on templates' guard for level instances. Params: actorLabel, enabled (#419/#420)"
2685
+ description: "Toggle bUpdateAnimationInEditor + VisibilityBasedAnimTickOption=AlwaysTickPoseAndRefreshBones on every SkeletalMeshComponent of an actor. Bypasses the 'cannot be edited on templates' guard for level instances. Params: actorLabel OR actorPath, enabled (#419/#420)"
2400
2686
  options:
2401
2687
  method: preview_animation
2402
2688
 
@@ -2416,19 +2702,19 @@ tasks:
2416
2702
  landscape.sample:
2417
2703
  class_path: ue-mcp.bridge
2418
2704
  group: landscape
2419
- description: "Sample height/layers. Params: x, y"
2705
+ description: "Read the surface height AND every paint-layer weight at one world XY. Height and weights come from the landscape's own height and weight data (the merged result of every edit layer), the same data landscape(paint_layer) writes, so they are exact and do not depend on built collision. Layers come back with weight (0..1), weight255 (the weightmap byte the editor shows), the LayerInfo path and its physical material, plus dominantLayer and totalWeight - which is what makes reading a paint weight one call instead of rendering the weightmap to a render target and reading that back. Also returns quad, quadExtent and inBounds, so a zero weight OFF the landscape reads as out of bounds rather than as a measured zero, and traceHeight/normal from a confirmation collision trace (absent when collision is unbuilt or the proxy is streamed out). Position accepts x + y, point {x, y}, or worldX + worldY. Params: x + y (or point, or worldX + worldY), actorLabel? OR actorPath? (which landscape, when the map has several), layerName? (one layer only), includeLayers? (default true) (#939)"
2420
2706
  options:
2421
2707
  method: sample_landscape
2422
2708
  landscape.sculpt:
2423
2709
  class_path: ue-mcp.bridge
2424
2710
  group: landscape
2425
- description: "Raise, lower or flatten terrain with a circular brush. mode=raise|lower|flatten; amount is world centimetres at full strength (raise/lower), and flatten pulls toward the height under the brush centre. falloff (0..1) is the smoothstepped soft edge. Runs in one transaction and leaves the level dirty and unsaved. Writes into an edit layer (editLayer by name, else editLayerIndex, default 0) - required on UE 5.8, where a write without one is regenerated away by the layer system. Params: center ({x,y} world space), radius (default 500), mode? (default raise), amount? (default 100), falloff? (default 0.5), actorLabel?, editLayer?, editLayerIndex?, maxVertices? (#742)"
2711
+ description: "Raise, lower or flatten terrain with a circular brush. mode=raise|lower|flatten; amount is world centimetres at full strength (raise/lower), and flatten pulls toward the height under the brush centre. falloff (0..1) is the smoothstepped soft edge. Runs in one transaction and leaves the level dirty and unsaved. Writes into an edit layer (editLayer by name, else editLayerIndex, default 0) - required on UE 5.8, where a write without one is regenerated away by the layer system. Params: center ({x,y} world space), radius (default 500), mode? (default raise), amount? (default 100), falloff? (default 0.5), actorLabel? OR actorPath?, editLayer?, editLayerIndex?, maxVertices? (#742)"
2426
2712
  options:
2427
2713
  method: sculpt_landscape
2428
2714
  landscape.paint_layer:
2429
2715
  class_path: ue-mcp.bridge
2430
2716
  group: landscape
2431
- description: "Paint a weight layer with a circular brush. The layer must already have a LayerInfo on this landscape (see add_layer_info) - an unregistered name errors and lists the layers that ARE registered instead of silently painting nothing. Weights are written as given - the engine no longer renormalises other layers for you, so set them explicitly if they must sum to 1. Writes into an edit layer (editLayer by name, else editLayerIndex, default 0). Params: layerName, center ({x,y} world space), radius (default 500), strength? (0..1, default 1), falloff? (default 0.5), actorLabel?, editLayer?, editLayerIndex?, maxVertices? (#742)"
2717
+ description: "Paint a weight layer with a circular brush. The layer must already have a LayerInfo on this landscape (see add_layer_info) - an unregistered name errors and lists the layers that ARE registered instead of silently painting nothing. Weights are written as given - the engine no longer renormalises other layers for you, so set them explicitly if they must sum to 1. Writes into an edit layer (editLayer by name, else editLayerIndex, default 0). Params: layerName, center ({x,y} world space), radius (default 500), strength? (0..1, default 1), falloff? (default 0.5), actorLabel? OR actorPath?, editLayer?, editLayerIndex?, maxVertices? (#742)"
2432
2718
  options:
2433
2719
  method: paint_landscape_layer
2434
2720
  landscape.list_splines:
@@ -2485,6 +2771,12 @@ tasks:
2485
2771
  description: "Resolve which loaded LandscapeStreamingProxy covers a world X/Y. Returns found/loaded + label, or loaded:false when the covering proxy is streamed out (so a 0-weight readback there is ambiguous, not real). Params: worldX, worldY (#733)"
2486
2772
  options:
2487
2773
  method: find_landscape_proxy_at
2774
+ landscape.refresh_physical_material_collision:
2775
+ class_path: ue-mcp.bridge
2776
+ group: landscape
2777
+ description: "UE 5.8+: safely refresh physical-material collision data in memory on loaded World Partition LandscapeStreamingProxy actors after a LayerInfo PhysMaterial change. Requires complete registered collision coverage and no pending landscape edit-layer work. Preserves and verifies every raw, complex-live, and simple-live height sample, builds material data before one collision recreation, and fails the whole matched batch on any unsafe result. Filters combine: actorLabels[], guids[], and bounds {min,max}; omitting them targets every loaded proxy up to maxActors (default 256, hard max 1024). Unloaded proxies are untouched; pin them first with level(load_actor_descs). Refuses PIE/SIE and non-World-Partition maps. Persistence is deliberately unsupported because Landscape PreSave can mutate edit-layer collision data; this action never saves packages. Returns loaded/matched/refreshed/failed counts and exact affected package paths."
2778
+ options:
2779
+ method: refresh_landscape_physical_material_collision
2488
2780
 
2489
2781
  # ── pcg ──
2490
2782
  pcg.list_graphs:
@@ -2514,7 +2806,7 @@ tasks:
2514
2806
  pcg.get_component_details:
2515
2807
  class_path: ue-mcp.bridge
2516
2808
  group: pcg
2517
- description: "Inspect PCG component. Params: actorLabel"
2809
+ description: "Inspect PCG component. Params: actorLabel OR actorPath (#983)"
2518
2810
  options:
2519
2811
  method: get_pcg_component_details
2520
2812
  pcg.create_graph:
@@ -2562,25 +2854,25 @@ tasks:
2562
2854
  pcg.execute:
2563
2855
  class_path: ue-mcp.bridge
2564
2856
  group: pcg
2565
- description: "Regenerate PCG. Params: actorLabel"
2857
+ description: "Regenerate PCG. Params: actorLabel OR actorPath (#983)"
2566
2858
  options:
2567
2859
  method: execute_pcg_graph
2568
2860
  pcg.force_regenerate:
2569
2861
  class_path: ue-mcp.bridge
2570
2862
  group: pcg
2571
- description: "Force a stuck PCG component to regenerate (clears graph ref, re-sets, cleanup+generate). Params: actorLabel (#146)"
2863
+ description: "Force a stuck PCG component to regenerate (clears graph ref, re-sets, cleanup+generate). Params: actorLabel OR actorPath (#146/#983)"
2572
2864
  options:
2573
2865
  method: force_regenerate_pcg
2574
2866
  pcg.cleanup:
2575
2867
  class_path: ue-mcp.bridge
2576
2868
  group: pcg
2577
- description: "Cleanup a PCG component (remove spawned content). Params: actorLabel, removeComponents? (default true) (#146)"
2869
+ description: "Cleanup a PCG component (remove spawned content). Params: actorLabel OR actorPath, removeComponents? (default true) (#146)"
2578
2870
  options:
2579
2871
  method: cleanup_pcg
2580
2872
  pcg.toggle_graph:
2581
2873
  class_path: ue-mcp.bridge
2582
2874
  group: pcg
2583
- description: "Toggle a PCG component's graph assignment to force reinit (no generate). Params: actorLabel, graphPath? (#146)"
2875
+ description: "Toggle a PCG component's graph assignment to force reinit (no generate). Params: actorLabel OR actorPath, graphPath? (#146)"
2584
2876
  options:
2585
2877
  method: toggle_pcg_graph
2586
2878
  pcg.add_volume:
@@ -2630,9 +2922,15 @@ tasks:
2630
2922
  foliage.set_settings:
2631
2923
  class_path: ue-mcp.bridge
2632
2924
  group: foliage
2633
- description: "Modify type settings. Params: foliageTypeName, settings"
2925
+ description: "Modify ONE foliage type's settings. For the same edit across every type matching a condition, use batch_set_settings_where instead of calling this in a loop. Params: foliageTypeName OR foliageTypePath, settings"
2634
2926
  options:
2635
2927
  method: set_foliage_type_settings
2928
+ foliage.batch_set_settings_where:
2929
+ class_path: ue-mcp.bridge
2930
+ group: foliage
2931
+ description: "Write settings to every FoliageType whose CURRENT property values match a predicate, with the predicate evaluated in the editor. set_settings is one asset per call and cannot express a condition at all, so 'include_in_hlod=false on every type whose cull distance is set' meant reading 201 assets out, computing the 36 matches client-side, and writing them back one at a time. Candidates come from foliageTypePaths[] (explicit), directory (scan FoliageType assets) or fromLevel=true (types placed in the open level). Predicate fields read the asset's own properties by dotted path, so CullDistance.Max works and a bare name is treated the same as props.<name>; operators are the same vocabulary as level(query_components). dryRun DEFAULTS TO TRUE because this writes to many assets at once, and the preview still resolves every setting path so an unwritable property is reported before the commit. Written values are read back rather than echoed, so a value the property coerced is visible. Params: settings (object of propertyName -> value, dotted paths supported), where ([{field, op, value}], required), whereMode? (all|any), one of foliageTypePaths[]/directory (+ recursive?)/fromLevel, propertyNames? (extra properties to report without filtering on them), dryRun? (default TRUE), save? (default true), maxTypes? (#988)"
2932
+ options:
2933
+ method: batch_set_foliage_settings_where
2636
2934
 
2637
2935
  # ── niagara ──
2638
2936
  niagara.list:
@@ -2668,13 +2966,13 @@ tasks:
2668
2966
  niagara.reactivate:
2669
2967
  class_path: ue-mcp.bridge
2670
2968
  group: niagara
2671
- description: "Reset + reactivate the NiagaraComponent on a placed actor (replay a burst before capturing). Params: actorLabel (#537)"
2969
+ description: "Reset + reactivate the NiagaraComponent on a placed actor (replay a burst before capturing). Params: actorLabel OR actorPath (#537/#983)"
2672
2970
  options:
2673
2971
  method: reactivate_niagara
2674
2972
  niagara.set_parameter:
2675
2973
  class_path: ue-mcp.bridge
2676
2974
  group: niagara
2677
- description: "Set parameter. Params: actorLabel, parameterName, value, parameterType?"
2975
+ description: "Set parameter. Params: actorLabel OR actorPath, parameterName, value, parameterType?"
2678
2976
  options:
2679
2977
  method: set_niagara_parameter
2680
2978
  niagara.create:
@@ -3218,11 +3516,11 @@ tasks:
3218
3516
  editor.start_editor:
3219
3517
  class_path: editor.start_editor
3220
3518
  group: editor
3221
- description: "Launch Unreal Editor and BLOCK until it is fully ready (not merely until the socket answers), rendering a startup progress bar in the terminal. Returns the phase timeline it waited through. Do NOT poll get_engine_state or get_status afterwards: this call already waited, and a ready editor is the only way it returns success. Params: timeout? (seconds, default 300)"
3519
+ description: "Launch Unreal Editor and BLOCK until it is fully ready (not merely until the socket answers), rendering a startup progress bar in the terminal. Returns the phase timeline it waited through. Do NOT poll get_engine_state or get_status afterwards: this call already waited, and a ready editor is the only way it returns success. dialogPolicy answers startup prompts before they can wedge the game thread, which is how the post-crash \"Restore Packages\" modal used to stall a launch (#968). Params: timeout? (seconds, default 300), dialogPolicy? (\"pattern=response;pattern=response\", responses as set_dialog_policy takes them)"
3222
3520
  editor.get_engine_state:
3223
3521
  class_path: editor.get_engine_state
3224
3522
  group: editor
3225
- description: "What the engine is REALLY doing, read from outside the game thread: startup phase from the editor's own log, process table (PID, command line, responding), the plugin's status snapshot (slow-task name and percent, active modal dialog, game-thread stall), and native dialog windows. Call this ONCE when something is already wrong (handlers timing out, an editor that will not come up). Never call it in a wait loop: start_editor blocks until ready on its own, and polling this during startup burns tokens re-reading state that is already tracked. Params: probeWindows? (default true; scans native windows, costs ~2s)"
3523
+ description: "What the engine is REALLY doing, read from outside the game thread: startup phase from the editor's own log, every process holding this project's .uproject open (PID, command line, responding), the plugin's status snapshot (slow-task name and percent, active modal dialog, game-thread stall), and native dialog windows. `running` follows the strongest evidence: an editor that answered over the bridge is running whatever the process table saw, and a probe that could not run is reported as processProbeFailed rather than as an absent editor (#965). Call this ONCE when something is already wrong (handlers timing out, an editor that will not come up). Never call it in a wait loop: start_editor blocks until ready on its own, and polling this during startup burns tokens re-reading state that is already tracked. Params: probeWindows? (default true; scans native windows, costs ~2s)"
3226
3524
  editor.stop_editor:
3227
3525
  class_path: editor.stop_editor
3228
3526
  group: editor
@@ -3244,7 +3542,7 @@ tasks:
3244
3542
  editor.execute_python:
3245
3543
  class_path: editor.execute_python
3246
3544
  group: editor
3247
- description: "GATED LAST RESORT. execute_python is unreachable until a semantic tool search over your taskSummary has been run AND every candidate it returns is EXPLICITLY ruled out with a stated reason. Flow: (1) call with taskSummary (+code) - it returns the candidate actions; (2) re-call with the same taskSummary/code PLUS ruledOut=[{action, reason}] giving a specific reason each candidate does not fit. Python runs only once every candidate is ruled out. Params: code, taskSummary (required), ruledOut?, resultVariable? (name of a top-level variable to return as `result`, separate from print()/log; #732) (#704)"
3545
+ description: "GATED LAST RESORT. execute_python is unreachable until a semantic tool search over your taskSummary has been run AND every candidate it returns is EXPLICITLY ruled out with a stated reason. Flow: (1) call with taskSummary (+code) - it returns the candidate actions AND the exact ruledOut array to send back; (2) re-call with the same taskSummary/code PLUS that ruledOut=[{action, reason}], each reason at least 12 characters saying why that candidate does not fit. The action field accepts the bare name, tool(action) or tool.action, and rulings are remembered for the session so rewording the taskSummary never asks you to justify the same action twice. Python runs only once every candidate is ruled out. Params: code, taskSummary (required), ruledOut?, resultVariable? (name of a top-level variable to return as `result`, separate from print()/log; #732) (#704, #938, #960)"
3248
3546
  editor.run_python_file:
3249
3547
  class_path: ue-mcp.bridge
3250
3548
  group: editor
@@ -3306,7 +3604,7 @@ tasks:
3306
3604
  editor.get_runtime_value:
3307
3605
  class_path: ue-mcp.bridge
3308
3606
  group: editor
3309
- description: "Read PIE actor property. Params: actorLabel, propertyName (supports dotted paths: component.field or component.struct.field for nested reads on component subobjects, #344/#381)"
3607
+ description: "Read PIE actor property. Params: actorLabel OR actorPath, propertyName (supports dotted paths: component.field or component.struct.field for nested reads on component subobjects, #344/#381)"
3310
3608
  options:
3311
3609
  method: get_runtime_value
3312
3610
  editor.get_pie_pawn:
@@ -3324,7 +3622,7 @@ tasks:
3324
3622
  editor.invoke_object_function:
3325
3623
  class_path: ue-mcp.bridge
3326
3624
  group: editor
3327
- description: "Call a UFUNCTION on any UObject, not just a placed actor. Target it with objectPath, or target=gameinstance|gamemode|gamestate|playercontroller|playerpawn|subsystem (subsystem also needs subsystemClass; playercontroller/playerpawn accept playerIndex). The GameInstance, GameMode and subsystems have no actor label, so invoke_function could never reach them. Returns output and return params under returnValues; an unknown function name lists the available ones. Params: functionName, objectPath? | target?, subsystemClass?, playerIndex?, args?, world? (editor|pie|auto), pieInstance? (#739)"
3625
+ description: "Call a UFUNCTION on any UObject, not just a placed actor. Target it with objectPath, or target=gameinstance|gamemode|gamestate|playercontroller|playerpawn|subsystem (subsystem also needs subsystemClass; playercontroller/playerpawn accept playerIndex). The GameInstance, GameMode and subsystems have no actor label, so invoke_function could never reach them. Returns output and return params under returnValues, with a TArray/TSet/TMap return as real JSON and everything else as export text (#885); an unknown function name lists the available ones. A scripted call runs under the editor script-execution guard, which forces every actor callspace to Local, so a UFUNCTION(Server) executes locally instead of being sent; the result warns when that happened, and deferToNextTick=true queues the call for the next engine tick where it routes normally, at the cost of returning before it runs (#973). Params: functionName, objectPath? | target?, subsystemClass?, playerIndex?, args?, world? (editor|pie|auto), pieInstance?, deferToNextTick? (#739)"
3328
3626
  options:
3329
3627
  method: invoke_object_function
3330
3628
  editor.invoke_object_functions:
@@ -3336,7 +3634,7 @@ tasks:
3336
3634
  editor.read_bone_transforms:
3337
3635
  class_path: ue-mcp.bridge
3338
3636
  group: editor
3339
- description: "Read live skeletal bone and socket transforms off an actor, once. This is a point-in-time read, NOT a time series - for per-frame capture over a window use the pie category's observe actions. Pass bones (bone OR socket names) or omit for every bone up to limit. space=world (default) or component; component space is independent of where the actor is standing. Pass relativeTo (bone OR socket name) to express every sample in that live reference frame; relativeTo supersedes space and is calculated in component space. Also reports the AnimInstance class/path. Params: actorLabel, componentName?, bones?, relativeTo?, space?, limit?, world? (editor|pie|auto), pieInstance? (#756/#757/#761/#764)"
3637
+ description: "Read live skeletal bone and socket transforms off an actor, once. This is a point-in-time read, NOT a time series - for per-frame capture over a window use the pie category's observe actions. Pass bones (bone OR socket names) or omit for every bone up to limit. space=world (default) or component; component space is independent of where the actor is standing. Pass relativeTo (bone OR socket name) to express every sample in that live reference frame; relativeTo supersedes space and is calculated in component space. Also reports the AnimInstance class/path. Params: actorLabel OR actorPath, componentName?, bones?, relativeTo?, space?, limit?, world? (editor|pie|auto), pieInstance? (#756/#757/#761/#764)"
3340
3638
  options:
3341
3639
  method: read_bone_transforms
3342
3640
  editor.get_object_properties:
@@ -3348,7 +3646,7 @@ tasks:
3348
3646
  editor.set_movement_mode:
3349
3647
  class_path: ue-mcp.bridge
3350
3648
  group: editor
3351
- description: "Set a live PIE character's movement mode and/or velocity on its CharacterMovementComponent. Modes are named (none|walking|navwalking|falling|swimming|flying|custom) rather than raw enum numbers, because a wrong number reads as success and then behaves as None. Reports previousMode/previousVelocity and reads the mode back afterwards, since SetMovementMode can refuse a mode the character cannot enter (flying with bCanFly off, swimming outside a volume). Params: actorLabel, mode?, customMode? (only with mode='custom'), velocity? {x,y,z}, world? (default pie), pieInstance? (#757)"
3649
+ description: "Set a live PIE character's movement mode and/or velocity on its CharacterMovementComponent. Modes are named (none|walking|navwalking|falling|swimming|flying|custom) rather than raw enum numbers, because a wrong number reads as success and then behaves as None. Reports previousMode/previousVelocity and reads the mode back afterwards, since SetMovementMode can refuse a mode the character cannot enter (flying with bCanFly off, swimming outside a volume). Params: actorLabel OR actorPath, mode?, customMode? (only with mode='custom'), velocity? {x,y,z}, world? (default pie), pieInstance? (#757)"
3352
3650
  options:
3353
3651
  method: set_movement_mode
3354
3652
  editor.set_object_property:
@@ -3366,19 +3664,19 @@ tasks:
3366
3664
  editor.teleport_runtime_actor:
3367
3665
  class_path: ue-mcp.bridge
3368
3666
  group: editor
3369
- description: "Move a live PIE actor and have it STAY moved. A plain SetActorLocation on a Character is undone by CharacterMovement on the next tick, so this stops the movement component, teleports, and stops it again. Reports actualLocation read back from the actor rather than what was requested. Params: actorLabel, location?, rotation?, stopMovement? (default true), sweep? (default false), world? (default pie), pieInstance? (#770/#777)"
3667
+ description: "Move a live PIE actor and have it STAY moved. A plain SetActorLocation on a Character is undone by CharacterMovement on the next tick, so this stops the movement component, teleports, and stops it again. Reports actualLocation read back from the actor rather than what was requested. Params: actorLabel OR actorPath, location?, rotation?, stopMovement? (default true), sweep? (default false), world? (default pie), pieInstance? (#770/#777)"
3370
3668
  options:
3371
3669
  method: teleport_runtime_actor
3372
3670
  editor.invoke_static_function:
3373
3671
  class_path: ue-mcp.bridge
3374
3672
  group: editor
3375
- description: "Call a static UFUNCTION on a UBlueprintFunctionLibrary (no actor instance). invoke_function needs an actor/component target; this targets the library class CDO instead, so it reaches static *_BlueprintOnly libraries (Voxel sculpt/query/stamp), GeometryScript, Kismet math, any function library. Params: className (short name or /Script/Module.Class path), functionName, args? (name -> JSON value, same marshalling as invoke_function), actorArgs? (name -> actor label for UObject* params that are actors, e.g. the sculpt actor), worldContextParam? (name of a UObject* param to fill with the editor/PIE world; auto-detected for params named WorldContextObject), world? (editor|pie). Returns return/out params under returnValues. Discover libraries + functions with list_function_libraries."
3673
+ description: "Call a static UFUNCTION on a UBlueprintFunctionLibrary (no actor instance). invoke_function needs an actor/component target; this targets the library class CDO instead, so it reaches static *_BlueprintOnly libraries (Voxel sculpt/query/stamp), GeometryScript, Kismet math, any function library. Params: className (short name or /Script/Module.Class path), functionName, args? (name -> JSON value, same marshalling as invoke_function), actorArgs? (name -> actor label for UObject* params that are actors, e.g. the sculpt actor), worldContextParam? (name of a UObject* param to fill with the selected world; auto-detected from the function's own WorldContext metadata and for params named WorldContextObject), world? (editor|pie|game|auto, default editor), pieInstance? (which PIE world; see list_pie_instances). world/pieInstance pick WHICH world fills the context param, so a static that looks a GameInstance subsystem up off its context can be exercised against a live PIE session (#971); the result names the world it ran against and the parameter that carried it. Returns return/out params under returnValues, with a TArray/TSet/TMap return as real JSON and everything else as export text (#885). Discover libraries + functions with list_function_libraries."
3376
3674
  options:
3377
3675
  method: invoke_static_function
3378
3676
  editor.invoke_function:
3379
3677
  class_path: ue-mcp.bridge
3380
3678
  group: editor
3381
- description: "Call a BlueprintCallable / Exec UFUNCTION on a target actor or one of its components. world=editor (the default) runs the function on the actor placed in the level, no PIE session needed, and reports which instance ran it as resolvedActorLabel/resolvedActorPath. actorLabel is matched against placed actors by editor label first, then internal object name, then full object path; a miss is an error naming what was searched (#806). Params: actorLabel, functionName, component? (component subobject name; redirects target from the actor to that component, #382), args? (object; struct values accept a JSON object such as {X,Y,Z} as well as an export-text string), actorArgs? (object mapping UObject* parameter name to actor label, resolved against live actors in the active world; #383), world? (editor|pie). Returns out/return params (#228/#229)"
3679
+ description: "Call a BlueprintCallable / Exec UFUNCTION on a target actor or one of its components. world=editor (the default) runs the function on the actor placed in the level, no PIE session needed, and reports which instance ran it as resolvedActorLabel/resolvedActorPath. actorLabel is matched against placed actors by editor label first, then internal object name, then full object path; a miss is an error naming what was searched (#806). Returns out/return params under returnValues; a TArray/TSet/TMap return comes back as real JSON and everything else as export text (#885). A scripted call runs under the editor script-execution guard, which forces every actor callspace to Local, so a UFUNCTION(Server) executes locally instead of being sent; the result warns when that happened, and deferToNextTick=true queues the call for the next engine tick where it routes normally, at the cost of returning before it runs (#973). Params: actorLabel OR actorPath, functionName, component? (component subobject name; redirects target from the actor to that component, #382), args? (object; struct values accept a JSON object such as {X,Y,Z} as well as an export-text string), actorArgs? (object mapping UObject* parameter name to actor label, resolved against live actors in the active world; #383), world? (editor|pie), deferToNextTick? (#228/#229)"
3382
3680
  options:
3383
3681
  method: invoke_function
3384
3682
  editor.list_function_libraries:
@@ -3438,13 +3736,13 @@ tasks:
3438
3736
  editor.capture_screenshot:
3439
3737
  class_path: ue-mcp.bridge
3440
3738
  group: editor
3441
- description: "Screenshot. target=pie synchronously captures the selected PIE client game viewport with UMG/Slate UI; target=editor captures the level viewport; target=window synchronously captures a whole Slate window via FSlateApplication::TakeScreenshot - pixel-true for ALL Slate/UMG UI, returns after the PNG is written, and works while the window is unfocused or off-screen. Multi-instance PIE automatically prefers a world with a game viewport; pass pieInstance or worldPath to select explicitly, which for target=window is what picks the PIE client window instead of the active editor window. Every mode captures at the source viewport/window size - use capture_scene_png for a chosen output size. Params: filename?, target? (auto|pie|editor|window), pieInstance?, worldPath?. Returns the resolved PIE instance/world and image dimensions (#226/#724)."
3739
+ description: "Screenshot. target=pie synchronously captures the selected PIE client game viewport with UMG/Slate UI; target=editor captures the level viewport; target=window synchronously captures a whole Slate window via FSlateApplication::TakeScreenshot - pixel-true for ALL Slate/UMG UI, returns after the PNG is written, and works while the window is unfocused or off-screen. Multi-instance PIE automatically prefers a world with a game viewport; pass pieInstance or worldPath to select explicitly, which for target=window is what picks the PIE client window instead of the active editor window. Every mode captures at the source viewport/window size - use capture_scene_png for a chosen output size. Params: filename? (outputPath is accepted for it too, so the two capture actions take the same name; #966), target? (auto|pie|editor|window), pieInstance?, worldPath?. Returns the resolved PIE instance/world and image dimensions (#226/#724)."
3442
3740
  options:
3443
3741
  method: capture_screenshot
3444
3742
  editor.capture_scene_png:
3445
3743
  class_path: ue-mcp.bridge
3446
3744
  group: editor
3447
- description: "Headless PNG screenshot via SceneCapture2D (works unfocused, guaranteed RGBA8 LDR). focusActorLabel auto-frames the camera on an actor's bounds; world:pie captures the running game world (#599). Params: outputPath, location?, rotation?, focusActorLabel?, focusDirection?, focusMargin?, world? (editor|pie), width? (default 1280), height? (default 720), fov? (default 90) (#148/#599)"
3745
+ description: "Headless PNG screenshot via SceneCapture2D (works unfocused, guaranteed RGBA8 LDR). focusActorLabel auto-frames the camera on an actor's bounds; world:pie captures the running game world (#599). The capture actor is transient and destroyed before the call returns, and any left by an earlier build is swept, so a capture leaves the level exactly as it found it (#966). Params: outputPath (filename is accepted for it too), location?, rotation?, focusActorLabel? OR focusActorPath, focusDirection?, focusMargin?, world? (editor|pie), width? (default 1280), height? (default 720), fov? (default 90) (#148/#599)"
3448
3746
  options:
3449
3747
  method: capture_scene_png
3450
3748
  editor.set_realtime:
@@ -3468,7 +3766,7 @@ tasks:
3468
3766
  editor.get_runtime_values:
3469
3767
  class_path: ue-mcp.bridge
3470
3768
  group: editor
3471
- description: "Bulk runtime read across the active world. For each actor/component matching classFilter, resolves every path against the (actor|component) root and returns rows of {actorLabel, actorClass, componentName?, componentClass?, values, errors?}. Paths support property hops, sub-object hops, and zero-arg BlueprintCallable getter calls at any segment (e.g. 'PowerConnector.GetRequired' reaches a UFUNCTION on a UObject sub-object). classFilter matches actor class OR component class - omit to match everything. World defaults to PIE if running, else editor. Params: classFilter?, paths[], world? (editor|pie) (#414)"
3769
+ description: "Bulk runtime read across the active world. For each actor/component matching classFilter, resolves every path against the (actor|component) root and returns rows of {actorLabel, actorClass, componentName?, componentClass?, values, errors?}. Paths support property hops, sub-object hops, and BlueprintCallable getter calls at any segment (e.g. 'PowerConnector.GetRequired' reaches a UFUNCTION on a UObject sub-object). A getter that takes arguments is written with them inline, 'GetMirroredTallyWeight(overclock)' or 'GetBalance(gold, 2)', which is what makes a keyed accessor readable across every matched instance in one call; the literals are coerced by the same rules invoke_object_function's args use, so FName/FString/int/float/bool/enum all read (#969). classFilter matches actor class OR component class - omit to match everything. A path whose result is a TArray/TSet/TMap comes back as real JSON rather than one string (#885). World defaults to PIE if running, else editor. Params: classFilter?, paths[], world? (editor|pie) (#414)"
3472
3770
  options:
3473
3771
  method: get_runtime_values
3474
3772
  editor.set_viewport:
@@ -3480,7 +3778,7 @@ tasks:
3480
3778
  editor.focus_on_actor:
3481
3779
  class_path: ue-mcp.bridge
3482
3780
  group: editor
3483
- description: "Focus on actor. Params: actorLabel"
3781
+ description: "Focus on actor. Params: actorLabel OR actorPath (#983)"
3484
3782
  options:
3485
3783
  method: focus_viewport_on_actor
3486
3784
  editor.create_sequence:
@@ -3492,25 +3790,25 @@ tasks:
3492
3790
  editor.get_sequence_info:
3493
3791
  class_path: ue-mcp.bridge
3494
3792
  group: editor
3495
- description: "Read sequence: bindings (possessable/spawnable) with their Sequencer tags (#556), tracks, and optional section detail. Params: assetPath, includeSectionDetails? (attach sockets, first transform key values per track)"
3793
+ description: "Read sequence: bindings (possessable/spawnable) with their Sequencer tags (#556), tracks, and optional section detail. UNITS: playbackRange is reported in TICKS (tick resolution, commonly 24000/s), while MovieSceneScripting*Channel.add_key defaults its time_unit to DISPLAY_RATE. Keys authored with a tick number under the default unit land roughly 800x past the range and the track evaluates to its first key, which presents as transforms that do not work on a structurally perfect sequence (#881). Params: assetPath, includeSectionDetails? (attach sockets, first transform key values per track)"
3496
3794
  options:
3497
3795
  method: get_sequence_info
3498
3796
  editor.add_sequence_track:
3499
3797
  class_path: ue-mcp.bridge
3500
3798
  group: editor
3501
- description: "Add an empty track. Params: assetPath, trackType, actorLabel?"
3799
+ description: "Add an empty track. Params: assetPath, trackType, actorLabel? OR actorPath? (#983)"
3502
3800
  options:
3503
3801
  method: add_sequence_track
3504
3802
  editor.add_sequence_section:
3505
3803
  class_path: ue-mcp.bridge
3506
3804
  group: editor
3507
- description: "Add a section to a track (creating the track if needed), set its start/end in seconds, and for a CameraCut track bind it to a camera. Returns the section index + channel names to key. Params: sequencePath, trackType (Transform|Float|Fade|CameraCut|Audio|Event|SkeletalAnimation), actorLabel? (binding scope), startSeconds?, endSeconds?, cameraActorLabel? (#548)"
3805
+ description: "Add a section to a track (creating the track if needed), set its start/end in seconds, and for a CameraCut track bind it to a camera. Returns the section index + channel names to key. Params: sequencePath, trackType (Transform|Float|Fade|CameraCut|Audio|Event|SkeletalAnimation), actorLabel? OR actorPath? (binding scope), startSeconds?, endSeconds?, cameraActorLabel? OR cameraActorPath? (#548/#983)"
3508
3806
  options:
3509
3807
  method: add_sequence_section
3510
3808
  editor.set_sequence_keyframes:
3511
3809
  class_path: ue-mcp.bridge
3512
3810
  group: editor
3513
- description: "Add keyframes to a section channel. Transform channels: Location.X/Y/Z, Rotation.X/Y/Z (or friendly x/y/z, yaw/pitch/roll); Fade/Float: the float channel. Params: sequencePath, trackType, actorLabel?, sectionIndex? (default 0), channel, keyframes ([{seconds, value}]), interpolation? (cubic|linear) (#548)"
3811
+ description: "Add keyframes to a section channel. Transform channels: Location.X/Y/Z, Rotation.X/Y/Z (or friendly x/y/z, yaw/pitch/roll); Fade/Float: the float channel. Params: sequencePath, trackType, actorLabel? OR actorPath?, sectionIndex? (default 0), channel, keyframes ([{seconds, value}]), interpolation? (cubic|linear) (#548)"
3514
3812
  options:
3515
3813
  method: set_sequence_keyframes
3516
3814
  editor.set_sequence_playback_range:
@@ -3525,6 +3823,12 @@ tasks:
3525
3823
  description: "Play/stop/pause a Level Sequence in Sequencer. Pass sequencePath (or assetPath) to target a specific sequence - it is opened first, because the underlying Sequencer commands act on whatever is currently open. Omit it and the call applies to the open sequence and says so. Params: sequencePath? (or assetPath), sequenceAction? (play|pause|stop, default play)"
3526
3824
  options:
3527
3825
  method: play_sequence
3826
+ editor.scrub_sequence:
3827
+ class_path: ue-mcp.bridge
3828
+ group: editor
3829
+ description: "Park the Sequencer playhead on an exact time and evaluate there, then return. This is what makes scrub-then-capture_scene_png deterministic: play_sequence only offers play/pause/stop and realtime playback races the capture. Pauses first, scrubs, and forces the evaluation before answering, because the playhead move alone does not write possessed-actor transforms. Pass exactly one of seconds or frame. frame is read in timeUnit: display (default, the frame numbers Sequencer shows) or tick (the units get_sequence_info's playbackRange reports). Returns the evaluated time in all three units plus displayRate/tickResolution/playbackRange, and warns when the time is outside the playback range. Params: sequencePath? (or assetPath), seconds? | frame?, timeUnit? (#881)"
3830
+ options:
3831
+ method: scrub_sequence
3528
3832
  editor.build_all:
3529
3833
  class_path: ue-mcp.bridge
3530
3834
  group: editor
@@ -3672,7 +3976,7 @@ tasks:
3672
3976
  editor.run_automation_tests:
3673
3977
  class_path: ue-mcp.bridge
3674
3978
  group: editor
3675
- description: "Run registered Automation tests matching a filter and return per-test pass/fail plus error lines. Runs them synchronously through the test framework rather than the console queue, and suspends the editor's unfocused-CPU throttle for the duration - otherwise an unfocused editor drops to a few FPS and the framework's interactive-frame-rate gate never opens, leaving tests queued forever (#765). Params: filter?, maxTests? (default 50) (#693)"
3979
+ description: "Run registered Automation tests matching a filter and return per-test pass/fail plus error lines. Runs them synchronously through the test framework rather than the console queue, and suspends the editor's unfocused-CPU throttle for the duration - otherwise an unfocused editor drops to a few FPS and the framework's interactive-frame-rate gate never opens, leaving tests queued forever (#765). A test whose latent commands are still queued when latentTimeoutSeconds runs out is reported as abandoned, with the reason: latent work needs engine frames, and this runs on the game thread, so a test that starts PIE (CQTest multi-client network tests, for instance) belongs in the editor's Automation window or -ExecCmds=\"Automation RunTests <name>\" at launch. Such a test used to terminate the editor outright (#993). Params: filter?, maxTests? (default 50), latentTimeoutSeconds? (default 5, max 120) (#693)"
3676
3980
  options:
3677
3981
  method: run_automation_tests
3678
3982
  editor.list_dirty_packages:
@@ -3681,12 +3985,16 @@ tasks:
3681
3985
  description: "Enumerate currently-dirty content + map packages, read from the editor's own dirty-package lists (the same ones Save All uses). Includes a never-saved /Temp world, because an unsaved new map is exactly the unsaved work a caller needs to see before closing or reloading (#340)"
3682
3986
  options:
3683
3987
  method: list_dirty_packages
3684
- editor.request_editor_shutdown:
3988
+ editor.get_world_state:
3685
3989
  class_path: ue-mcp.bridge
3686
3990
  group: editor
3687
- description: "Ask the editor to close itself from inside the engine, after it has checked that closing is safe. Refuses by default when any content or map package is dirty (including an unsaved /Temp world) and reports which ones, so nothing is lost to a silent discard. Ends an active PIE/SIE session first and closes only once play has actually stopped. The response is returned before the process exits. Use editor(stop_editor) for the full stop-and-confirm flow; this action is the in-engine half of it. Params: requireClean? (default true), endPIE? (default true)"
3991
+ description: "One atomic read of which world is open and what is unsaved. Returns editorWorldName, editorWorldPackage, persistentLevelPackage, worldPackageDirty, a sorted dirtyPackages list with counts, and the editor/play/simulate mode. level(get_current) plus editor(list_dirty_packages) is two calls, so the editor can change between them and neither result proves which world the other described; this answers both in one game-thread dispatch. Read-only, and fails closed rather than reporting an empty world as a clean one (#920/#921)"
3688
3992
  options:
3689
- method: request_editor_shutdown
3993
+ method: get_world_state
3994
+ editor.request_editor_shutdown:
3995
+ class_path: editor.request_editor_shutdown
3996
+ group: editor
3997
+ description: "Ask the editor to close itself from inside the engine, after it has checked that closing is safe. Refuses by default when any content or map package is dirty (including an unsaved /Temp world) and reports which ones, so nothing is lost to a silent discard. Ends an active PIE/SIE session first and closes only once play has actually stopped. The response is returned before the process exits. Aimed at the same editor stop_editor aims at, through the same ownership check, so the two can never disagree about which editor belongs to the loaded project (#967). Use editor(stop_editor) for the full stop-and-confirm flow; this action is the in-engine half of it. Params: requireClean? (default true), endPIE? (default true)"
3690
3998
 
3691
3999
  # ── reflection ──
3692
4000
  reflection.reflect_class:
@@ -3766,37 +4074,37 @@ tasks:
3766
4074
  gameplay.set_collision_profile:
3767
4075
  class_path: ue-mcp.bridge
3768
4076
  group: gameplay
3769
- description: "Set collision preset. Params: actorLabel, profileName"
4077
+ description: "Set collision preset. Params: actorLabel OR actorPath, profileName"
3770
4078
  options:
3771
4079
  method: set_collision_profile
3772
4080
  gameplay.set_simulate_physics:
3773
4081
  class_path: ue-mcp.bridge
3774
4082
  group: gameplay
3775
- description: "Toggle physics. Params: actorLabel, simulate"
4083
+ description: "Toggle physics. Params: actorLabel OR actorPath, simulate"
3776
4084
  options:
3777
4085
  method: set_simulate_physics
3778
4086
  gameplay.add_impulse:
3779
4087
  class_path: ue-mcp.bridge
3780
4088
  group: gameplay
3781
- description: "Apply an impulse (or force with mode='force') to a (PIE) actor's simulating physics body so its motion can be observed over time - loop level(read_actor_motion) to sample the response. Params: actorLabel, impulse {x,y,z} (or force/vector), mode? (impulse|force), componentName?, boneName?, location? (apply at world point), velChange?/accelChange?, world? (editor|pie|auto) (#676)"
4089
+ description: "Apply an impulse (or force with mode='force') to a (PIE) actor's simulating physics body so its motion can be observed over time - loop level(read_actor_motion) to sample the response. Params: actorLabel OR actorPath, impulse {x,y,z} (or force/vector), mode? (impulse|force), componentName?, boneName?, location? (apply at world point), velChange?/accelChange?, world? (editor|pie|auto) (#676)"
3782
4090
  options:
3783
4091
  method: add_impulse
3784
4092
  gameplay.set_collision_enabled:
3785
4093
  class_path: ue-mcp.bridge
3786
4094
  group: gameplay
3787
- description: "Set collision mode. Params: actorLabel, collisionEnabled"
4095
+ description: "Set collision mode. Params: actorLabel OR actorPath, collisionEnabled"
3788
4096
  options:
3789
4097
  method: set_collision_enabled
3790
4098
  gameplay.set_collision:
3791
4099
  class_path: ue-mcp.bridge
3792
4100
  group: gameplay
3793
- description: "Unified collision authoring for a placed actor (actorLabel) or a Blueprint component template (assetPath+componentName). Apply any of: collisionProfile, collisionEnabled (NoCollision|QueryOnly|PhysicsOnly|QueryAndPhysics), objectType (channel name), responseToAllChannels (Block|Overlap|Ignore), responses ({channel: Block|Overlap|Ignore}). Profile is applied first, then overrides. componentName optional for actors (defaults to all primitive components), required for Blueprint templates (#545)"
4101
+ description: "Unified collision authoring for a placed actor (actorLabel or actorPath) or a Blueprint component template (assetPath+componentName). Apply any of: collisionProfile, collisionEnabled (NoCollision|QueryOnly|PhysicsOnly|QueryAndPhysics), objectType (channel name), responseToAllChannels (Block|Overlap|Ignore), responses ({channel: Block|Overlap|Ignore}). Profile is applied first, then overrides. componentName optional for actors (defaults to all primitive components), required for Blueprint templates (#545)"
3794
4102
  options:
3795
4103
  method: set_collision
3796
4104
  gameplay.set_physics_properties:
3797
4105
  class_path: ue-mcp.bridge
3798
4106
  group: gameplay
3799
- description: "Set mass/damping/gravity. Params: actorLabel, mass?, linearDamping?, angularDamping?, enableGravity?"
4107
+ description: "Set mass/damping/gravity. Params: actorLabel OR actorPath, mass?, linearDamping?, angularDamping?, enableGravity?"
3800
4108
  options:
3801
4109
  method: set_physics_properties
3802
4110
  gameplay.rebuild_navigation:
@@ -3808,7 +4116,7 @@ tasks:
3808
4116
  gameplay.find_nav_path:
3809
4117
  class_path: ue-mcp.bridge
3810
4118
  group: gameplay
3811
- description: "Synchronous nav-path query between two world points. Returns valid/partial/length plus the polyline. The standard 'why doesn't my AI move?' diagnostic. Params: start (Vec3), end (Vec3), pathfindingContext? (actorLabel - uses its agent + filter) (#424)"
4119
+ description: "Synchronous nav-path query between two world points. Returns valid/partial/length plus the polyline. The standard 'why doesn't my AI move?' diagnostic. Params: start (Vec3), end (Vec3), pathfindingContext? (actor label) OR pathfindingContextPath? (object path) - uses its agent + filter (#424/#983)"
3812
4120
  options:
3813
4121
  method: find_nav_path
3814
4122
  gameplay.list_nav_invokers:
@@ -3910,15 +4218,63 @@ tasks:
3910
4218
  gameplay.get_behavior_tree_info:
3911
4219
  class_path: ue-mcp.bridge
3912
4220
  group: gameplay
3913
- description: "Inspect behavior tree (top-level + blackboard). Params: assetPath"
4221
+ description: "Inspect a BehaviorTree asset: root node, blackboard asset, every blackboard key (name, type, instanceSynced, description) plus the keys inherited from the blackboard's parent chain, and the node/decorator counts. Params: assetPath (#887)"
3914
4222
  options:
3915
4223
  method: get_behavior_tree_info
3916
4224
  gameplay.read_behavior_tree_graph:
3917
4225
  class_path: ue-mcp.bridge
3918
4226
  group: gameplay
3919
- description: "Walk BT tree: composites, tasks, decorators, services with blackboard keys. Params: assetPath"
4227
+ description: "Walk a BT asset: composites, tasks, decorators, services, each with a stable nodePath ('Root.Children[0].Decorators[1]') you pass to read_bt_node_properties / set_bt_node_property. Every decorator reports its full runtime config - blackboardKey {selectedKeyName, selectedKeyType}, basicOperation (Set|NotSet), arithmeticOperation, textOperation, flowAbortMode, notifyObserver, inverseCondition, int/float/stringValue and staticDescription - which is what answers 'the tree is running but the wrong branch fires'. Set includeProperties for each node's own UPROPERTY values, propertyNames to narrow those, includeInherited to keep UBTNode's own fields. Params: assetPath, includeProperties?, includeInherited?, propertyNames? (#888)"
3920
4228
  options:
3921
4229
  method: read_behavior_tree_graph
4230
+ gameplay.read_bt_node_properties:
4231
+ class_path: ue-mcp.bridge
4232
+ group: gameplay
4233
+ description: "Filtered read of BT node UPROPERTY values: pick nodes by nodeClass, nodeName, nodePath or kind and get back only their own properties, instead of an unfiltered whole-asset dump. Narrow further with propertyNames. A UE 5.8 FValueOrBBKey_* field (AcceptableRadius, WaitTime, FilterClass) is unpacked into {defaultValue, key, isBound, baseClass, text}. Params: assetPath, nodeClass?, nodeName?, nodePath?, kind?, propertyNames?, includeInherited? (#919)"
4234
+ options:
4235
+ method: read_bt_node_properties
4236
+ gameplay.list_bt_tasks:
4237
+ class_path: ue-mcp.bridge
4238
+ group: gameplay
4239
+ description: "Inventory BTTask nodes with their name, class, parent path and FilterClass. Pass assetPath for one tree, or directory (+recursive) to sweep many. On UE 5.8 BTTask_MoveTo.FilterClass is a FValueOrBBKey_Class, so it is reported as {defaultValue, defaultValueName, key, isBound, baseClass, text} - the shape get_editor_property reads as empty. filterClassOnly keeps only tasks that declare one. Params: assetPath?, directory?, recursive?, taskClass?, filterClassOnly?, limit? (#940)"
4240
+ options:
4241
+ method: list_bt_tasks
4242
+ gameplay.set_bt_node_property:
4243
+ class_path: ue-mcp.bridge
4244
+ group: gameplay
4245
+ description: "Scoped write onto one owned BT node subobject. Pick the node with nodePath (from read_behavior_tree_graph), nodeName, nodeClass or kind - the write refuses to run unless exactly one node matches - then set property + value, or a properties map of dotted/indexed paths ('Lines[1].Text', 'BlackboardKey.SelectedKeyName'). A scalar aimed at a UE 5.8 FValueOrBBKey_* field lands on its DefaultValue; an object writes the struct's own fields, so {Key: 'MyKey'} binds it to a blackboard key. Every target is read back and reported with its previous value. Params: assetPath, nodePath?, nodeName?, nodeClass?, kind?, property?, value?, properties? (#919)"
4246
+ options:
4247
+ method: set_bt_node_property
4248
+ gameplay.list_bt_graph_nodes:
4249
+ class_path: ue-mcp.bridge
4250
+ group: gameplay
4251
+ description: "List the EDITOR-GRAPH nodes of a BehaviorTree, which is the layer add_bt_node / move_bt_node / remove_bt_node address. Each entry carries its guid (the primary key: stable across recompiles and unaffected by inserting a sibling), category (root|composite|task|decorator|service), class, parentGuid, indexInParent, childGuids in execution order, decoratorGuids, serviceGuids, graph position and any node error. runtimePath cross-references the same node's read address ('Root.Children[0]') so one listing serves both surfaces. A tree that has never been opened in the BT editor reports hasGraph false and no nodes; add_bt_node seeds the graph. Params: assetPath (#889)"
4252
+ options:
4253
+ method: list_bt_graph_nodes
4254
+ gameplay.add_bt_node:
4255
+ class_path: ue-mcp.bridge
4256
+ group: gameplay
4257
+ description: "Add a composite, task, decorator or service to a BehaviorTree's editor graph and recompile it into the runnable tree. This is the authoring half that reflection cannot reach: UBehaviorTreeGraph::UpdateAsset, which turns the graph into the UBTCompositeNode tree, is editor-only and unexposed, so nodes spawned by script alone never become a valid tree. parent takes a guid from list_bt_graph_nodes, a runtime address from read_behavior_tree_graph, a unique node name, or 'root' (the default). Decorators and services attach as subnodes of their parent rather than as children. index places the node among its siblings, which is the execution order a Selector or Sequence is defined by; on a SimpleParallel it picks the output (0 = main task, 1 = background). properties writes UPROPERTY values (a bare number aimed at a UE 5.8 FValueOrBBKey_* field lands on its DefaultValue), and blackboardKeys points FBlackboardKeySelector fields at named blackboard keys, resolved against the tree's blackboard. Params: assetPath, nodeClass, nodeCategory?, parent?, index?, nodeName?, properties?, blackboardKeys? (#889)"
4258
+ options:
4259
+ method: add_bt_node
4260
+ gameplay.move_bt_node:
4261
+ class_path: ue-mcp.bridge
4262
+ group: gameplay
4263
+ description: "Reconnect a BehaviorTree node to a different parent, reorder it among its siblings, or both, then recompile. Pass parent to reparent and index to reorder; at least one is required. Child order is what a Selector or Sequence executes by, so this is behaviour rather than layout. Decorators and services move between their owners' subnode lists. Moving a node under itself or its own descendant is refused, and the whole subtree travels with it. Returns the parent's siblingOrder after the compile. Params: assetPath, node, parent?, index? (#947)"
4264
+ options:
4265
+ method: move_bt_node
4266
+ gameplay.remove_bt_node:
4267
+ class_path: ue-mcp.bridge
4268
+ group: gameplay
4269
+ description: "Delete a node from a BehaviorTree's editor graph and recompile. A composite takes its whole branch with it, so the compiled tree never reports nodes that no longer run. Decorators and services detach from their owner. The root node cannot be removed. Returns every removed node's guid and class. Params: assetPath, node (#889)"
4270
+ options:
4271
+ method: remove_bt_node
4272
+ gameplay.set_bt_task_property:
4273
+ class_path: ue-mcp.bridge
4274
+ group: gameplay
4275
+ description: "Write a property on one BT task node, FilterClass included. Same selector and dotted-path rules as set_bt_node_property. Retarget a MoveTo filter with property='FilterClass' and a class path, a short class name or a Blueprint asset path; pass null to clear it, or {Key: 'MyKey'} to bind it to a blackboard key. The new value is read back and returned. Params: assetPath, nodePath?, nodeName?, nodeClass?, property?, value?, properties? (#940)"
4276
+ options:
4277
+ method: set_bt_task_property
3922
4278
  gameplay.create_blackboard:
3923
4279
  class_path: ue-mcp.bridge
3924
4280
  group: gameplay
@@ -3994,7 +4350,7 @@ tasks:
3994
4350
  gameplay.get_state_tree_runtime:
3995
4351
  class_path: ue-mcp.bridge
3996
4352
  group: gameplay
3997
- description: "Read a running StateTreeComponent's active state names in PIE (the 'brain' state). Params: actorLabel, world? (default pie), componentName? (#654)"
4353
+ description: "Read a running StateTreeComponent's active state names in PIE (the 'brain' state). Params: actorLabel OR actorPath, world? (default pie), componentName? (#654)"
3998
4354
  options:
3999
4355
  method: get_state_tree_runtime
4000
4356
  gameplay.create_state_tree:
@@ -4170,33 +4526,45 @@ tasks:
4170
4526
  gas.apply_effect:
4171
4527
  class_path: ue-mcp.bridge
4172
4528
  group: gas
4173
- description: "Apply a GameplayEffect to a live actor's ASC (agnostic stat/damage stimulus - uses the game's own effect). Params: actorLabel, effectClass (content path or class name), level?, setByCaller? ({tag-or-name: magnitude}), world? (auto|pie|editor, default auto)"
4529
+ description: "Apply a GameplayEffect to a live actor's ASC (agnostic stat/damage stimulus - uses the game's own effect). Params: actorLabel OR actorPath, effectClass (content path or class name), level?, setByCaller? ({tag-or-name: magnitude}), world? (auto|pie|editor, default auto)"
4174
4530
  options:
4175
4531
  method: apply_effect
4176
4532
  gas.set_attribute:
4177
4533
  class_path: ue-mcp.bridge
4178
4534
  group: gas
4179
- description: "Set a gameplay attribute's base value on a live actor's ASC (recalculates CurrentValue through the aggregator). Params: actorLabel, attribute (Health | SetName.Health), value, world?"
4535
+ description: "Set a gameplay attribute's base value on a live actor's ASC (recalculates CurrentValue through the aggregator). Params: actorLabel OR actorPath, attribute (Health | SetName.Health), value, world?"
4180
4536
  options:
4181
4537
  method: set_attribute
4182
4538
  gas.get_attribute:
4183
4539
  class_path: ue-mcp.bridge
4184
4540
  group: gas
4185
- description: "Read gameplay attribute base + current values on a live actor's ASC. Omit attribute to list all. Params: actorLabel, attribute?, world?"
4541
+ description: "Read gameplay attribute base + current values on a live actor's ASC. Omit attribute to list all. Params: actorLabel OR actorPath, attribute?, world?"
4186
4542
  options:
4187
4543
  method: get_attribute
4188
4544
  gas.init_asc:
4189
4545
  class_path: ue-mcp.bridge
4190
4546
  group: gas
4191
- description: "Initialize a live actor's ASC (InitAbilityActorInfo) and optionally instantiate an AttributeSet so attributes are live - the runtime setup step for testing a bridge-authored GAS actor. Params: actorLabel, attributeSet? (content path or class name), world?"
4547
+ description: "Initialize a live actor's ASC (InitAbilityActorInfo) and optionally instantiate an AttributeSet so attributes are live - the runtime setup step for testing a bridge-authored GAS actor. Params: actorLabel OR actorPath, attributeSet? (content path or class name), world?"
4192
4548
  options:
4193
4549
  method: init_asc
4194
4550
  gas.get_asc_state:
4195
4551
  class_path: ue-mcp.bridge
4196
4552
  group: gas
4197
- description: "Introspect a live actor's ASC: granted ability specs (class, level, inputID, active, dynamicTags) + owned gameplay tags. Params: actorLabel, world? (auto|pie|editor) (#587)"
4553
+ description: "Introspect a live actor's ASC: granted ability specs (class, level, inputID, active, dynamicTags) + owned gameplay tags. Params: actorLabel OR actorPath, world? (auto|pie|editor) (#587)"
4198
4554
  options:
4199
4555
  method: get_asc_state
4556
+ gas.get_live_attribute_value:
4557
+ class_path: ue-mcp.bridge
4558
+ group: gas
4559
+ description: "Read the live value of one FGameplayAttributeData on the attribute set instance actually REGISTERED on an actor's AbilitySystemComponent - equivalent to ASC->GetSet<T>(), not the actor's own subobject pointer. Works in the editor world, where no set is registered yet, by first registering the actor's own sets the way BeginPlay would (set registerOwnerSets=false for a strict read). Returns currentValue and baseValue off the instance plus the aggregator's view of both, and the instance's object path so you can prove which object was read. Params: actorLabel (label or internal name) OR actorPath, attributeSet (content path or class name), attribute (property name, or Set.Property), registerOwnerSets?, world? (#956)"
4560
+ options:
4561
+ method: get_live_attribute_value
4562
+ gas.set_live_attribute_value:
4563
+ class_path: ue-mcp.bridge
4564
+ group: gas
4565
+ description: "Write the live value of one FGameplayAttributeData on the REGISTERED attribute set instance on an actor's AbilitySystemComponent. valueType=\"current\" (default) writes the attribute data in place, which is what staging a mid-combat state needs; valueType=\"base\" writes through the ASC so the aggregator recomputes the current value, which is what a durable change needs. The set's PreAttributeChange may clamp, so the result reports what was actually stored alongside the previous values and the instance's object path. Params: actorLabel (label or internal name) OR actorPath, attributeSet, attribute, value, valueType?, registerOwnerSets?, world? (#956)"
4566
+ options:
4567
+ method: set_live_attribute_value
4200
4568
 
4201
4569
  # ── networking ──
4202
4570
  networking.set_replicates:
@@ -4296,7 +4664,7 @@ tasks:
4296
4664
  feedback.submit:
4297
4665
  class_path: feedback.submit
4298
4666
  group: feedback
4299
- description: "Submit feedback about a tool gap (missing action, wrong behavior, crash, or a case you had to work around). Provide a specific title and a summary; pythonWorkaround and idealTool are optional enrichment, not prerequisites. Checks the plugin registry first and files against the owning plugin's repo when one matches, then blocks on an MCP elicitation prompt that asks the USER (not the agent) to approve or decline the exact payload - and to override the tracker - before anything is posted to GitHub."
4667
+ description: "Submit feedback about a tool gap (missing action, wrong behavior, crash, or a case you had to work around). Provide a specific title and a summary; pythonWorkaround and idealTool are optional enrichment, not prerequisites. Checks the plugin registry first and files against the owning plugin's repo when one matches, then blocks on an MCP elicitation prompt that asks the USER (not the agent) to approve or decline the exact payload - and to override the tracker - before anything is posted to GitHub. If the client cannot show that form (it never advertised elicitation, it throws, or it auto-answers in milliseconds without rendering anything), nothing is lost: the report is written to disk and the result carries a prefilled GitHub issue URL for the user to click."
4300
4668
  feedback.route:
4301
4669
  class_path: feedback.route
4302
4670
  group: feedback