flockbay 0.10.15
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.
- package/README.md +56 -0
- package/bin/flockbay-mcp.mjs +56 -0
- package/bin/flockbay.mjs +78 -0
- package/dist/codex/flockbayMcpStdioBridge.cjs +383 -0
- package/dist/codex/flockbayMcpStdioBridge.d.cts +2 -0
- package/dist/codex/flockbayMcpStdioBridge.d.mts +2 -0
- package/dist/codex/flockbayMcpStdioBridge.mjs +381 -0
- package/dist/flockbayScreenshotGate-DJX3Is5d.mjs +136 -0
- package/dist/flockbayScreenshotGate-DkxU24cR.cjs +138 -0
- package/dist/index--o4BPz5o.cjs +10311 -0
- package/dist/index-CUp3juDS.mjs +10268 -0
- package/dist/index.cjs +43 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +40 -0
- package/dist/lib.cjs +33 -0
- package/dist/lib.d.cts +957 -0
- package/dist/lib.d.mts +957 -0
- package/dist/lib.mjs +23 -0
- package/dist/runCodex-D3eT-TvB.cjs +3449 -0
- package/dist/runCodex-o6PCbHQ7.mjs +3446 -0
- package/dist/runGemini-Bt0oEj_g.mjs +3183 -0
- package/dist/runGemini-CBxZp6I7.cjs +3185 -0
- package/dist/types-C-jnUdn_.cjs +4498 -0
- package/dist/types-DGd6ea2Z.mjs +4450 -0
- package/kits/kit.open_world/kit.json +59 -0
- package/package.json +130 -0
- package/scripts/claude_local_launcher.cjs +73 -0
- package/scripts/claude_remote_launcher.cjs +16 -0
- package/scripts/claude_version_utils.cjs +391 -0
- package/scripts/ripgrep_launcher.cjs +33 -0
- package/scripts/session_hook_forwarder.cjs +49 -0
- package/scripts/test-codex-abort-history.mjs +77 -0
- package/scripts/unpack-tools.cjs +222 -0
- package/tools/licenses/difftastic-LICENSE +21 -0
- package/tools/licenses/ripgrep-LICENSE +3 -0
- package/tools/unreal-mcp/UPSTREAM_VERSION.md +8 -0
- package/tools/unreal-mcp/upstream/Docs/README.md +8 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/README.md +7 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/actor_tools.md +184 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/blueprint_tools.md +268 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/editor_tools.md +104 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/node_tools.md +274 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Config/FilterPlugin.ini +8 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintCommands.cpp +1160 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintNodeCommands.cpp +924 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommonUtils.cpp +709 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPEditorCommands.cpp +896 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPProjectCommands.cpp +72 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPUMGCommands.cpp +544 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/MCPServerRunnable.cpp +321 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPBridge.cpp +419 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPModule.cpp +21 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintCommands.h +34 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintNodeCommands.h +27 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPCommonUtils.h +59 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPEditorCommands.h +40 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPProjectCommands.h +20 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPUMGCommands.h +82 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/MCPServerRunnable.h +34 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPBridge.h +64 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPModule.h +22 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/UnrealMCP.Build.cs +78 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/UnrealMCP.uplugin +36 -0
- package/tools/unreal-mcp/upstream/Python/README.md +40 -0
- package/tools/unreal-mcp/upstream/Python/pyproject.toml +22 -0
- package/tools/unreal-mcp/upstream/Python/scripts/actors/test_cube.py +203 -0
- package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_blueprints_with_different_components.py +497 -0
- package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_cube_blueprint.py +194 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_component_reference.py +267 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_create_bird_blueprint_with_input_and_camera.py +618 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_input_mapping.py +366 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_physics_variables.py +390 -0
- package/tools/unreal-mcp/upstream/Python/tools/blueprint_tools.py +420 -0
- package/tools/unreal-mcp/upstream/Python/tools/editor_tools.py +369 -0
- package/tools/unreal-mcp/upstream/Python/tools/node_tools.py +430 -0
- package/tools/unreal-mcp/upstream/Python/tools/project_tools.py +64 -0
- package/tools/unreal-mcp/upstream/Python/tools/umg_tools.py +333 -0
- package/tools/unreal-mcp/upstream/Python/unreal_mcp_server.py +398 -0
- package/tools/unreal-mcp/upstream/Python/uv.lock +521 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "CoreMinimal.h"
|
|
4
|
+
#include "Json.h"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Handles UMG (Widget Blueprint) related MCP commands
|
|
8
|
+
* Responsible for creating and modifying UMG Widget Blueprints,
|
|
9
|
+
* adding widget components, and managing widget instances in the viewport.
|
|
10
|
+
*/
|
|
11
|
+
class UNREALMCP_API FUnrealMCPUMGCommands
|
|
12
|
+
{
|
|
13
|
+
public:
|
|
14
|
+
FUnrealMCPUMGCommands();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Handle UMG-related commands
|
|
18
|
+
* @param CommandType - The type of command to handle
|
|
19
|
+
* @param Params - JSON parameters for the command
|
|
20
|
+
* @return JSON response with results or error
|
|
21
|
+
*/
|
|
22
|
+
TSharedPtr<FJsonObject> HandleCommand(const FString& CommandType, const TSharedPtr<FJsonObject>& Params);
|
|
23
|
+
|
|
24
|
+
private:
|
|
25
|
+
/**
|
|
26
|
+
* Create a new UMG Widget Blueprint
|
|
27
|
+
* @param Params - Must include "name" for the blueprint name
|
|
28
|
+
* @return JSON response with the created blueprint details
|
|
29
|
+
*/
|
|
30
|
+
TSharedPtr<FJsonObject> HandleCreateUMGWidgetBlueprint(const TSharedPtr<FJsonObject>& Params);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Add a Text Block widget to a UMG Widget Blueprint
|
|
34
|
+
* @param Params - Must include:
|
|
35
|
+
* "blueprint_name" - Name of the target Widget Blueprint
|
|
36
|
+
* "widget_name" - Name for the new Text Block
|
|
37
|
+
* "text" - Initial text content (optional)
|
|
38
|
+
* "position" - [X, Y] position in the canvas (optional)
|
|
39
|
+
* @return JSON response with the added widget details
|
|
40
|
+
*/
|
|
41
|
+
TSharedPtr<FJsonObject> HandleAddTextBlockToWidget(const TSharedPtr<FJsonObject>& Params);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Add a widget instance to the game viewport
|
|
45
|
+
* @param Params - Must include:
|
|
46
|
+
* "blueprint_name" - Name of the Widget Blueprint to instantiate
|
|
47
|
+
* "z_order" - Z-order for widget display (optional)
|
|
48
|
+
* @return JSON response with the widget instance details
|
|
49
|
+
*/
|
|
50
|
+
TSharedPtr<FJsonObject> HandleAddWidgetToViewport(const TSharedPtr<FJsonObject>& Params);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Add a Button widget to a UMG Widget Blueprint
|
|
54
|
+
* @param Params - Must include:
|
|
55
|
+
* "blueprint_name" - Name of the target Widget Blueprint
|
|
56
|
+
* "widget_name" - Name for the new Button
|
|
57
|
+
* "text" - Button text
|
|
58
|
+
* "position" - [X, Y] position in the canvas
|
|
59
|
+
* @return JSON response with the added widget details
|
|
60
|
+
*/
|
|
61
|
+
TSharedPtr<FJsonObject> HandleAddButtonToWidget(const TSharedPtr<FJsonObject>& Params);
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Bind an event to a widget (e.g. button click)
|
|
65
|
+
* @param Params - Must include:
|
|
66
|
+
* "blueprint_name" - Name of the target Widget Blueprint
|
|
67
|
+
* "widget_name" - Name of the widget to bind
|
|
68
|
+
* "event_name" - Name of the event to bind
|
|
69
|
+
* @return JSON response with the binding details
|
|
70
|
+
*/
|
|
71
|
+
TSharedPtr<FJsonObject> HandleBindWidgetEvent(const TSharedPtr<FJsonObject>& Params);
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Set up text block binding for dynamic updates
|
|
75
|
+
* @param Params - Must include:
|
|
76
|
+
* "blueprint_name" - Name of the target Widget Blueprint
|
|
77
|
+
* "widget_name" - Name of the widget to bind
|
|
78
|
+
* "binding_name" - Name of the binding to set up
|
|
79
|
+
* @return JSON response with the binding details
|
|
80
|
+
*/
|
|
81
|
+
TSharedPtr<FJsonObject> HandleSetTextBlockBinding(const TSharedPtr<FJsonObject>& Params);
|
|
82
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "CoreMinimal.h"
|
|
4
|
+
#include "HAL/Runnable.h"
|
|
5
|
+
#include "Sockets.h"
|
|
6
|
+
#include "Interfaces/IPv4/IPv4Address.h"
|
|
7
|
+
|
|
8
|
+
class UUnrealMCPBridge;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Runnable class for the MCP server thread
|
|
12
|
+
*/
|
|
13
|
+
class FMCPServerRunnable : public FRunnable
|
|
14
|
+
{
|
|
15
|
+
public:
|
|
16
|
+
FMCPServerRunnable(UUnrealMCPBridge* InBridge, TSharedPtr<FSocket> InListenerSocket);
|
|
17
|
+
virtual ~FMCPServerRunnable();
|
|
18
|
+
|
|
19
|
+
// FRunnable interface
|
|
20
|
+
virtual bool Init() override;
|
|
21
|
+
virtual uint32 Run() override;
|
|
22
|
+
virtual void Stop() override;
|
|
23
|
+
virtual void Exit() override;
|
|
24
|
+
|
|
25
|
+
protected:
|
|
26
|
+
void HandleClientConnection(TSharedPtr<FSocket> ClientSocket);
|
|
27
|
+
void ProcessMessage(TSharedPtr<FSocket> Client, const FString& Message);
|
|
28
|
+
|
|
29
|
+
private:
|
|
30
|
+
UUnrealMCPBridge* Bridge;
|
|
31
|
+
TSharedPtr<FSocket> ListenerSocket;
|
|
32
|
+
TSharedPtr<FSocket> ClientSocket;
|
|
33
|
+
bool bRunning;
|
|
34
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "CoreMinimal.h"
|
|
4
|
+
#include "EditorSubsystem.h"
|
|
5
|
+
#include "Sockets.h"
|
|
6
|
+
#include "SocketSubsystem.h"
|
|
7
|
+
#include "Http.h"
|
|
8
|
+
#include "Json.h"
|
|
9
|
+
#include "Interfaces/IPv4/IPv4Address.h"
|
|
10
|
+
#include "Interfaces/IPv4/IPv4Endpoint.h"
|
|
11
|
+
#include "Commands/UnrealMCPEditorCommands.h"
|
|
12
|
+
#include "Commands/UnrealMCPBlueprintCommands.h"
|
|
13
|
+
#include "Commands/UnrealMCPBlueprintNodeCommands.h"
|
|
14
|
+
#include "Commands/UnrealMCPProjectCommands.h"
|
|
15
|
+
#include "Commands/UnrealMCPUMGCommands.h"
|
|
16
|
+
#include "UnrealMCPBridge.generated.h"
|
|
17
|
+
|
|
18
|
+
class FMCPServerRunnable;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Editor subsystem for MCP Bridge
|
|
22
|
+
* Handles communication between external tools and the Unreal Editor
|
|
23
|
+
* through a TCP socket connection. Commands are received as JSON and
|
|
24
|
+
* routed to appropriate command handlers.
|
|
25
|
+
*/
|
|
26
|
+
UCLASS()
|
|
27
|
+
class UNREALMCP_API UUnrealMCPBridge : public UEditorSubsystem
|
|
28
|
+
{
|
|
29
|
+
GENERATED_BODY()
|
|
30
|
+
|
|
31
|
+
public:
|
|
32
|
+
UUnrealMCPBridge();
|
|
33
|
+
virtual ~UUnrealMCPBridge();
|
|
34
|
+
|
|
35
|
+
// UEditorSubsystem implementation
|
|
36
|
+
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
|
37
|
+
virtual void Deinitialize() override;
|
|
38
|
+
|
|
39
|
+
// Server functions
|
|
40
|
+
void StartServer();
|
|
41
|
+
void StopServer();
|
|
42
|
+
bool IsRunning() const { return bIsRunning; }
|
|
43
|
+
|
|
44
|
+
// Command execution
|
|
45
|
+
FString ExecuteCommand(const FString& CommandType, const TSharedPtr<FJsonObject>& Params);
|
|
46
|
+
|
|
47
|
+
private:
|
|
48
|
+
// Server state
|
|
49
|
+
bool bIsRunning;
|
|
50
|
+
TSharedPtr<FSocket> ListenerSocket;
|
|
51
|
+
TSharedPtr<FSocket> ConnectionSocket;
|
|
52
|
+
FRunnableThread* ServerThread;
|
|
53
|
+
|
|
54
|
+
// Server configuration
|
|
55
|
+
FIPv4Address ServerAddress;
|
|
56
|
+
uint16 Port;
|
|
57
|
+
|
|
58
|
+
// Command handler instances
|
|
59
|
+
TSharedPtr<FUnrealMCPEditorCommands> EditorCommands;
|
|
60
|
+
TSharedPtr<FUnrealMCPBlueprintCommands> BlueprintCommands;
|
|
61
|
+
TSharedPtr<FUnrealMCPBlueprintNodeCommands> BlueprintNodeCommands;
|
|
62
|
+
TSharedPtr<FUnrealMCPProjectCommands> ProjectCommands;
|
|
63
|
+
TSharedPtr<FUnrealMCPUMGCommands> UMGCommands;
|
|
64
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "CoreMinimal.h"
|
|
4
|
+
#include "Modules/ModuleManager.h"
|
|
5
|
+
|
|
6
|
+
class FUnrealMCPModule : public IModuleInterface
|
|
7
|
+
{
|
|
8
|
+
public:
|
|
9
|
+
/** IModuleInterface implementation */
|
|
10
|
+
virtual void StartupModule() override;
|
|
11
|
+
virtual void ShutdownModule() override;
|
|
12
|
+
|
|
13
|
+
static inline FUnrealMCPModule& Get()
|
|
14
|
+
{
|
|
15
|
+
return FModuleManager::LoadModuleChecked<FUnrealMCPModule>("UnrealMCP");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static inline bool IsAvailable()
|
|
19
|
+
{
|
|
20
|
+
return FModuleManager::Get().IsModuleLoaded("UnrealMCP");
|
|
21
|
+
}
|
|
22
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
using UnrealBuildTool;
|
|
4
|
+
|
|
5
|
+
public class UnrealMCP : ModuleRules
|
|
6
|
+
{
|
|
7
|
+
public UnrealMCP(ReadOnlyTargetRules Target) : base(Target)
|
|
8
|
+
{
|
|
9
|
+
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
|
10
|
+
// Use IWYUSupport instead of the deprecated bEnforceIWYU in UE5.5
|
|
11
|
+
IWYUSupport = IWYUSupport.Full;
|
|
12
|
+
|
|
13
|
+
PublicIncludePaths.AddRange(
|
|
14
|
+
new string[] {
|
|
15
|
+
// ... add public include paths required here ...
|
|
16
|
+
}
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
PrivateIncludePaths.AddRange(
|
|
20
|
+
new string[] {
|
|
21
|
+
// ... add other private include paths required here ...
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
PublicDependencyModuleNames.AddRange(
|
|
26
|
+
new string[]
|
|
27
|
+
{
|
|
28
|
+
"Core",
|
|
29
|
+
"CoreUObject",
|
|
30
|
+
"Engine",
|
|
31
|
+
"InputCore",
|
|
32
|
+
"Networking",
|
|
33
|
+
"Sockets",
|
|
34
|
+
"HTTP",
|
|
35
|
+
"Json",
|
|
36
|
+
"JsonUtilities",
|
|
37
|
+
"DeveloperSettings"
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
PrivateDependencyModuleNames.AddRange(
|
|
42
|
+
new string[]
|
|
43
|
+
{
|
|
44
|
+
"UnrealEd",
|
|
45
|
+
"EditorScriptingUtilities",
|
|
46
|
+
"EditorSubsystem",
|
|
47
|
+
"Slate",
|
|
48
|
+
"SlateCore",
|
|
49
|
+
"UMG",
|
|
50
|
+
"Kismet",
|
|
51
|
+
"KismetCompiler",
|
|
52
|
+
"BlueprintGraph",
|
|
53
|
+
"Projects",
|
|
54
|
+
"AssetRegistry"
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
if (Target.bBuildEditor == true)
|
|
59
|
+
{
|
|
60
|
+
PrivateDependencyModuleNames.AddRange(
|
|
61
|
+
new string[]
|
|
62
|
+
{
|
|
63
|
+
"PropertyEditor", // For widget property editing
|
|
64
|
+
"ToolMenus", // For editor UI
|
|
65
|
+
"BlueprintEditorLibrary", // For Blueprint utilities
|
|
66
|
+
"UMGEditor" // For WidgetBlueprint.h and other UMG editor functionality
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
DynamicallyLoadedModuleNames.AddRange(
|
|
72
|
+
new string[]
|
|
73
|
+
{
|
|
74
|
+
// ... add any modules that your module loads dynamically here ...
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"FileVersion": 3,
|
|
3
|
+
"Version": 1,
|
|
4
|
+
"VersionName": "1.0",
|
|
5
|
+
"FriendlyName": "Flockbay MCP",
|
|
6
|
+
"Description": "Flockbay bridge for Unreal Editor via Model Context Protocol (MCP)",
|
|
7
|
+
"Category": "Editor",
|
|
8
|
+
"CreatedBy": "Respaced Inc.",
|
|
9
|
+
"CreatedByURL": "",
|
|
10
|
+
"DocsURL": "",
|
|
11
|
+
"MarketplaceURL": "",
|
|
12
|
+
"SupportURL": "",
|
|
13
|
+
"CanContainContent": true,
|
|
14
|
+
"IsBetaVersion": false,
|
|
15
|
+
"IsExperimentalVersion": false,
|
|
16
|
+
"EnabledByDefault": false,
|
|
17
|
+
"Installed": false,
|
|
18
|
+
"Modules": [
|
|
19
|
+
{
|
|
20
|
+
"Name": "UnrealMCP",
|
|
21
|
+
"Type": "Editor",
|
|
22
|
+
"LoadingPhase": "Default",
|
|
23
|
+
"WhitelistPlatforms": [
|
|
24
|
+
"Win64",
|
|
25
|
+
"Mac",
|
|
26
|
+
"Linux"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"Plugins": [
|
|
31
|
+
{
|
|
32
|
+
"Name": "EditorScriptingUtilities",
|
|
33
|
+
"Enabled": true
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Unreal MCP
|
|
2
|
+
|
|
3
|
+
Python bridge for interacting with Unreal Engine 5.5 using the Model Context Protocol (MCP).
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
1. Make sure Python 3.10+ is installed
|
|
8
|
+
2. Install `uv` if you haven't already:
|
|
9
|
+
```bash
|
|
10
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
11
|
+
```
|
|
12
|
+
3. Create and activate a virtual environment:
|
|
13
|
+
```bash
|
|
14
|
+
uv venv
|
|
15
|
+
source .venv/bin/activate # On Unix/macOS
|
|
16
|
+
# or
|
|
17
|
+
.venv\Scripts\activate # On Windows
|
|
18
|
+
```
|
|
19
|
+
4. Install dependencies:
|
|
20
|
+
```bash
|
|
21
|
+
uv pip install -e .
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
At this point, you can configure your MCP Client (Claude Desktop, Cursor, Windsurf) to use the Unreal MCP Server as per the [Configuring your MCP Client](README.md#configuring-your-mcp-client).
|
|
25
|
+
|
|
26
|
+
## Testing Scripts
|
|
27
|
+
|
|
28
|
+
There are several scripts in the [scripts](./scripts) folder. They are useful for testing the tools and the Unreal Bridge via a direct connection. This means that you do not need to have an MCP Server running.
|
|
29
|
+
|
|
30
|
+
You should make sure you have installed dependencies and/or are running in the `uv` virtual environment in order for the scripts to work.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Troubleshooting
|
|
34
|
+
|
|
35
|
+
- Make sure Unreal Engine editor is loaded loaded and running before running the server.
|
|
36
|
+
- Check logs in `unreal_mcp.log` for detailed error information
|
|
37
|
+
|
|
38
|
+
## Development
|
|
39
|
+
|
|
40
|
+
To add new tools, modify the `UnrealMCPBridge.py` file to add new command handlers, and update the `unreal_mcp_server.py` file to expose them through the HTTP API.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "unreal-mcp"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Unreal MCP Server: A server for Unreal Engine integration via the Model Context Protocol (MCP)."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"mcp[cli]>=1.4.1",
|
|
9
|
+
"fastmcp>=0.2.0",
|
|
10
|
+
"uvicorn",
|
|
11
|
+
"fastapi",
|
|
12
|
+
"pydantic>=2.6.1",
|
|
13
|
+
"requests"
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[build-system]
|
|
17
|
+
requires = ["setuptools>=42", "wheel"]
|
|
18
|
+
build-backend = "setuptools.build_meta"
|
|
19
|
+
|
|
20
|
+
[tool.setuptools]
|
|
21
|
+
# The main server script is a single-file module
|
|
22
|
+
py-modules = ["unreal_mcp_server"]
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Test script for creating and manipulating actors in Unreal Engine via MCP.
|
|
4
|
+
|
|
5
|
+
This script demonstrates the basic actor manipulation capabilities of the MCP system:
|
|
6
|
+
- Creating actors with specific names and transforms
|
|
7
|
+
- Getting actor properties
|
|
8
|
+
- Modifying actor transforms
|
|
9
|
+
- Error handling and validation
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import sys
|
|
13
|
+
import os
|
|
14
|
+
import time
|
|
15
|
+
import socket
|
|
16
|
+
import json
|
|
17
|
+
import logging
|
|
18
|
+
from typing import Dict, Any, Optional
|
|
19
|
+
|
|
20
|
+
# Add the parent directory to the path so we can import the server module
|
|
21
|
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
22
|
+
|
|
23
|
+
# Set up logging
|
|
24
|
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
25
|
+
logger = logging.getLogger("TestCube")
|
|
26
|
+
|
|
27
|
+
def send_command(command: str, params: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
28
|
+
"""Send a command to the Unreal MCP server and get the response.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
command: The command type to send
|
|
32
|
+
params: Dictionary of parameters for the command
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Optional[Dict[str, Any]]: The response from the server, or None if there was an error
|
|
36
|
+
"""
|
|
37
|
+
try:
|
|
38
|
+
# Create new socket connection
|
|
39
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
40
|
+
sock.connect(("127.0.0.1", 55557))
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
# Create command object
|
|
44
|
+
command_obj = {
|
|
45
|
+
"type": command,
|
|
46
|
+
"params": params
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# Convert to JSON and send
|
|
50
|
+
command_json = json.dumps(command_obj)
|
|
51
|
+
logger.info(f"Sending command: {command_json}")
|
|
52
|
+
sock.sendall(command_json.encode('utf-8'))
|
|
53
|
+
|
|
54
|
+
# Receive response
|
|
55
|
+
chunks = []
|
|
56
|
+
while True:
|
|
57
|
+
chunk = sock.recv(4096)
|
|
58
|
+
if not chunk:
|
|
59
|
+
break
|
|
60
|
+
chunks.append(chunk)
|
|
61
|
+
|
|
62
|
+
# Try parsing to see if we have a complete response
|
|
63
|
+
try:
|
|
64
|
+
data = b''.join(chunks)
|
|
65
|
+
json.loads(data.decode('utf-8'))
|
|
66
|
+
# If we can parse it, we have the complete response
|
|
67
|
+
break
|
|
68
|
+
except json.JSONDecodeError:
|
|
69
|
+
# Not a complete JSON object yet, continue receiving
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
# Parse response
|
|
73
|
+
data = b''.join(chunks)
|
|
74
|
+
response = json.loads(data.decode('utf-8'))
|
|
75
|
+
logger.info(f"Received response: {response}")
|
|
76
|
+
return response
|
|
77
|
+
|
|
78
|
+
finally:
|
|
79
|
+
# Always close the socket
|
|
80
|
+
sock.close()
|
|
81
|
+
|
|
82
|
+
except Exception as e:
|
|
83
|
+
logger.error(f"Error sending command: {e}")
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
def create_test_cube(name: str, location: list[float]) -> Optional[Dict[str, Any]]:
|
|
87
|
+
"""Create a test cube actor with the specified name and location.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
name: The name to give the cube actor
|
|
91
|
+
location: The [x, y, z] world location to spawn at
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
Optional[Dict[str, Any]]: The response from the create command, or None if failed
|
|
95
|
+
"""
|
|
96
|
+
cube_params = {
|
|
97
|
+
"name": name,
|
|
98
|
+
"type": "StaticMeshActor",
|
|
99
|
+
"location": location,
|
|
100
|
+
"rotation": [0.0, 0.0, 0.0],
|
|
101
|
+
"scale": [1.0, 1.0, 1.0]
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
response = send_command("create_actor", cube_params)
|
|
105
|
+
if not response or response.get("status") != "success":
|
|
106
|
+
logger.error(f"Failed to create cube: {response}")
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
logger.info(f"Created cube '{name}' successfully at location {location}")
|
|
110
|
+
return response
|
|
111
|
+
|
|
112
|
+
def get_actor_properties(name: str) -> Optional[Dict[str, Any]]:
|
|
113
|
+
"""Get the properties of an actor by name.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
name: The name of the actor to get properties for
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Optional[Dict[str, Any]]: The actor properties, or None if not found/error
|
|
120
|
+
"""
|
|
121
|
+
response = send_command("get_actor_properties", {"name": name})
|
|
122
|
+
if not response or response.get("status") != "success":
|
|
123
|
+
logger.error(f"Failed to get properties for actor '{name}': {response}")
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
logger.info(f"Got properties for actor '{name}' successfully")
|
|
127
|
+
return response
|
|
128
|
+
|
|
129
|
+
def set_actor_transform(
|
|
130
|
+
name: str,
|
|
131
|
+
location: Optional[list[float]] = None,
|
|
132
|
+
rotation: Optional[list[float]] = None,
|
|
133
|
+
scale: Optional[list[float]] = None
|
|
134
|
+
) -> Optional[Dict[str, Any]]:
|
|
135
|
+
"""Set the transform of an actor.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
name: The name of the actor to modify
|
|
139
|
+
location: Optional new [x, y, z] location
|
|
140
|
+
rotation: Optional new [pitch, yaw, roll] rotation in degrees
|
|
141
|
+
scale: Optional new [x, y, z] scale
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
Optional[Dict[str, Any]]: The updated actor properties, or None if failed
|
|
145
|
+
"""
|
|
146
|
+
transform_params = {"name": name}
|
|
147
|
+
if location is not None:
|
|
148
|
+
transform_params["location"] = location
|
|
149
|
+
if rotation is not None:
|
|
150
|
+
transform_params["rotation"] = rotation
|
|
151
|
+
if scale is not None:
|
|
152
|
+
transform_params["scale"] = scale
|
|
153
|
+
|
|
154
|
+
response = send_command("set_actor_transform", transform_params)
|
|
155
|
+
if not response or response.get("status") != "success":
|
|
156
|
+
logger.error(f"Failed to set transform for actor '{name}': {response}")
|
|
157
|
+
return None
|
|
158
|
+
|
|
159
|
+
logger.info(f"Modified transform for actor '{name}' successfully")
|
|
160
|
+
return response
|
|
161
|
+
|
|
162
|
+
def main():
|
|
163
|
+
"""Main function to test actor creation and manipulation."""
|
|
164
|
+
try:
|
|
165
|
+
# Create first test cube
|
|
166
|
+
cube1_name = "TestCube_001"
|
|
167
|
+
cube1 = create_test_cube(cube1_name, [0.0, 0.0, 100.0])
|
|
168
|
+
if not cube1:
|
|
169
|
+
logger.error("Failed to create first test cube")
|
|
170
|
+
return
|
|
171
|
+
|
|
172
|
+
# Get its properties to verify creation
|
|
173
|
+
props = get_actor_properties(cube1_name)
|
|
174
|
+
if not props:
|
|
175
|
+
logger.error("Failed to verify first test cube properties")
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
# Modify its transform
|
|
179
|
+
result = set_actor_transform(
|
|
180
|
+
cube1_name,
|
|
181
|
+
location=[0.0, 0.0, 200.0],
|
|
182
|
+
rotation=[0.0, 45.0, 0.0],
|
|
183
|
+
scale=[2.0, 2.0, 2.0]
|
|
184
|
+
)
|
|
185
|
+
if not result:
|
|
186
|
+
logger.error("Failed to modify first test cube transform")
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
# Create a second test cube at a different location
|
|
190
|
+
cube2_name = "TestCube_002"
|
|
191
|
+
cube2 = create_test_cube(cube2_name, [100.0, 100.0, 100.0])
|
|
192
|
+
if not cube2:
|
|
193
|
+
logger.error("Failed to create second test cube")
|
|
194
|
+
return
|
|
195
|
+
|
|
196
|
+
logger.info("All test operations completed successfully!")
|
|
197
|
+
|
|
198
|
+
except Exception as e:
|
|
199
|
+
logger.error(f"Error in main: {e}")
|
|
200
|
+
sys.exit(1)
|
|
201
|
+
|
|
202
|
+
if __name__ == "__main__":
|
|
203
|
+
main()
|