MCP Backup Restore and remove undo
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include "AssetRegistry/IAssetRegistry.h"
|
||||
#include "AssetToolsModule.h"
|
||||
#include "IAssetTools.h"
|
||||
#include "FileHelpers.h"
|
||||
#include "MCPHandlers_AssetMutation.generated.h"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -241,3 +242,97 @@ public:
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
UCLASS(meta=(ToolName="backup_asset"))
|
||||
class UMCPHandler_BackupAsset : public UObject, public IMCPHandler
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(meta=(Description="Full package path of the asset (e.g. /Game/Widgets/WB_Hotkeys)"))
|
||||
FString AssetPath;
|
||||
|
||||
virtual FString GetDescription() const override
|
||||
{
|
||||
return TEXT("Copy an asset's .uasset file to a .uasset.bak backup.");
|
||||
}
|
||||
|
||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||
{
|
||||
FString Filename = FPaths::ConvertRelativePathToFull(
|
||||
FPackageName::LongPackageNameToFilename(AssetPath, FPackageName::GetAssetPackageExtension()));
|
||||
|
||||
if (!IFileManager::Get().FileExists(*Filename))
|
||||
{
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Asset file not found: %s"), *Filename));
|
||||
}
|
||||
|
||||
FString BackupFilename = Filename + TEXT(".bak");
|
||||
uint32 CopyResult = IFileManager::Get().Copy(*BackupFilename, *Filename, true);
|
||||
if (CopyResult != COPY_OK)
|
||||
{
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Failed to back up %s"), *Filename));
|
||||
}
|
||||
|
||||
Result->SetStringField(TEXT("backupFile"), BackupFilename);
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
UCLASS(meta=(ToolName="restore_asset"))
|
||||
class UMCPHandler_RestoreAsset : public UObject, public IMCPHandler
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(meta=(Description="Full package path of the asset (e.g. /Game/Widgets/WB_Hotkeys)"))
|
||||
FString AssetPath;
|
||||
|
||||
virtual FString GetDescription() const override
|
||||
{
|
||||
return TEXT("Restore a .uasset file from its .uasset.bak backup, reloading it in the editor.");
|
||||
}
|
||||
|
||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||
{
|
||||
FString Filename = FPaths::ConvertRelativePathToFull(
|
||||
FPackageName::LongPackageNameToFilename(AssetPath, FPackageName::GetAssetPackageExtension()));
|
||||
FString BackupFilename = Filename + TEXT(".bak");
|
||||
|
||||
if (!IFileManager::Get().FileExists(*BackupFilename))
|
||||
{
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Backup file not found: %s"), *BackupFilename));
|
||||
}
|
||||
|
||||
// Release file handles if the package is loaded
|
||||
UPackage* Package = FindPackage(nullptr, *AssetPath);
|
||||
if (Package)
|
||||
{
|
||||
ResetLoaders(Package);
|
||||
}
|
||||
|
||||
// Copy backup over the original
|
||||
uint32 CopyResult = IFileManager::Get().Copy(*Filename, *BackupFilename, true);
|
||||
if (CopyResult != COPY_OK)
|
||||
{
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Failed to restore %s"), *Filename));
|
||||
}
|
||||
|
||||
// Reload the package if it was loaded
|
||||
if (Package)
|
||||
{
|
||||
bool bReloaded = false;
|
||||
FText ErrorMessage;
|
||||
UEditorLoadingAndSavingUtils::ReloadPackages({Package}, bReloaded, ErrorMessage, EReloadPackagesInteractionMode::AssumePositive);
|
||||
}
|
||||
|
||||
Result->SetStringField(TEXT("restoredFrom"), BackupFilename);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -253,23 +253,12 @@ void FMCPServer::DispatchToolCall(const FString& ToolName, const FJsonObject* Pa
|
||||
{
|
||||
if (UClass** HandlerClass = MCPHandlerRegistry.Find(ToolName))
|
||||
{
|
||||
const bool bIsMutation = MutationEndpoints.Contains(ToolName);
|
||||
if (bIsMutation && GEditor)
|
||||
{
|
||||
GEditor->BeginTransaction(FText::FromString(FString::Printf(TEXT("BlueprintMCP: %s"), *ToolName)));
|
||||
}
|
||||
|
||||
TStrongObjectPtr<UObject> HandlerObj(NewObject<UObject>(GetTransientPackage(), *HandlerClass));
|
||||
IMCPHandler* Handler = Cast<IMCPHandler>(HandlerObj.Get());
|
||||
if (MCPUtils::PopulateFromJson(HandlerObj->GetClass(), HandlerObj.Get(), Params, Result))
|
||||
{
|
||||
Handler->Handle(Params, Result);
|
||||
}
|
||||
|
||||
if (bIsMutation && GEditor)
|
||||
{
|
||||
GEditor->EndTransaction();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -316,7 +305,6 @@ bool FMCPServer::Start(int32 InPort, bool bEditorMode)
|
||||
|
||||
// Register handlers
|
||||
BuildMCPHandlerRegistry();
|
||||
RegisterHandlers();
|
||||
|
||||
// Create TCP listen socket
|
||||
ISocketSubsystem* SocketSub = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
|
||||
@@ -535,65 +523,9 @@ bool FMCPServer::ProcessOneRequest()
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// RegisterHandlers / BuildMCPHandlerRegistry
|
||||
// BuildMCPHandlerRegistry
|
||||
// ============================================================
|
||||
|
||||
void FMCPServer::RegisterHandlers()
|
||||
{
|
||||
// Mutation endpoints — wrapped in undo transactions by DispatchToolCall()
|
||||
MutationEndpoints = {
|
||||
TEXT("replace_function_calls_in_blueprint"),
|
||||
TEXT("change_blueprint_variable_type"),
|
||||
TEXT("change_function_parameter_type"),
|
||||
TEXT("remove_function_parameter"),
|
||||
TEXT("delete_asset"),
|
||||
TEXT("connect_blueprint_pins"),
|
||||
TEXT("disconnect_blueprint_pins"),
|
||||
TEXT("refresh_all_nodes_in_graph"),
|
||||
TEXT("set_pin_default_values"),
|
||||
TEXT("set_node_positions"),
|
||||
TEXT("change_struct_node_type"),
|
||||
TEXT("delete_node_from_graph"),
|
||||
TEXT("duplicate_nodes_in_graph"),
|
||||
TEXT("spawn_nodes_in_graph"),
|
||||
TEXT("set_node_comment"),
|
||||
TEXT("rename_asset"),
|
||||
TEXT("reparent_blueprint"),
|
||||
TEXT("set_class_default_value"),
|
||||
TEXT("create_blueprint_asset"),
|
||||
TEXT("create_blueprint_graph"),
|
||||
TEXT("delete_blueprint_graph"),
|
||||
TEXT("rename_blueprint_graph"),
|
||||
TEXT("add_blueprint_variable"),
|
||||
TEXT("remove_blueprint_variable"),
|
||||
TEXT("set_blueprint_variable_metadata"),
|
||||
TEXT("add_blueprint_interface"),
|
||||
TEXT("remove_blueprint_interface"),
|
||||
TEXT("add_event_dispatcher"),
|
||||
TEXT("add_function_parameter"),
|
||||
TEXT("add_blueprint_component"),
|
||||
TEXT("remove_blueprint_component"),
|
||||
TEXT("create_material_asset"),
|
||||
TEXT("set_material_property"),
|
||||
TEXT("add_material_expression"),
|
||||
TEXT("delete_material_expression"),
|
||||
TEXT("connect_material_expression_pins"),
|
||||
TEXT("disconnect_material_expression_pin"),
|
||||
TEXT("set_material_expression_property"),
|
||||
TEXT("set_material_expression_position"),
|
||||
TEXT("create_material_instance_asset"),
|
||||
TEXT("set_material_instance_parameter"),
|
||||
TEXT("reparent_material_instance"),
|
||||
TEXT("create_material_function_asset"),
|
||||
TEXT("add_anim_state_to_machine"),
|
||||
TEXT("remove_anim_state_from_machine"),
|
||||
TEXT("add_anim_state_transition"),
|
||||
TEXT("set_anim_transition_rule"),
|
||||
TEXT("set_anim_state_animation"),
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void FMCPServer::BuildMCPHandlerRegistry()
|
||||
{
|
||||
for (TObjectIterator<UClass> It; It; ++It)
|
||||
|
||||
@@ -51,8 +51,6 @@ public:
|
||||
private:
|
||||
// ----- Tool dispatch -----
|
||||
TMap<FString, UClass*> MCPHandlerRegistry; // tool name -> UMCPHandler subclass
|
||||
TSet<FString> MutationEndpoints;
|
||||
void RegisterHandlers();
|
||||
void BuildMCPHandlerRegistry();
|
||||
|
||||
// Dispatch a tool call to the appropriate handler
|
||||
|
||||
Reference in New Issue
Block a user