Refactor MCPHandler to be a UINTERFACE

This commit is contained in:
2026-03-06 14:28:24 -05:00
parent 896df949f7
commit 7e3a4d2fea
6 changed files with 41 additions and 35 deletions

View File

@@ -862,8 +862,9 @@ bool FBlueprintMCPServer::ProcessOneRequest()
GEditor->BeginTransaction(FText::FromString(FString::Printf(TEXT("BlueprintMCP: %s"), *Req->Endpoint)));
}
TStrongObjectPtr<UMCPHandler> Handler(NewObject<UMCPHandler>(GetTransientPackage(), *HandlerClass));
FString PopulateError = PopulateFromJson(Handler->GetClass(), Handler.Get(), Params.Get());
TStrongObjectPtr<UObject> HandlerObj(NewObject<UObject>(GetTransientPackage(), *HandlerClass));
IMCPHandler* Handler = Cast<IMCPHandler>(HandlerObj.Get());
FString PopulateError = PopulateFromJson(HandlerObj->GetClass(), HandlerObj.Get(), Params.Get());
if (PopulateError.IsEmpty())
{
Handler->Handle(Params.Get(), &*Result);
@@ -1057,11 +1058,13 @@ void FBlueprintMCPServer::RegisterHandlers()
void FBlueprintMCPServer::BuildMCPHandlerRegistry()
{
TArray<UClass*> HandlerClasses;
GetDerivedClasses(UMCPHandler::StaticClass(), HandlerClasses);
for (UClass* Class : HandlerClasses)
for (TObjectIterator<UClass> It; It; ++It)
{
UClass* Class = *It;
if (!Class->ImplementsInterface(UMCPHandler::StaticClass()))
{
continue;
}
if (Class->HasAnyClassFlags(CLASS_Abstract))
{
continue;

View File

@@ -5,7 +5,7 @@
#include "BlueprintMCPHandlers_DiffBlueprints.generated.h"
UCLASS(meta=(ToolName="diff_blueprints"))
class UMCPHandler_DiffBlueprints : public UMCPHandler
class UMCPHandler_DiffBlueprints : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -5,7 +5,7 @@
#include "BlueprintMCPHandlers_Interfaces.generated.h"
UCLASS(meta=(ToolName="list_interfaces"))
class UMCPHandler_ListInterfaces : public UMCPHandler
class UMCPHandler_ListInterfaces : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -23,7 +23,7 @@ public:
};
UCLASS(meta=(ToolName="add_interface"))
class UMCPHandler_AddInterface : public UMCPHandler
class UMCPHandler_AddInterface : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -44,7 +44,7 @@ public:
};
UCLASS(meta=(ToolName="remove_interface"))
class UMCPHandler_RemoveInterface : public UMCPHandler
class UMCPHandler_RemoveInterface : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -23,7 +23,7 @@ struct FSetPinDefaultEntry
};
UCLASS(meta=(ToolName="set_pin_default"))
class UMCPHandler_SetPinDefault : public UMCPHandler
class UMCPHandler_SetPinDefault : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -55,7 +55,7 @@ struct FMoveNodeEntry
};
UCLASS(meta=(ToolName="move_node"))
class UMCPHandler_MoveNode : public UMCPHandler
class UMCPHandler_MoveNode : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -75,7 +75,7 @@ public:
};
UCLASS(meta=(ToolName="duplicate_nodes"))
class UMCPHandler_DuplicateNodes : public UMCPHandler
class UMCPHandler_DuplicateNodes : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -121,7 +121,7 @@ struct FSpawnNodeEntry
};
UCLASS(meta=(ToolName="spawn_node"))
class UMCPHandler_SpawnNode : public UMCPHandler
class UMCPHandler_SpawnNode : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -146,7 +146,7 @@ public:
};
UCLASS(meta=(ToolName="get_node_comment"))
class UMCPHandler_GetNodeComment : public UMCPHandler
class UMCPHandler_GetNodeComment : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -166,7 +166,7 @@ public:
};
UCLASS(meta=(ToolName="set_node_comment"))
class UMCPHandler_SetNodeComment : public UMCPHandler
class UMCPHandler_SetNodeComment : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -189,7 +189,7 @@ public:
};
UCLASS(meta=(ToolName="delete_node"))
class UMCPHandler_DeleteNode : public UMCPHandler
class UMCPHandler_DeleteNode : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -228,7 +228,7 @@ struct FConnectPinsEntry
};
UCLASS(meta=(ToolName="connect_pins"))
class UMCPHandler_ConnectPins : public UMCPHandler
class UMCPHandler_ConnectPins : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -266,7 +266,7 @@ struct FDisconnectPinEntry
};
UCLASS(meta=(ToolName="disconnect_pin"))
class UMCPHandler_DisconnectPin : public UMCPHandler
class UMCPHandler_DisconnectPin : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -287,7 +287,7 @@ public:
};
UCLASS(meta=(ToolName="replace_function_calls"))
class UMCPHandler_ReplaceFunctionCalls : public UMCPHandler
class UMCPHandler_ReplaceFunctionCalls : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -314,7 +314,7 @@ public:
};
UCLASS(meta=(ToolName="delete_asset"))
class UMCPHandler_DeleteAsset : public UMCPHandler
class UMCPHandler_DeleteAsset : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -335,7 +335,7 @@ public:
};
UCLASS(meta=(ToolName="refresh_all_nodes"))
class UMCPHandler_RefreshAllNodes : public UMCPHandler
class UMCPHandler_RefreshAllNodes : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -353,7 +353,7 @@ public:
};
UCLASS(meta=(ToolName="change_struct_node_type"))
class UMCPHandler_ChangeStructNodeType : public UMCPHandler
class UMCPHandler_ChangeStructNodeType : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -377,7 +377,7 @@ public:
};
UCLASS(meta=(ToolName="rename_asset"))
class UMCPHandler_RenameAsset : public UMCPHandler
class UMCPHandler_RenameAsset : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -397,7 +397,7 @@ public:
};
UCLASS(meta=(ToolName="set_blueprint_default"))
class UMCPHandler_SetBlueprintDefault : public UMCPHandler
class UMCPHandler_SetBlueprintDefault : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -421,7 +421,7 @@ public:
};
UCLASS(meta=(ToolName="search_node_types"))
class UMCPHandler_SearchNodeTypes : public UMCPHandler
class UMCPHandler_SearchNodeTypes : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -14,7 +14,7 @@ class UMaterial;
class UMaterialInstanceConstant;
class UMaterialFunction;
class UMaterialExpression;
class UMCPHandler;
class IMCPHandler;
// ----- Snapshot data structures -----

View File

@@ -23,9 +23,9 @@ struct FMCPJsonArray
TArray<TSharedPtr<FJsonValue>> Array;
};
// Base class for self-registering MCP tool handlers.
// Interface for self-registering MCP tool handlers.
//
// Subclasses declare their parameters as UPROPERTY fields, which are
// Implementing classes declare their parameters as UPROPERTY fields, which are
// automatically populated from the incoming JSON request and used to
// generate the tool's JSON Schema for MCP tools/list.
//
@@ -35,17 +35,20 @@ struct FMCPJsonArray
// Property metadata:
// Optional - marks a parameter as not required
//
UCLASS(Abstract)
class BLUEPRINTMCP_API UMCPHandler : public UObject
UINTERFACE(MinimalAPI, meta=(CannotImplementInterfaceInBlueprint))
class UMCPHandler : public UInterface
{
GENERATED_BODY()
};
class BLUEPRINTMCP_API IMCPHandler
{
GENERATED_BODY()
public:
// Human-readable tool description for MCP tools/list.
// Override in each subclass.
virtual FString GetDescription() const PURE_VIRTUAL(UMCPHandler::GetDescription, return FString(););
virtual FString GetDescription() const = 0;
// Called after parameter fields have been populated from JSON.
// Override in each subclass.
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) PURE_VIRTUAL(UMCPHandler::Handle, );
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) = 0;
};