Files
unreal-engine-mcp-system-pl…/Source/UEBlueprintMCPEditor/Public/MCPGraphLibrary.h
Bonchellon eba71c4ca8 Unified, portable Unreal Engine MCP system plugin
Merge of the two project copies into one self-contained plugin (the superset:
variable_op + variables.py, full pcg_op runtime/declarative/preset ops, the
CreateWidgetFloatAnimation widget tool, and full Voxel graph authoring).

Made fully project- and machine-agnostic — no hardcoded paths:
- New src/projectPaths.js auto-detects the host .uproject (walk-up), project
  name, Editor build target, log file, and engine install (EngineAssociation
  via launcher manifest/registry, else installed-engine scan). All overridable
  via UE_* env vars.
- Rewired buildOrchestrator/insights/launcher/insightsExporter/server.js and the
  Python workers (cpp_scaffold, live_coding, apply_graph, console) off the old
  C:/Github/ihy, IHY*, E:/UE_Versions and UE_5.7 literals onto the resolver.
- Voxel made optional: Build.cs auto-detects the Voxel plugin (env
  UE_MCP_WITH_VOXEL override) and the C++ compiles to stubs under WITH_MCP_VOXEL,
  so the module builds in projects without Voxel; .uplugin marks Voxel optional.
- De-branded the agent-gateway and docs; scrubbed a leaked API key; excluded
  node_modules/Binaries/Intermediate/__pycache__/secrets from the repo.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 01:07:24 +03:00

431 lines
23 KiB
C++

// Exposes K2 graph mutation to Python.
//
// In Python these are reachable as:
// unreal.MCPGraphLibrary.spawn_call_function_node(bp, graph, owner_class, fn_name, pos)
// unreal.MCPGraphLibrary.connect_pins(graph, from_id, "Then", to_id, "Exec")
// etc.
//
// Every spawn returns the node's NodeGuid as a string. Python keeps a local
// id -> NodeGuid map and passes the guid into connect_pins / set_pin_default.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "MCPGraphLibrary.generated.h"
class UBlueprint;
class UWidgetBlueprint;
class UWidget;
class UEdGraph;
class UEdGraphNode;
class UEdGraphPin;
class UScriptStruct;
class UEnum;
UCLASS()
class UEBLUEPRINTMCPEDITOR_API UMCPGraphLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
// ====================================================================
// Graph lookup
// ====================================================================
UFUNCTION(BlueprintCallable, Category = "MCP|Graph")
static UEdGraph* FindEventGraph(UBlueprint* Blueprint);
UFUNCTION(BlueprintCallable, Category = "MCP|Graph")
static UEdGraph* FindFunctionGraph(UBlueprint* Blueprint, FName FunctionName);
UFUNCTION(BlueprintCallable, Category = "MCP|Graph")
static TArray<FString> ListNodeIds(UEdGraph* Graph);
UFUNCTION(BlueprintCallable, Category = "MCP|Graph")
static TArray<FString> ListPinsOnNode(UEdGraph* Graph, const FString& NodeId);
UFUNCTION(BlueprintCallable, Category = "MCP|Graph")
static int32 ClearGraph(UEdGraph* Graph);
UFUNCTION(BlueprintCallable, Category = "MCP|Graph")
static bool DeleteNode(UEdGraph* Graph, const FString& NodeId);
// ====================================================================
// Spawners — basic
// ====================================================================
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnCallFunctionNode(UBlueprint* Blueprint, UEdGraph* Graph, UClass* FunctionOwnerClass, FName FunctionName, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnEventNode(UBlueprint* Blueprint, UEdGraph* Graph, UClass* OwnerClass, FName EventName, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnCustomEventNode(UBlueprint* Blueprint, UEdGraph* Graph, FName EventName, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Network")
static bool SetCustomEventNetworkFlags(UBlueprint* Blueprint, UEdGraph* Graph, const FString& NodeIdOrEventName, FName Mode, bool bReliable);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnComponentBoundEvent(UBlueprint* Blueprint, UEdGraph* Graph, FName ComponentName, FName DelegateName, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnBranchNode(UBlueprint* Blueprint, UEdGraph* Graph, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnSequenceNode(UBlueprint* Blueprint, UEdGraph* Graph, FVector2D Position, int32 OutputCount);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnVariableGetNode(UBlueprint* Blueprint, UEdGraph* Graph, FName VariableName, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnVariableSetNode(UBlueprint* Blueprint, UEdGraph* Graph, FName VariableName, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnSelfNode(UBlueprint* Blueprint, UEdGraph* Graph, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnCastNode(UBlueprint* Blueprint, UEdGraph* Graph, UClass* TargetClass, FVector2D Position);
// ====================================================================
// Spawners — flow / collections
// ====================================================================
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnSwitchOnIntNode(UBlueprint* Blueprint, UEdGraph* Graph, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnSwitchOnStringNode(UBlueprint* Blueprint, UEdGraph* Graph, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnSwitchOnEnumNode(UBlueprint* Blueprint, UEdGraph* Graph, UEnum* EnumType, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnMakeArrayNode(UBlueprint* Blueprint, UEdGraph* Graph, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnMakeStructNode(UBlueprint* Blueprint, UEdGraph* Graph, UScriptStruct* StructType, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnBreakStructNode(UBlueprint* Blueprint, UEdGraph* Graph, UScriptStruct* StructType, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnSetFieldsInStructNode(UBlueprint* Blueprint, UEdGraph* Graph, UScriptStruct* StructType, FVector2D Position);
/** Spawn a UK2Node_MacroInstance bound to one of the StandardMacros (ForLoop,
* ForEachLoop, WhileLoop, DoOnce, Gate, FlipFlop, MultiGate, IsValid, DoN). */
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnStandardMacroNode(UBlueprint* Blueprint, UEdGraph* Graph, FName MacroName, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnSpawnActorFromClassNode(UBlueprint* Blueprint, UEdGraph* Graph, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnFormatTextNode(UBlueprint* Blueprint, UEdGraph* Graph, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnGetSubsystemNode(UBlueprint* Blueprint, UEdGraph* Graph, UClass* SubsystemClass, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnLoadAssetNode(UBlueprint* Blueprint, UEdGraph* Graph, FVector2D Position);
// ====================================================================
// Spawners — Tier 2 (knot/comment/enum literal/class defaults/return/arrays)
// ====================================================================
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnKnotNode(UBlueprint* Blueprint, UEdGraph* Graph, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnCommentNode(UBlueprint* Blueprint, UEdGraph* Graph, FVector2D Position, FVector2D Size, const FString& Comment);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnEnumLiteralNode(UBlueprint* Blueprint, UEdGraph* Graph, UEnum* EnumType, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnGetClassDefaultsNode(UBlueprint* Blueprint, UEdGraph* Graph, UClass* TargetClass, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnFunctionResultNode(UBlueprint* Blueprint, UEdGraph* Graph, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnGetArrayItemNode(UBlueprint* Blueprint, UEdGraph* Graph, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Spawn")
static FString SpawnPromotableOperatorNode(UBlueprint* Blueprint, UEdGraph* Graph, FName OperatorName, FVector2D Position);
/** Add a new case pin to a SwitchInt/SwitchString/SwitchEnum node. */
UFUNCTION(BlueprintCallable, Category = "MCP|Edit")
static bool AddCasePinToSwitch(UEdGraph* Graph, const FString& NodeId);
/** Set FormatText template AND reconstruct so {arg} pins appear. */
UFUNCTION(BlueprintCallable, Category = "MCP|Edit")
static bool FormatTextSetFormat(UEdGraph* Graph, const FString& NodeId, const FString& Format);
/** Force a node to ReconstructNode() (e.g. after toggling pure/latent). */
UFUNCTION(BlueprintCallable, Category = "MCP|Edit")
static bool ReconstructNode(UEdGraph* Graph, const FString& NodeId);
// ====================================================================
// Delegates
// ====================================================================
/** Bind an existing event to a component's multicast delegate.
* target = "ComponentName.DelegateName". */
UFUNCTION(BlueprintCallable, Category = "MCP|Delegate")
static FString SpawnBindDelegateNode(UBlueprint* Blueprint, UEdGraph* Graph, FName ComponentName, FName DelegateName, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Delegate")
static FString SpawnUnbindDelegateNode(UBlueprint* Blueprint, UEdGraph* Graph, FName ComponentName, FName DelegateName, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|Delegate")
static FString SpawnCallDelegateNode(UBlueprint* Blueprint, UEdGraph* Graph, FName DispatcherName, FVector2D Position);
/** AssignDelegate = AddDelegate + CustomEvent — a sugar combo node. */
UFUNCTION(BlueprintCallable, Category = "MCP|Delegate")
static FString SpawnAssignDelegateNode(UBlueprint* Blueprint, UEdGraph* Graph, FName ComponentName, FName DelegateName, FVector2D Position);
/** Add an Event Dispatcher (multicast delegate variable) with no params. */
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool AddEventDispatcher(UBlueprint* Blueprint, FName DispatcherName);
// ====================================================================
// Edges & defaults
// ====================================================================
UFUNCTION(BlueprintCallable, Category = "MCP|Edges")
static bool ConnectPins(UEdGraph* Graph, const FString& FromNodeId, FName FromPin, const FString& ToNodeId, FName ToPin);
UFUNCTION(BlueprintCallable, Category = "MCP|Edges")
static bool BreakLink(UEdGraph* Graph, const FString& FromNodeId, FName FromPin, const FString& ToNodeId, FName ToPin);
UFUNCTION(BlueprintCallable, Category = "MCP|Edges")
static bool BreakAllNodeLinks(UEdGraph* Graph, const FString& NodeId);
UFUNCTION(BlueprintCallable, Category = "MCP|Edges")
static bool SetPinDefault(UEdGraph* Graph, const FString& NodeId, FName PinName, const FString& Value);
// ====================================================================
// BP-level authoring
// ====================================================================
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static UEdGraph* AddFunctionGraph(UBlueprint* Blueprint, FName FunctionName);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static UEdGraph* AddMacroGraph(UBlueprint* Blueprint, FName MacroName);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool AddInterface(UBlueprint* Blueprint, const FString& InterfacePath);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool SetVariableDefaultValue(UBlueprint* Blueprint, FName VariableName, const FString& Value);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool SetVariableMetadata(UBlueprint* Blueprint, FName VariableName, bool bInstanceEditable, bool bExposeOnSpawn, const FString& Category, const FString& Tooltip);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool AddLocalVariable(UBlueprint* Blueprint, FName FunctionName, FName VariableName, const FString& TypeSpec, const FString& DefaultValue);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static FString AddComponentToBlueprint(UBlueprint* Blueprint, UClass* ComponentClass, FName ComponentName);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool AddMemberVariable(UBlueprint* Blueprint, FName VariableName, const FString& TypeSpec);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool RemoveComponent(UBlueprint* Blueprint, FName ComponentName);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool AttachComponent(UBlueprint* Blueprint, FName ChildName, FName ParentName, FName SocketName);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool SetRootComponent(UBlueprint* Blueprint, FName ComponentName);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool SetComponentProperty(UBlueprint* Blueprint, FName ComponentName, FName PropertyName, const FString& Value);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool SetComponentTransform(UBlueprint* Blueprint, FName ComponentName, FVector Location, FRotator Rotation, FVector Scale);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool ConfigureBoxComponent(UBlueprint* Blueprint, FName ComponentName, FVector Extent, FName CollisionProfile);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool RenameVariable(UBlueprint* Blueprint, FName OldName, FName NewName);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool DeleteVariable(UBlueprint* Blueprint, FName VariableName);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool RenameFunction(UBlueprint* Blueprint, FName OldName, FName NewName);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool RemoveFunctionGraph(UBlueprint* Blueprint, FName FunctionName);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool RemoveMacroGraph(UBlueprint* Blueprint, FName MacroName);
/** Add an input/output parameter to a user function. Direction: "input"/"output". */
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool AddFunctionParameter(UBlueprint* Blueprint, FName FunctionName, FName ParamName, const FString& TypeSpec, const FString& Direction);
UFUNCTION(BlueprintCallable, Category = "MCP|Authoring")
static bool RemoveFunctionParameter(UBlueprint* Blueprint, FName FunctionName, FName ParamName);
// ====================================================================
// UMG Designer / WidgetTree
// ====================================================================
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static FString DescribeWidgetTreeJson(UWidgetBlueprint* Blueprint);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static FString GetWidgetPropertiesJson(UWidgetBlueprint* Blueprint, FName WidgetName);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static FString GetWidgetSlotPropertiesJson(UWidgetBlueprint* Blueprint, FName WidgetName);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static FString AddWidgetToTree(UWidgetBlueprint* Blueprint, UClass* WidgetClass, FName WidgetName, FName ParentName, int32 Index, bool bIsVariable);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static bool RemoveWidgetFromTree(UWidgetBlueprint* Blueprint, FName WidgetName);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static bool RenameWidgetInTree(UWidgetBlueprint* Blueprint, FName OldName, FName NewName);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static bool MoveWidgetInTree(UWidgetBlueprint* Blueprint, FName WidgetName, FName NewParentName, int32 Index);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static bool SetRootWidget(UWidgetBlueprint* Blueprint, FName WidgetName);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static bool SetWidgetIsVariable(UWidgetBlueprint* Blueprint, FName WidgetName, bool bIsVariable);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static bool SetWidgetProperty(UWidgetBlueprint* Blueprint, FName WidgetName, FName PropertyName, const FString& Value);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static bool SetWidgetSlotProperty(UWidgetBlueprint* Blueprint, FName WidgetName, FName PropertyName, const FString& Value);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static bool SetCanvasSlotLayout(UWidgetBlueprint* Blueprint, FName WidgetName, FVector2D Position, FVector2D Size, FVector2D AnchorsMinimum, FVector2D AnchorsMaximum, FVector2D Alignment, bool bAutoSize, int32 ZOrder);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static bool SetNamedSlotContent(UWidgetBlueprint* Blueprint, FName HostWidgetName, FName SlotName, FName ContentWidgetName);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static bool ClearNamedSlotContent(UWidgetBlueprint* Blueprint, FName HostWidgetName, FName SlotName);
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static bool SetDesiredFocusWidget(UWidgetBlueprint* Blueprint, FName WidgetName);
/** Create a UMG WidgetAnimation that keys a single float property (e.g. RenderOpacity)
* on WidgetName. Times (seconds) and Values are parallel arrays — each pair is one
* linear key. The animation is added to the WidgetBlueprint's Animations array; loop
* is controlled at PlayAnimation time (NumLoopsToPlay=0). Returns false on bad input
* or if an animation with AnimName already exists. */
UFUNCTION(BlueprintCallable, Category = "MCP|WidgetTree")
static bool CreateWidgetFloatAnimation(UWidgetBlueprint* Blueprint, FName AnimName, FName WidgetName, FName PropertyName, const TArray<float>& Times, const TArray<float>& Values);
// ====================================================================
// Compile / introspect
// ====================================================================
UFUNCTION(BlueprintCallable, Category = "MCP|Asset")
static bool CompileAndSaveBlueprint(UBlueprint* Blueprint);
UFUNCTION(BlueprintCallable, Category = "MCP|Asset")
static TArray<FString> GetCompileErrors(UBlueprint* Blueprint);
/** Compile + capture FCompilerResultsLog. Returns "SEV|NodeName|Message" per entry. */
UFUNCTION(BlueprintCallable, Category = "MCP|Asset")
static TArray<FString> CompileWithMessages(UBlueprint* Blueprint);
/** Dump entire graph as JSON string round-trippable into apply_graph NodeSpec. */
UFUNCTION(BlueprintCallable, Category = "MCP|Asset")
static FString DumpGraphToJson(UEdGraph* Graph);
// ====================================================================
// Discovery — Pipeline v0.3
// ====================================================================
/** List all graphs on a Blueprint. Returns JSON: {event:[], functions:[], macros:[], delegates:[]}. */
UFUNCTION(BlueprintCallable, Category = "MCP|Discover")
static FString ListGraphsJson(UBlueprint* Blueprint);
/** Full BP overview: parent, interfaces, vars, components (SCS tree), functions, dispatchers. JSON. */
UFUNCTION(BlueprintCallable, Category = "MCP|Discover")
static FString DescribeBlueprintJson(UBlueprint* Blueprint);
/** Currently selected nodes in the open BP editor for `Blueprint`. JSON list of NodeGuid strings + per-node info. */
UFUNCTION(BlueprintCallable, Category = "MCP|Discover")
static FString GetSelectedNodesJson(UBlueprint* Blueprint);
/** All currently-open Blueprint editors (paths). */
UFUNCTION(BlueprintCallable, Category = "MCP|Discover")
static TArray<FString> ListOpenBlueprints();
/** For a UK2Node_CallFunction by guid, return {owner_class, function, source_bp_path?, native?} JSON. */
UFUNCTION(BlueprintCallable, Category = "MCP|Discover")
static FString ResolveFunctionSourceJson(UEdGraph* Graph, const FString& NodeId);
/** All node guids in this BP that reference variable `Name`. JSON list grouped by graph. */
UFUNCTION(BlueprintCallable, Category = "MCP|Discover")
static FString FindVariableReferencesJson(UBlueprint* Blueprint, FName VariableName);
/** All call sites of `FunctionName` (defined on Blueprint or external) within this BP. JSON. */
UFUNCTION(BlueprintCallable, Category = "MCP|Discover")
static FString FindFunctionReferencesJson(UBlueprint* Blueprint, FName FunctionName);
/** AssetRegistry-driven BP search by parent class path. Returns list of BP paths. */
UFUNCTION(BlueprintCallable, Category = "MCP|Discover")
static TArray<FString> FindBlueprintsByParent(const FString& ParentClassPath);
/** Hard-referenced assets of this BP (asset registry). */
UFUNCTION(BlueprintCallable, Category = "MCP|Discover")
static TArray<FString> GetReferencedAssets(const FString& AssetPath);
/** Reverse: assets that reference this BP. */
UFUNCTION(BlueprintCallable, Category = "MCP|Discover")
static TArray<FString> GetReferencersOfAsset(const FString& AssetPath);
// ====================================================================
// Editing — single-node operations
// ====================================================================
/** Move nodes by guid to new positions. positions: array of {guid,x,y} encoded as parallel arrays. */
UFUNCTION(BlueprintCallable, Category = "MCP|Edit")
static int32 MoveNodes(UEdGraph* Graph, const TArray<FString>& NodeIds, const TArray<FVector2D>& Positions);
UFUNCTION(BlueprintCallable, Category = "MCP|Edit")
static bool ResizeCommentNode(UEdGraph* Graph, const FString& NodeId, FVector2D Size);
UFUNCTION(BlueprintCallable, Category = "MCP|Edit")
static bool SetNodeComment(UEdGraph* Graph, const FString& NodeId, const FString& Comment, bool bCommentBubbleVisible);
// ====================================================================
// Navigation — open editors, focus nodes
// ====================================================================
UFUNCTION(BlueprintCallable, Category = "MCP|Navigate")
static bool OpenBlueprintEditor(UBlueprint* Blueprint);
UFUNCTION(BlueprintCallable, Category = "MCP|Navigate")
static bool OpenGraphInEditor(UBlueprint* Blueprint, UEdGraph* Graph);
UFUNCTION(BlueprintCallable, Category = "MCP|Navigate")
static bool JumpToNodeInEditor(UBlueprint* Blueprint, UEdGraph* Graph, const FString& NodeId);
UFUNCTION(BlueprintCallable, Category = "MCP|Introspect")
static TArray<FString> ListFunctionsOnClass(UClass* Class);
UFUNCTION(BlueprintCallable, Category = "MCP|Introspect")
static TArray<FString> ListPropertiesOnClass(UClass* Class);
UFUNCTION(BlueprintCallable, Category = "MCP|Introspect")
static TArray<FString> ListDelegatesOnClass(UClass* Class);
UFUNCTION(BlueprintCallable, Category = "MCP|Introspect")
static FString GetPinType(UClass* OwnerClass, FName FunctionName, FName PinName);
private:
static UEdGraphNode* FindNodeByGuid(UEdGraph* Graph, const FString& NodeId);
static UEdGraphPin* FindPinByName(UEdGraphNode* Node, const FName& PinName);
static class USCS_Node* FindSCSNode(UBlueprint* Blueprint, FName ComponentName);
template <typename TNode>
static TNode* PlaceNode(UEdGraph* Graph, FVector2D Position);
};