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>
This commit is contained in:
Bonchellon
2026-06-24 01:07:24 +03:00
parent d46e03e53e
commit eba71c4ca8
76 changed files with 23838 additions and 1 deletions

View File

@ -0,0 +1,79 @@
// Headless capture helpers for the UEBlueprintMCP plugin.
//
// Lets external agents SEE editor content WITHOUT opening any editor tab/window:
// * RenderAssetThumbnailToPNG — renders ANY asset (StaticMesh, SkeletalMesh,
// Material, Texture, Blueprint, Niagara, AnimSequence, Sound, ...) using the
// editor's per-class thumbnail renderer. No asset editor needs to be open.
// * CaptureEditorSceneToPNG — renders the current editor world from an
// arbitrary camera via an offscreen SceneCaptureComponent2D. No level
// viewport / PIE required.
//
// Both write a PNG to disk and return its absolute path. Called from Python via
// unreal.MCPCaptureLibrary.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "MCPCaptureLibrary.generated.h"
UCLASS()
class UEBLUEPRINTMCPEDITOR_API UMCPCaptureLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
/**
* Render an asset's thumbnail to a PNG file, headlessly.
* Works for every asset type that has a registered thumbnail renderer, which
* is effectively all of them (meshes, materials, textures, blueprints,
* niagara systems, anim sequences, sounds, data assets, ...). The asset
* editor does NOT need to be open.
*
* @param AssetPath Object path, e.g. "/Game/Meshes/SM_Rock" (no class prefix needed).
* @param OutputAbsPath Absolute directory to write into (created if missing).
* @param FileNameNoExt File name WITHOUT extension. ".png" is appended.
* @param Width Pixels, clamped [16, 2048].
* @param Height Pixels, clamped [16, 2048].
* @param OutFullPath On success, absolute path of the written PNG.
* @param OutError On failure, a short description.
*/
UFUNCTION(BlueprintCallable, Category = "MCP|Capture",
meta = (DisplayName = "Render Asset Thumbnail To PNG"))
static bool RenderAssetThumbnailToPNG(
const FString& AssetPath,
const FString& OutputAbsPath,
const FString& FileNameNoExt,
int32 Width,
int32 Height,
FString& OutFullPath,
FString& OutError
);
/**
* Render the active editor world from an arbitrary camera to a PNG, headlessly,
* using an offscreen SceneCaptureComponent2D. No level viewport is needed.
*
* @param Location World-space camera location.
* @param Rotation World-space camera rotation (pitch/yaw/roll).
* @param FOV Horizontal field of view in degrees (clamped [5, 170]).
* @param OutputAbsPath Absolute directory to write into (created if missing).
* @param FileNameNoExt File name WITHOUT extension. ".png" is appended.
* @param Width Pixels, clamped [16, 4096].
* @param Height Pixels, clamped [16, 4096].
* @param OutFullPath On success, absolute path of the written PNG.
* @param OutError On failure, a short description.
*/
UFUNCTION(BlueprintCallable, Category = "MCP|Capture",
meta = (DisplayName = "Capture Editor Scene To PNG"))
static bool CaptureEditorSceneToPNG(
FVector Location,
FRotator Rotation,
float FOV,
const FString& OutputAbsPath,
const FString& FileNameNoExt,
int32 Width,
int32 Height,
FString& OutFullPath,
FString& OutError
);
};

View File

@ -0,0 +1,430 @@
// 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);
};

View File

@ -0,0 +1,28 @@
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "MCPMaterialLibrary.generated.h"
class UMaterialExpression;
class UMaterial;
class UMaterialFunction;
UCLASS()
class UEBLUEPRINTMCPEDITOR_API UMCPMaterialLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "MCP|Material")
static TArray<UMaterialExpression*> GetMaterialExpressions(UObject* MaterialOrFunction);
UFUNCTION(BlueprintCallable, Category = "MCP|Material")
static UMaterialExpression* FindMaterialExpression(UObject* MaterialOrFunction, const FString& NodeId);
UFUNCTION(BlueprintCallable, Category = "MCP|Material")
static FString DumpMaterialGraphToJson(UObject* MaterialOrFunction);
UFUNCTION(BlueprintCallable, Category = "MCP|Material")
static FString ConnectMaterialExpressionsRaw(UObject* MaterialOrFunction, UMaterialExpression* FromExpression, const FString& FromOutput, UMaterialExpression* ToExpression, const FString& ToInput);
};

View File

@ -0,0 +1,69 @@
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "MCPNiagaraLibrary.generated.h"
class UNiagaraSystem;
class UNiagaraEmitter;
class UNiagaraScript;
class UNiagaraRendererProperties;
/**
* Editor-only helpers wrapping Niagara authoring APIs for the MCP server.
* All methods are no-ops/return defaults outside the editor.
*/
UCLASS()
class UMCPNiagaraLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
/** Create an empty UNiagaraSystem asset at the given /Game/... path. */
UFUNCTION(BlueprintCallable, Category = "MCP|Niagara")
static bool CreateNiagaraSystem(const FString& PackagePath);
/** List emitter handle names on the system. */
UFUNCTION(BlueprintCallable, Category = "MCP|Niagara")
static TArray<FString> GetEmitterHandleNames(UNiagaraSystem* System);
/** Add an emitter (asset) to the system. Returns the new handle name or empty on failure. */
UFUNCTION(BlueprintCallable, Category = "MCP|Niagara")
static FString AddEmitterToSystem(UNiagaraSystem* System, UNiagaraEmitter* SourceEmitter, const FString& EmitterName);
/** Remove an emitter handle (by handle name) from the system. */
UFUNCTION(BlueprintCallable, Category = "MCP|Niagara")
static bool RemoveEmitterFromSystem(UNiagaraSystem* System, const FString& EmitterName);
/**
* List module nodes (function-call nodes) in a stack group.
* GroupName: EmitterSpawn | EmitterUpdate | ParticleSpawn | ParticleUpdate | SystemSpawn | SystemUpdate
* EmitterName ignored for SystemSpawn/SystemUpdate.
* Returns module names in evaluation order.
*/
UFUNCTION(BlueprintCallable, Category = "MCP|Niagara")
static TArray<FString> ListModules(UNiagaraSystem* System, const FString& EmitterName, const FString& GroupName);
/**
* Insert a module script into the stack group. Index = -1 appends.
* Returns the spawned module's function name (used as ModuleName for subsequent ops), or empty on failure.
*/
UFUNCTION(BlueprintCallable, Category = "MCP|Niagara")
static FString AddModuleToStack(UNiagaraSystem* System, const FString& EmitterName, const FString& GroupName, UNiagaraScript* ModuleScript, int32 Index);
/** Remove a module node from the stack group by name. */
UFUNCTION(BlueprintCallable, Category = "MCP|Niagara")
static bool RemoveModuleFromStack(UNiagaraSystem* System, const FString& EmitterName, const FString& GroupName, const FString& ModuleName);
/** Add a renderer (UNiagaraRendererProperties subclass) to an emitter. Returns the renderer class name or empty. */
UFUNCTION(BlueprintCallable, Category = "MCP|Niagara")
static FString AddRendererToEmitter(UNiagaraSystem* System, const FString& EmitterName, UClass* RendererClass);
/** Remove all renderers of a given class from an emitter. Returns count removed. */
UFUNCTION(BlueprintCallable, Category = "MCP|Niagara")
static int32 RemoveRenderersFromEmitter(UNiagaraSystem* System, const FString& EmitterName, UClass* RendererClass);
/** Recompile the Niagara system (and its emitters). */
UFUNCTION(BlueprintCallable, Category = "MCP|Niagara")
static bool RequestCompile(UNiagaraSystem* System);
};

View File

@ -0,0 +1,69 @@
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "MCPVoxelGraphLibrary.generated.h"
class UEdGraph;
UCLASS()
class UEBLUEPRINTMCPEDITOR_API UMCPVoxelGraphLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static bool IsVoxelGraphAsset(UObject* Asset);
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static FString ListTerminalGraphsJson(UObject* Asset);
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static UEdGraph* FindTerminalEdGraph(UObject* Asset, const FString& Terminal);
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static FString DumpTerminalGraphJson(UObject* Asset, const FString& Terminal);
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static FString GetSelectedNodesJson(UObject* Asset, const FString& Terminal);
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static FString SpawnCommentNode(UEdGraph* Graph, FVector2D Position, FVector2D Size, const FString& Comment, FLinearColor Color);
// Returns a JSON catalogue of every spawnable Voxel node (struct nodes + function-library nodes).
// Filter is an optional case-insensitive substring matched against id / display name / category.
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static FString ListNodeTypesJson(const FString& Filter, int32 Limit);
// Spawns a functional Voxel node (UVoxelGraphNode_Struct) identified by NodeId
// (struct name, struct path, display name, or "Library.Function" for function nodes).
// Returns the new node GUID as string, or empty on failure.
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static FString SpawnStructNode(UEdGraph* Graph, const FString& NodeId, FVector2D Position);
// Registers a graph property and returns its new GUID as JSON {ok, guid, name, type}.
// Kind: "parameter" (graph parameter), "input"/"output" (function in/out), "local" (local variable).
// TypeStr: float|double|int|bool|vector2d|vector|color|name (defaults to float).
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static FString AddGraphPropertyJson(UObject* Asset, const FString& Terminal, const FString& Kind, const FString& Name, const FString& TypeStr, const FString& Category);
// Lists graph properties of the given Kind as JSON {ok, properties:[{guid,name,type,category}]}.
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static FString ListGraphPropertiesJson(UObject* Asset, const FString& Terminal, const FString& Kind);
// Spawns a usage node for an existing property (Ref = guid or name). bDeclaration only matters
// for Kind "local" (declaration vs usage). Returns the new node GUID, or empty on failure.
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static FString SpawnPropertyNode(UEdGraph* Graph, const FString& Kind, const FString& Ref, FVector2D Position, bool bDeclaration);
// Spawns a "Call Function" node for a function terminal graph (FunctionRef = terminal guid or name).
// Returns the new node GUID, or empty on failure.
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static FString SpawnCallFunctionNode(UEdGraph* Graph, const FString& FunctionRef, FVector2D Position);
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static bool NotifyGraphChanged(UEdGraph* Graph, bool bCompile);
UFUNCTION(BlueprintCallable, Category = "MCP|VoxelGraph")
static bool OpenVoxelGraphAsset(UObject* Asset);
};

View File

@ -0,0 +1,42 @@
// Vision-loop helper for the UEBlueprintMCP plugin.
// Renders a UMG WidgetBlueprint to a PNG file so external agents can SEE
// what they just authored. Called from Python via unreal.MCPWidgetRenderLibrary.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "MCPWidgetRenderLibrary.generated.h"
class UUserWidget;
UCLASS()
class UEBLUEPRINTMCPEDITOR_API UMCPWidgetRenderLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
/**
* Render a UserWidget class to a PNG file on disk.
* Returns true on success and fills OutFullPath with the absolute file path.
*
* @param WidgetClass A UUserWidget subclass (e.g. GeneratedClass of a WidgetBlueprint).
* @param OutputAbsPath Absolute directory path where the PNG should be written.
* The folder is created if missing.
* @param FileNameNoExt File name WITHOUT extension. ".png" is appended automatically.
* @param Width Texture width in pixels (clamped to [16, 8192]).
* @param Height Texture height in pixels (clamped to [16, 8192]).
* @param OutFullPath On success, the absolute path of the written PNG.
* @param OutError On failure, a short description of what went wrong.
*/
UFUNCTION(BlueprintCallable, Category = "MCP|UI",
meta = (DisplayName = "Render Widget To PNG"))
static bool RenderWidgetToPNG(
TSubclassOf<UUserWidget> WidgetClass,
const FString& OutputAbsPath,
const FString& FileNameNoExt,
int32 Width,
int32 Height,
FString& OutFullPath,
FString& OutError
);
};

View File

@ -0,0 +1,31 @@
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FBlueprintEditor;
class IInputProcessor;
class UBlueprint;
class UEdGraph;
class FUEBlueprintMCPEditorModule : public IModuleInterface
{
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
private:
friend class FMCPZoneInputProcessor;
void RegisterMenus();
void NotifyBridgeStatus();
void ToggleMCPZoneMode(TWeakPtr<FBlueprintEditor> BlueprintEditor);
bool IsMCPZoneModeActive(TWeakPtr<FBlueprintEditor> BlueprintEditor) const;
bool TryCreateMCPZoneFromScreenDrag(const FVector2f& StartScreenPosition, const FVector2f& EndScreenPosition);
void CreateMCPZone(UEdGraph* Graph, UBlueprint* Blueprint, const FVector2f& GraphStart, const FVector2f& GraphEnd) const;
void RemoveMCPZones(UBlueprint* Blueprint) const;
bool bMCPZoneModeActive = false;
TWeakPtr<FBlueprintEditor> ActiveMCPZoneEditor;
TSharedPtr<IInputProcessor> MCPZoneInputProcessor;
};