ue-mcp 1.3.7 → 1.3.8-beta

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 (197) hide show
  1. package/README.md +2 -2
  2. package/dist/action-class.d.ts +22 -1
  3. package/dist/action-class.js +17 -1
  4. package/dist/action-class.js.map +1 -1
  5. package/dist/action-effects.d.ts +84 -0
  6. package/dist/action-effects.js +214 -0
  7. package/dist/action-effects.js.map +1 -0
  8. package/dist/action-schema.d.ts +16 -3
  9. package/dist/action-schema.js +2 -2
  10. package/dist/action-schema.js.map +1 -1
  11. package/dist/action-verbs.d.ts +45 -0
  12. package/dist/action-verbs.js +64 -0
  13. package/dist/action-verbs.js.map +1 -0
  14. package/dist/editor-gate.js +34 -6
  15. package/dist/editor-gate.js.map +1 -1
  16. package/dist/epic-input.d.ts +22 -0
  17. package/dist/epic-input.js +120 -0
  18. package/dist/epic-input.js.map +1 -0
  19. package/dist/epic-surface.d.ts +47 -0
  20. package/dist/epic-surface.js +37 -0
  21. package/dist/epic-surface.js.map +1 -0
  22. package/dist/flow/flow-tool.js +6 -0
  23. package/dist/flow/flow-tool.js.map +1 -1
  24. package/dist/flow/guard-schema.d.ts +28 -16
  25. package/dist/flow/guard-schema.js +16 -2
  26. package/dist/flow/guard-schema.js.map +1 -1
  27. package/dist/flow/guard.d.ts +37 -7
  28. package/dist/flow/guard.js +57 -19
  29. package/dist/flow/guard.js.map +1 -1
  30. package/dist/flow/guards.js +3 -1
  31. package/dist/flow/guards.js.map +1 -1
  32. package/dist/flow/journal-actions.js +18 -0
  33. package/dist/flow/journal-actions.js.map +1 -1
  34. package/dist/flow/schema.d.ts +10 -10
  35. package/dist/flow/skill-actions.d.ts +15 -1
  36. package/dist/flow/skill-actions.js +33 -6
  37. package/dist/flow/skill-actions.js.map +1 -1
  38. package/dist/flow/write-methods.d.ts +0 -24
  39. package/dist/flow/write-methods.js +21 -5
  40. package/dist/flow/write-methods.js.map +1 -1
  41. package/dist/index.js +25 -77
  42. package/dist/index.js.map +1 -1
  43. package/dist/init.js +6 -6
  44. package/dist/init.js.map +1 -1
  45. package/dist/lean-context.js +16 -0
  46. package/dist/lean-context.js.map +1 -1
  47. package/dist/lock-owner.d.ts +13 -0
  48. package/dist/lock-owner.js +26 -0
  49. package/dist/lock-owner.js.map +1 -0
  50. package/dist/locking.d.ts +30 -15
  51. package/dist/locking.js +45 -54
  52. package/dist/locking.js.map +1 -1
  53. package/dist/plugin/injection.js +7 -0
  54. package/dist/plugin/injection.js.map +1 -1
  55. package/dist/plugin/manifest.d.ts +46 -16
  56. package/dist/plugin/manifest.js +9 -0
  57. package/dist/plugin/manifest.js.map +1 -1
  58. package/dist/plugin/provision.js +6 -0
  59. package/dist/plugin/provision.js.map +1 -1
  60. package/dist/schemas.js +1 -1
  61. package/dist/schemas.js.map +1 -1
  62. package/dist/session.js +1 -1
  63. package/dist/session.js.map +1 -1
  64. package/dist/skill-packs.d.ts +10 -2
  65. package/dist/skill-packs.js +12 -7
  66. package/dist/skill-packs.js.map +1 -1
  67. package/dist/tool-counts.json +26 -24
  68. package/dist/tools/animation.js +118 -115
  69. package/dist/tools/animation.js.map +1 -1
  70. package/dist/tools/asset.js +141 -126
  71. package/dist/tools/asset.js.map +1 -1
  72. package/dist/tools/audio.js +51 -51
  73. package/dist/tools/audio.js.map +1 -1
  74. package/dist/tools/blueprint.js +89 -84
  75. package/dist/tools/blueprint.js.map +1 -1
  76. package/dist/tools/chooser.js +9 -9
  77. package/dist/tools/chooser.js.map +1 -1
  78. package/dist/tools/conversation.d.ts +10 -0
  79. package/dist/tools/conversation.js +12 -0
  80. package/dist/tools/conversation.js.map +1 -0
  81. package/dist/tools/dataflow.d.ts +15 -0
  82. package/dist/tools/dataflow.js +17 -0
  83. package/dist/tools/dataflow.js.map +1 -0
  84. package/dist/tools/demo.js +4 -4
  85. package/dist/tools/demo.js.map +1 -1
  86. package/dist/tools/editor.js +123 -102
  87. package/dist/tools/editor.js.map +1 -1
  88. package/dist/tools/epic/animation.generated.d.ts +6 -0
  89. package/dist/tools/epic/animation.generated.js +875 -0
  90. package/dist/tools/epic/animation.generated.js.map +1 -0
  91. package/dist/tools/epic/asset.generated.d.ts +6 -0
  92. package/dist/tools/epic/asset.generated.js +226 -0
  93. package/dist/tools/epic/asset.generated.js.map +1 -0
  94. package/dist/tools/epic/blueprint.generated.d.ts +6 -0
  95. package/dist/tools/epic/blueprint.generated.js +168 -0
  96. package/dist/tools/epic/blueprint.generated.js.map +1 -0
  97. package/dist/tools/epic/conversation.generated.d.ts +6 -0
  98. package/dist/tools/epic/conversation.generated.js +37 -0
  99. package/dist/tools/epic/conversation.generated.js.map +1 -0
  100. package/dist/tools/epic/dataflow.generated.d.ts +6 -0
  101. package/dist/tools/epic/dataflow.generated.js +88 -0
  102. package/dist/tools/epic/dataflow.generated.js.map +1 -0
  103. package/dist/tools/epic/editor.generated.d.ts +6 -0
  104. package/dist/tools/epic/editor.generated.js +88 -0
  105. package/dist/tools/epic/editor.generated.js.map +1 -0
  106. package/dist/tools/epic/effects.d.ts +25 -0
  107. package/dist/tools/epic/effects.js +1716 -0
  108. package/dist/tools/epic/effects.js.map +1 -0
  109. package/dist/tools/epic/epic.generated.d.ts +6 -0
  110. package/dist/tools/epic/epic.generated.js +39 -0
  111. package/dist/tools/epic/epic.generated.js.map +1 -0
  112. package/dist/tools/epic/gameplay.generated.d.ts +6 -0
  113. package/dist/tools/epic/gameplay.generated.js +113 -0
  114. package/dist/tools/epic/gameplay.generated.js.map +1 -0
  115. package/dist/tools/epic/gas.generated.d.ts +6 -0
  116. package/dist/tools/epic/gas.generated.js +59 -0
  117. package/dist/tools/epic/gas.generated.js.map +1 -0
  118. package/dist/tools/epic/index.d.ts +40 -0
  119. package/dist/tools/epic/index.js +41 -0
  120. package/dist/tools/epic/index.js.map +1 -0
  121. package/dist/tools/epic/level.generated.d.ts +6 -0
  122. package/dist/tools/epic/level.generated.js +135 -0
  123. package/dist/tools/epic/level.generated.js.map +1 -0
  124. package/dist/tools/epic/material.generated.d.ts +6 -0
  125. package/dist/tools/epic/material.generated.js +114 -0
  126. package/dist/tools/epic/material.generated.js.map +1 -0
  127. package/dist/tools/epic/niagara.generated.d.ts +6 -0
  128. package/dist/tools/epic/niagara.generated.js +186 -0
  129. package/dist/tools/epic/niagara.generated.js.map +1 -0
  130. package/dist/tools/epic/pcg.generated.d.ts +6 -0
  131. package/dist/tools/epic/pcg.generated.js +116 -0
  132. package/dist/tools/epic/pcg.generated.js.map +1 -0
  133. package/dist/tools/epic/plugins.generated.d.ts +6 -0
  134. package/dist/tools/epic/plugins.generated.js +78 -0
  135. package/dist/tools/epic/plugins.generated.js.map +1 -0
  136. package/dist/tools/epic/project.generated.d.ts +6 -0
  137. package/dist/tools/epic/project.generated.js +61 -0
  138. package/dist/tools/epic/project.generated.js.map +1 -0
  139. package/dist/tools/epic/reflection.generated.d.ts +6 -0
  140. package/dist/tools/epic/reflection.generated.js +37 -0
  141. package/dist/tools/epic/reflection.generated.js.map +1 -0
  142. package/dist/tools/epic/statetree.generated.d.ts +6 -0
  143. package/dist/tools/epic/statetree.generated.js +41 -0
  144. package/dist/tools/epic/statetree.generated.js.map +1 -0
  145. package/dist/tools/epic/widget.generated.d.ts +6 -0
  146. package/dist/tools/epic/widget.generated.js +140 -0
  147. package/dist/tools/epic/widget.generated.js.map +1 -0
  148. package/dist/tools/epic.js +7 -4
  149. package/dist/tools/epic.js.map +1 -1
  150. package/dist/tools/fab.js +8 -8
  151. package/dist/tools/fab.js.map +1 -1
  152. package/dist/tools/feedback.js +4 -0
  153. package/dist/tools/feedback.js.map +1 -1
  154. package/dist/tools/foliage.js +17 -13
  155. package/dist/tools/foliage.js.map +1 -1
  156. package/dist/tools/gameplay.js +101 -98
  157. package/dist/tools/gameplay.js.map +1 -1
  158. package/dist/tools/gas.js +36 -33
  159. package/dist/tools/gas.js.map +1 -1
  160. package/dist/tools/landscape.js +35 -35
  161. package/dist/tools/landscape.js.map +1 -1
  162. package/dist/tools/level.js +113 -92
  163. package/dist/tools/level.js.map +1 -1
  164. package/dist/tools/material.js +52 -49
  165. package/dist/tools/material.js.map +1 -1
  166. package/dist/tools/networking.js +11 -11
  167. package/dist/tools/networking.js.map +1 -1
  168. package/dist/tools/niagara.js +47 -42
  169. package/dist/tools/niagara.js.map +1 -1
  170. package/dist/tools/pcg.js +22 -19
  171. package/dist/tools/pcg.js.map +1 -1
  172. package/dist/tools/plugins.js +7 -0
  173. package/dist/tools/plugins.js.map +1 -1
  174. package/dist/tools/project.js +101 -10
  175. package/dist/tools/project.js.map +1 -1
  176. package/dist/tools/reflection.js +16 -13
  177. package/dist/tools/reflection.js.map +1 -1
  178. package/dist/tools/statetree.js +51 -48
  179. package/dist/tools/statetree.js.map +1 -1
  180. package/dist/tools/widget.js +52 -49
  181. package/dist/tools/widget.js.map +1 -1
  182. package/dist/tools.js +4 -0
  183. package/dist/tools.js.map +1 -1
  184. package/dist/types.d.ts +108 -6
  185. package/dist/types.js +21 -7
  186. package/dist/types.js.map +1 -1
  187. package/dist/ue-mcp.default.yml +6358 -1786
  188. package/package.json +7 -3
  189. package/plugin/ue_mcp_bridge/UE_MCP_Bridge.uplugin +2 -2
  190. package/skills/ue-mcp-workflow/SKILL.md +1 -1
  191. package/assets/epic-catalog.snapshot.json +0 -15758
  192. package/dist/epic-cache.d.ts +0 -43
  193. package/dist/epic-cache.js +0 -81
  194. package/dist/epic-cache.js.map +0 -1
  195. package/dist/epic-enrich.d.ts +0 -47
  196. package/dist/epic-enrich.js +0 -323
  197. package/dist/epic-enrich.js.map +0 -1
@@ -24,6 +24,7 @@ import { readLogState, readEngineSnapshot } from "../engine-observer.js";
24
24
  import { switchProject, isTargetDiverged } from "../project-switch.js";
25
25
  import { ueMcpConfigRejections, describeConfigRejections } from "../project.js";
26
26
  import { CURSOR_PARAM, paged } from "../pagination.js";
27
+ import { actions as epicActions, schema as epicSchema } from "./epic/project.generated.js";
27
28
  /**
28
29
  * The environment variables flattening every registered editor into one, right
29
30
  * now.
@@ -142,6 +143,8 @@ function resolveSourceModuleDir(projectDir, projectName, moduleName) {
142
143
  }
143
144
  export const projectTool = categoryTool("project", "Project status and editor connection: get_status (is the editor connected?), set_project (switch/redirect the bridge to another .uproject), get_info. Also config INI files, module load state, and C++ source inspection. Call project(get_status) first in any session.", {
144
145
  get_status: {
146
+ kind: "handler",
147
+ effect: "read",
145
148
  description: "Check server mode and editor connection. Also reports pluginBuildStale when the compiled bridge is older than its source, which is the real cause of 'Unknown method' on handlers that do exist. Params: none (#785)",
146
149
  handler: async (ctx) => {
147
150
  const flows = ctx.getFlows?.() ?? [];
@@ -243,6 +246,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
243
246
  },
244
247
  },
245
248
  set_project: {
249
+ kind: "handler",
250
+ effect: "mutate",
246
251
  description: "Switch project: moves both path resolution and the editor connection to the new .uproject. Params: projectPath",
247
252
  handler: async (ctx, p) => {
248
253
  const projectPath = p.projectPath;
@@ -287,6 +292,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
287
292
  },
288
293
  },
289
294
  list_editors: {
295
+ kind: "handler",
296
+ effect: "read",
290
297
  description: "List every editor session this server drives: name, project, bridge port, whether the socket is connected, whether anything is answering on that port, and which session untargeted calls fall through to. Params: none (#817)",
291
298
  handler: async (ctx) => {
292
299
  if (!ctx.sessions) {
@@ -334,6 +341,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
334
341
  },
335
342
  },
336
343
  use_editor: {
344
+ kind: "handler",
345
+ effect: "mutate",
337
346
  description: "Make one editor session the default target for untargeted calls. Does not change the session set and never touches any editor process. Params: editorTarget (session name, project name, or .uproject path) (#817)",
338
347
  handler: async (ctx, p) => {
339
348
  if (!ctx.sessions)
@@ -352,6 +361,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
352
361
  },
353
362
  },
354
363
  add_editor: {
364
+ kind: "handler",
365
+ effect: "mutate",
355
366
  description: "Register another project as an addressable editor session, with its own bridge connection and port. Optionally launch its editor. Every category then accepts editor=\"<name>\" to run a call there. Params: projectPath, editorName? (defaults to the project name), start? (launch the editor and wait for it to be ready), timeout? (seconds, default 300) (#817)",
356
367
  handler: async (ctx, p) => {
357
368
  if (!ctx.sessions)
@@ -423,6 +434,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
423
434
  },
424
435
  },
425
436
  drop_editor: {
437
+ kind: "handler",
438
+ effect: "mutate",
426
439
  description: "Forget an editor session and close its bridge socket. The editor process is LEFT RUNNING and untouched - this detaches, it does not stop anything (use editor(stop_editor) for that). Params: editorTarget (#817)",
427
440
  handler: async (ctx, p) => {
428
441
  if (!ctx.sessions)
@@ -442,6 +455,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
442
455
  },
443
456
  },
444
457
  get_info: {
458
+ kind: "handler",
459
+ effect: "read",
445
460
  description: "Read .uproject file details. Params: none",
446
461
  handler: async (ctx) => {
447
462
  ctx.project.ensureLoaded();
@@ -449,6 +464,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
449
464
  },
450
465
  },
451
466
  read_config: {
467
+ kind: "handler",
468
+ effect: "read",
452
469
  description: "Read INI config. Params: configName (e.g. 'Engine', 'Game')",
453
470
  handler: async (ctx, p) => {
454
471
  ctx.project.ensureLoaded();
@@ -460,6 +477,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
460
477
  },
461
478
  },
462
479
  search_config: {
480
+ kind: "handler",
481
+ effect: "read",
463
482
  description: "Search INI files. Params: query",
464
483
  handler: async (ctx, p) => {
465
484
  ctx.project.ensureLoaded();
@@ -485,6 +504,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
485
504
  },
486
505
  },
487
506
  list_config_tags: {
507
+ kind: "handler",
508
+ effect: "read",
488
509
  description: "Extract gameplay tags from config. Params: none",
489
510
  handler: async (ctx) => {
490
511
  ctx.project.ensureLoaded();
@@ -516,6 +537,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
516
537
  },
517
538
  },
518
539
  read_cpp_header: {
540
+ kind: "handler",
541
+ effect: "read",
519
542
  description: "Parse a .h file. Params: headerPath",
520
543
  handler: async (ctx, p) => {
521
544
  ctx.project.ensureLoaded();
@@ -532,6 +555,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
532
555
  },
533
556
  },
534
557
  read_module: {
558
+ kind: "handler",
559
+ effect: "read",
535
560
  description: "Read module source. Params: moduleName",
536
561
  handler: async (ctx, p) => {
537
562
  ctx.project.ensureLoaded();
@@ -548,6 +573,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
548
573
  },
549
574
  },
550
575
  list_modules: {
576
+ kind: "handler",
577
+ effect: "read",
551
578
  description: "List C++ modules. Params: none",
552
579
  handler: async (ctx) => {
553
580
  ctx.project.ensureLoaded();
@@ -567,6 +594,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
567
594
  },
568
595
  },
569
596
  search_cpp: {
597
+ kind: "handler",
598
+ effect: "read",
570
599
  description: "Search .h/.cpp files. Params: query, directory?",
571
600
  handler: async (ctx, p) => {
572
601
  ctx.project.ensureLoaded();
@@ -624,6 +653,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
624
653
  },
625
654
  },
626
655
  read_engine_header: {
656
+ kind: "handler",
657
+ effect: "read",
627
658
  description: "Parse a .h file from the engine source tree. Params: headerPath (relative to Engine/Source, or absolute)",
628
659
  handler: async (ctx, p) => {
629
660
  const engineRoot = requireEngineRoot(ctx);
@@ -638,6 +669,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
638
669
  },
639
670
  },
640
671
  find_engine_symbol: {
672
+ kind: "handler",
673
+ effect: "read",
641
674
  description: "Grep engine headers for a symbol. Params: symbol, maxResults?",
642
675
  handler: async (ctx, p) => {
643
676
  const engineRoot = requireEngineRoot(ctx);
@@ -676,6 +709,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
676
709
  },
677
710
  },
678
711
  list_engine_modules: {
712
+ kind: "handler",
713
+ effect: "read",
679
714
  description: "List modules in Engine/Source/Runtime. Params: none",
680
715
  handler: async (ctx) => {
681
716
  const engineRoot = requireEngineRoot(ctx);
@@ -689,6 +724,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
689
724
  },
690
725
  },
691
726
  search_engine_cpp: {
727
+ kind: "handler",
728
+ effect: "read",
692
729
  description: "Search engine .h/.cpp/.inl files across Runtime/Editor/Developer/Plugins. Params: query, tree? (Runtime|Editor|Developer|Plugins|all - default Runtime), subdirectory?, maxResults? (default 500)",
693
730
  handler: async (ctx, p) => {
694
731
  const engineRoot = requireEngineRoot(ctx);
@@ -762,6 +799,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
762
799
  },
763
800
  },
764
801
  search_tools: {
802
+ kind: "handler",
803
+ effect: "read",
765
804
  description: "Search every ue-mcp tool + action by keyword or task INTENT (a synonym layer maps 'screenshot'->capture_scene_png, 'tile a texture'->the texture-bomb flow, etc.) and return ranked matches (tool, action, description, score). The first step before editor(execute_python); most tasks already have a dedicated action. Params: query (space-separated keywords/intent), limit? (default 20) (#704)",
766
805
  handler: async (_ctx, p) => {
767
806
  const query = p.query ?? "";
@@ -779,6 +818,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
779
818
  },
780
819
  },
781
820
  describe_action: {
821
+ kind: "handler",
822
+ effect: "read",
782
823
  description: "Return the live parameter schema for one action: every parameter it accepts, "
783
824
  + "with type, required/optional, description, allowed values and default, plus the "
784
825
  + "bridge method it dispatches to. search_tools finds an action by keyword and hands "
@@ -831,6 +872,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
831
872
  },
832
873
  },
833
874
  list_available_actions: {
875
+ kind: "handler",
876
+ effect: "read",
834
877
  description: "Report which actions this server can serve RIGHT NOW and why the rest cannot. With no editor "
835
878
  + "attached the surface is advertised in full but most of it cannot run, and this is the line "
836
879
  + "between the two halves: an action either runs in this Node process (availability 'always') or "
@@ -872,6 +915,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
872
915
  },
873
916
  },
874
917
  list_content_assets: {
918
+ kind: "handler",
919
+ effect: "read",
875
920
  description: "List the project's assets from the package files on DISK, which is the one asset query that "
876
921
  + "works with no editor running. Takes a mount path (/Game, /Game/Characters, or a plugin's "
877
922
  + "/MyPlugin) and resolves it through the same mount table the live path uses, so an offline "
@@ -890,6 +935,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
890
935
  }),
891
936
  },
892
937
  check_install: {
938
+ kind: "handler",
939
+ effect: "read",
893
940
  description: "Answer whether this project can run the bridge at all, from disk, with no editor running and "
894
941
  + "nothing compiled. Reports the project kind (a project declaring no native modules of its own "
895
942
  + "is Blueprint-only, which is NOT a blocker: UnrealBuildTool writes temporary target and module "
@@ -909,6 +956,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
909
956
  },
910
957
  },
911
958
  execute_python_report: {
959
+ kind: "handler",
960
+ effect: "read",
912
961
  description: "Measurement for #704: reads this session's execute_python calls and, for each, runs its taskSummary back through search_tools to flag calls that OVERLAPPED an existing dedicated action ('you used Python for X, but tool Y does X'). Returns totalCalls, overlapping[] and an overlapRate. Params: none (#704)",
913
962
  handler: async (ctx) => {
914
963
  const entries = getWorkarounds(ctx);
@@ -932,6 +981,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
932
981
  },
933
982
  },
934
983
  list_files: {
984
+ kind: "handler",
985
+ effect: "read",
935
986
  description: "List files on disk under a directory, optionally filtered by extension(s). Runs in the MCP server process (no editor round-trip). Params: directory (absolute, or relative to the project dir), extensions? (e.g. ['png','exr'] or 'png'), recursive? (default false), maxResults? (default 1000) (#608)",
936
987
  handler: async (ctx, p) => {
937
988
  ctx.project.ensureLoaded();
@@ -974,8 +1025,10 @@ export const projectTool = categoryTool("project", "Project status and editor co
974
1025
  return { directory: base, extensions: exts, recursive, count: results.length, files: results };
975
1026
  },
976
1027
  },
977
- set_config: bp("Write to INI. Params: configName, section, key, value", "set_config"),
1028
+ set_config: bp("mutate", "Write to INI. Params: configName, section, key, value", "set_config"),
978
1029
  build: {
1030
+ kind: "handler",
1031
+ effect: "mutate",
979
1032
  // #958: this used to be dispatched over the editor bridge, so it failed
980
1033
  // with ECONNREFUSED whenever the editor was down. That made it unusable
981
1034
  // for its only real job: UnrealBuildTool refuses to link while an editor
@@ -995,11 +1048,13 @@ export const projectTool = categoryTool("project", "Project status and editor co
995
1048
  return { ...result, output: lines.join("") };
996
1049
  },
997
1050
  },
998
- generate_project_files: bp("Generate IDE project files (Visual Studio, Xcode, etc.). Params: none", "generate_project_files"),
1051
+ generate_project_files: bp("mutate", "Generate IDE project files (Visual Studio, Xcode, etc.). Params: none", "generate_project_files"),
999
1052
  // v0.7.13 - native C++ authoring. Bridge handlers wrap
1000
1053
  // GameProjectUtils / ILiveCodingModule (same APIs used by the editor's
1001
1054
  // File → New C++ Class and Live Coding menus).
1002
1055
  create_cpp_class: {
1056
+ kind: "bridge",
1057
+ effect: "mutate",
1003
1058
  description: "Create a new native UCLASS in a project module. Uses the same engine template path as File → New C++ Class. Writes .h + .cpp; returns both paths plus needsEditorRestart (true unless Live Coding successfully hot-reloaded). Params: className (no prefix), parentClass? (default UObject; accepts short names like 'Actor' or /Script/<Module>.<Class> paths), moduleName? (default: first project module, use list_project_modules to pick), classDomain? ('public'|'private'|'classes', default public), subPath?",
1004
1059
  bridge: "create_cpp_class",
1005
1060
  // AddCodeToProject regenerates IDE project files synchronously - can
@@ -1013,21 +1068,25 @@ export const projectTool = categoryTool("project", "Project status and editor co
1013
1068
  subPath: p.subPath,
1014
1069
  }),
1015
1070
  },
1016
- list_project_modules: bp(paged("List native modules in the current project (name, host type, source path), in the .uproject's own declaration order. Feed moduleName from here into create_cpp_class."), "list_project_modules", (p) => ({ cursor: p.cursor, limit: p.limit })),
1017
- list_loaded_modules: bp(paged("Enumerate ALL engine+project modules with runtime load state (loaded/gameModule), not just uproject-declared ones. Params: filter? (case-insensitive substring), loadedOnly? (default false) (#689)"), "list_loaded_modules", (p) => ({ filter: p.filter, loadedOnly: p.loadedOnly, cursor: p.cursor, limit: p.limit })),
1018
- is_module_loaded: bp("Report whether a named module is currently loaded in the editor. Params: moduleName (#689)", "is_module_loaded", (p) => ({ moduleName: p.moduleName })),
1019
- list_available_plugins: bp(paged("List every plugin installed in this engine or project, sorted by name, with its category, version, type, whether it is enabled in THIS editor session, whether it is enabled by default, and the .uproject's current reference to it under projectReference {present, enabled}. Those two disagree after enable_plugin until the editor restarts, which is the point of reporting both. Params: filter?, pluginCategory?, enabledOnly?, limit? (default 200, max 2000)"), "list_available_plugins", (p) => ({ filter: p.filter, pluginCategory: p.pluginCategory, enabledOnly: p.enabledOnly, cursor: p.cursor, limit: p.limit })),
1020
- enable_plugin: bp("Enable a plugin in the .uproject. Plugin enablement is neither a UPROPERTY nor an INI key, it is a JSON array in the .uproject read once at startup, so set_config cannot reach it and without this a plugin-gated capability stays permanently unreachable through the bridge. Idempotent: a plugin already enabled, or enabled by default with no entry, reports existed and writes nothing. The change is a file change, so modules, classes, content and settings appear only after editor(restart_editor), which the result says. Params: pluginName", "enable_plugin", (p) => ({ pluginName: p.pluginName })),
1021
- disable_plugin: bp("Disable a plugin in the .uproject. removeReference deletes the entry outright instead of writing an explicit disable, which is the difference between handing a default-on plugin back to its default and overriding it, and the two are not the same file. Idempotent against whichever of the two was asked for. Refuses to disable the bridge itself, since that would leave no way to undo it. Takes effect on the next editor start. Params: pluginName, removeReference?", "disable_plugin", (p) => ({ pluginName: p.pluginName, removeReference: p.removeReference })),
1071
+ list_project_modules: bp("read", paged("List native modules in the current project (name, host type, source path), in the .uproject's own declaration order. Feed moduleName from here into create_cpp_class."), "list_project_modules", (p) => ({ cursor: p.cursor, limit: p.limit })),
1072
+ list_loaded_modules: bp("read", paged("Enumerate ALL engine+project modules with runtime load state (loaded/gameModule), not just uproject-declared ones. Params: filter? (case-insensitive substring), loadedOnly? (default false) (#689)"), "list_loaded_modules", (p) => ({ filter: p.filter, loadedOnly: p.loadedOnly, cursor: p.cursor, limit: p.limit })),
1073
+ is_module_loaded: bp("read", "Report whether a named module is currently loaded in the editor. Params: moduleName (#689)", "is_module_loaded", (p) => ({ moduleName: p.moduleName })),
1074
+ list_available_plugins: bp("read", paged("List every plugin installed in this engine or project, sorted by name, with its category, version, type, whether it is enabled in THIS editor session, whether it is enabled by default, and the .uproject's current reference to it under projectReference {present, enabled}. Those two disagree after enable_plugin until the editor restarts, which is the point of reporting both. Params: filter?, pluginCategory?, enabledOnly?, limit? (default 200, max 2000)"), "list_available_plugins", (p) => ({ filter: p.filter, pluginCategory: p.pluginCategory, enabledOnly: p.enabledOnly, cursor: p.cursor, limit: p.limit })),
1075
+ enable_plugin: bp("mutate", "Enable a plugin in the .uproject. Plugin enablement is neither a UPROPERTY nor an INI key, it is a JSON array in the .uproject read once at startup, so set_config cannot reach it and without this a plugin-gated capability stays permanently unreachable through the bridge. Idempotent: a plugin already enabled, or enabled by default with no entry, reports existed and writes nothing. The change is a file change, so modules, classes, content and settings appear only after editor(restart_editor), which the result says. Params: pluginName", "enable_plugin", (p) => ({ pluginName: p.pluginName })),
1076
+ disable_plugin: bp("mutate", "Disable a plugin in the .uproject. removeReference deletes the entry outright instead of writing an explicit disable, which is the difference between handing a default-on plugin back to its default and overriding it, and the two are not the same file. Idempotent against whichever of the two was asked for. Refuses to disable the bridge itself, since that would leave no way to undo it. Takes effect on the next editor start. Params: pluginName, removeReference?", "disable_plugin", (p) => ({ pluginName: p.pluginName, removeReference: p.removeReference })),
1022
1077
  live_coding_compile: {
1078
+ kind: "bridge",
1079
+ effect: "mutate",
1023
1080
  description: "Trigger a Live Coding compile (Windows only). Hot-patches method bodies of existing UCLASSes without editor restart - the fast inner loop for UFUNCTION implementations. Does NOT reliably register brand-new UCLASSes; use build_project + editor restart for those. Params: wait? (default false - fire and return 'in_progress').",
1024
1081
  bridge: "live_coding_compile",
1025
1082
  timeoutMs: 300_000,
1026
1083
  mapParams: (p) => ({ wait: p.wait }),
1027
1084
  },
1028
- live_coding_status: bp("Report Live Coding availability/state (available, started, enabledForSession, compiling). Helps choose between live_coding_compile and build_project. Params: none", "live_coding_status", () => ({})),
1029
- resolve_collision_profile: bp("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?", "resolve_collision_profile", (p) => ({ profileName: p.profileName, channel: p.channel, includeAllChannels: p.includeAllChannels })),
1085
+ live_coding_status: bp("read", "Report Live Coding availability/state (available, started, enabledForSession, compiling). Helps choose between live_coding_compile and build_project. Params: none", "live_coding_status", () => ({})),
1086
+ resolve_collision_profile: bp("read", "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?", "resolve_collision_profile", (p) => ({ profileName: p.profileName, channel: p.channel, includeAllChannels: p.includeAllChannels })),
1030
1087
  write_cpp_file: {
1088
+ kind: "handler",
1089
+ effect: "mutate",
1031
1090
  description: "Write a .h / .cpp / .inl file under the project's Source/ tree. Used to append UPROPERTYs/UFUNCTIONs or method bodies after create_cpp_class. Writes are scoped to Source/ for safety. Params: path (relative to Source/ or absolute within Source/), content (full file contents). After editing, call live_coding_compile (for existing classes) or build_project (for new classes).",
1032
1091
  handler: async (ctx, p) => {
1033
1092
  ctx.project.ensureLoaded();
@@ -1060,6 +1119,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1060
1119
  },
1061
1120
  },
1062
1121
  read_cpp_source: {
1122
+ kind: "handler",
1123
+ effect: "read",
1063
1124
  description: "Read a .cpp file from the project Source/ tree. Companion to read_cpp_header for round-trip edits. Params: sourcePath (relative to Source/ or absolute).",
1064
1125
  handler: async (ctx, p) => {
1065
1126
  ctx.project.ensureLoaded();
@@ -1079,6 +1140,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1079
1140
  },
1080
1141
  },
1081
1142
  write_source_file: {
1143
+ kind: "handler",
1144
+ effect: "mutate",
1082
1145
  description: "Write a .h/.cpp/.inl into a named module's Public/Private folder (resolves the module dir for you, including plugin modules under Plugins/*/Source/ that write_cpp_file refuses). After a new file, build_project + restart; after a body edit, live_coding_compile. Params: module (module name, default the project's primary module), visibility (Public|Private, default Private), fileName, content.",
1083
1146
  handler: async (ctx, p) => {
1084
1147
  ctx.project.ensureLoaded();
@@ -1112,6 +1175,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1112
1175
  },
1113
1176
  },
1114
1177
  read_source_file: {
1178
+ kind: "handler",
1179
+ effect: "read",
1115
1180
  description: "Read a .h/.cpp/.inl from a named module's folder (companion to write_source_file; resolves plugin modules too). With no visibility it tries Public then Private then the module root. Params: module, visibility?, fileName.",
1116
1181
  handler: async (ctx, p) => {
1117
1182
  ctx.project.ensureLoaded();
@@ -1134,6 +1199,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1134
1199
  },
1135
1200
  },
1136
1201
  build_engine_index: {
1202
+ kind: "handler",
1203
+ effect: "mutate",
1137
1204
  description: "Build or refresh the engine symbol index that verify_symbols, lint_cpp_header and "
1138
1205
  + "suggest_build_deps read. Scans roughly 31,000 headers across Runtime, Editor, Developer "
1139
1206
  + "and the includable half of Engine/Plugins, and records for each symbol the header that "
@@ -1161,6 +1228,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1161
1228
  },
1162
1229
  },
1163
1230
  verify_symbols: {
1231
+ kind: "handler",
1232
+ effect: "read",
1164
1233
  description: "Check that engine symbols exist BEFORE writing C++ that uses them, and get back what you "
1165
1234
  + "need to write it: the header to #include, the owning module for Build.cs, the exact "
1166
1235
  + "declaration, the base class, and any UE_DEPRECATED with its version and message. Accepts "
@@ -1179,6 +1248,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1179
1248
  },
1180
1249
  },
1181
1250
  suggest_build_deps: {
1251
+ kind: "handler",
1252
+ effect: "mutate",
1182
1253
  description: "Given the engine symbols a module uses, report which modules its Build.cs has to depend on "
1183
1254
  + "and which of those it does not list yet, plus the AddRange line to paste. Core and "
1184
1255
  + "CoreUObject are omitted because every module already has them. buildCsPath defaults to "
@@ -1201,6 +1272,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1201
1272
  },
1202
1273
  },
1203
1274
  find_example_usage: {
1275
+ kind: "handler",
1276
+ effect: "read",
1204
1277
  description: "Find real call sites for an engine symbol in the engine's own .cpp files, which answers "
1205
1278
  + "'how is this actually used' with code that compiles. Better than a signature for anything "
1206
1279
  + "with a non-obvious calling convention. Searches sources rather than headers on purpose: a "
@@ -1225,6 +1298,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1225
1298
  },
1226
1299
  },
1227
1300
  class_hierarchy: {
1301
+ kind: "handler",
1302
+ effect: "read",
1228
1303
  description: "Report what a class derives from and what derives from it, which is the question behind "
1229
1304
  + "'what should I subclass' and 'what already does this'. Ancestors are the full chain up "
1230
1305
  + "to the root, nearest parent first; descendants default to the direct subclasses only, "
@@ -1258,6 +1333,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1258
1333
  },
1259
1334
  },
1260
1335
  find_references: {
1336
+ kind: "handler",
1337
+ effect: "read",
1261
1338
  description: "Find every line in the engine tree that names a symbol, which answers 'how is this woven "
1262
1339
  + "into the engine' and 'what would break if this changed'. Broader than find_callers on "
1263
1340
  + "purpose: a reference is a member declaration, a UPROPERTY type, a cast, a template "
@@ -1285,6 +1362,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1285
1362
  },
1286
1363
  },
1287
1364
  find_callers: {
1365
+ kind: "handler",
1366
+ effect: "read",
1288
1367
  description: "Find who calls a function, and from which enclosing function, which is how to see the "
1289
1368
  + "conventions around a call before writing one: what is checked first, what is passed, "
1290
1369
  + "what is done with the result. Searches .cpp bodies first, since a mention in a header is "
@@ -1312,6 +1391,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1312
1391
  },
1313
1392
  },
1314
1393
  find_callees: {
1394
+ kind: "handler",
1395
+ effect: "read",
1315
1396
  description: "Report what a function calls, by reading its body and looking every called name back up "
1316
1397
  + "in the engine index. Answers 'what does doing this properly actually involve': the "
1317
1398
  + "result carries each callee's module and include, and modules[] is the Build.cs cost of "
@@ -1340,6 +1421,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1340
1421
  },
1341
1422
  },
1342
1423
  symbol_context: {
1424
+ kind: "handler",
1425
+ effect: "read",
1343
1426
  description: "Return the lines of engine source around a declaration, so the API surrounding a symbol "
1344
1427
  + "can be read without opening the file: the sibling overloads, the UPROPERTY above it, the "
1345
1428
  + "comment saying which of three similar methods to call. verify_symbols returns the "
@@ -1368,6 +1451,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1368
1451
  },
1369
1452
  },
1370
1453
  lint_cpp_header: {
1454
+ kind: "handler",
1455
+ effect: "read",
1371
1456
  description: "Check a header you just wrote against the engine it has to build against, and report what "
1372
1457
  + "the compiler would before the compiler runs. Covers the structural mistakes that produce "
1373
1458
  + "baffling Unreal build errors (a reflected type with no .generated.h include, a .generated.h "
@@ -1400,6 +1485,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1400
1485
  },
1401
1486
  },
1402
1487
  add_module_dependency: {
1488
+ kind: "handler",
1489
+ effect: "mutate",
1403
1490
  description: "Add a module to a target module's Build.cs dependency array. Params: moduleName (the Build.cs to edit - must exist in the project), dependency (module name to add, e.g. 'UMG'), access? ('public'|'private', default 'private'). Creates the corresponding AddRange block if missing. Rebuild required afterward.",
1404
1491
  handler: async (ctx, p) => {
1405
1492
  ctx.project.ensureLoaded();
@@ -1453,6 +1540,8 @@ export const projectTool = categoryTool("project", "Project status and editor co
1453
1540
  },
1454
1541
  },
1455
1542
  add_cpp_member: {
1543
+ kind: "handler",
1544
+ effect: "mutate",
1456
1545
  // #423: append a UPROPERTY / UFUNCTION declaration to an existing UCLASS
1457
1546
  // header in the right access-specifier block. The recurring trap is that
1458
1547
  // raw appending lands the declaration in whatever access section the
@@ -1536,7 +1625,9 @@ export const projectTool = categoryTool("project", "Project status and editor co
1536
1625
  };
1537
1626
  },
1538
1627
  },
1628
+ ...epicActions,
1539
1629
  }, undefined, {
1630
+ ...epicSchema,
1540
1631
  projectPath: z.string().optional().describe("For set_project / add_editor / check_install: path to .uproject"),
1541
1632
  editorName: z.string().optional().describe("For add_editor: name to address the new session by (default the project name) (#817)"),
1542
1633
  editorTarget: z.string().optional().describe("For use_editor / drop_editor: session name, project name, or .uproject path (#817)"),