| name | ue-coding-workflow |
| description | This skill should be used when working with Unreal Engine C++ code changes, compiling the project, handling build errors, or adding new features to the MCP plugin. Trigger when the user asks to add new UE functionality, fix compilation errors, or modify C++ code. |
UE C++ Coding & Compilation Workflow
Compilation Commands
# Build the project
cd d:\CodeBuddy\rendering-mcp
powershell -ExecutionPolicy Bypass -File Build.ps1
Build logs are saved to build_logs/build_YYYYMMDD_HHMMSS.log.
Common Compilation Issues
1. DLL Locked by UE Editor
Error:
fatal error LNK1104: cannot open file 'UnrealEditor-UnrealMCP.dll'
The process cannot access the file because it is being used by another process
Solution: Close UE Editor before compiling.
2. Header File Not Found
Error:
fatal error C1083: Cannot open include file: 'SomeHeader.h'
Solution:
- Search UE source for the header:
dir /s /b "E:\UE\UE_5.7\Engine\Source\*SomeHeader*.h"
- Find the module containing the header
- Add module to
UnrealMCP.Build.cs:
PublicDependencyModuleNames.AddRange(new string[] {
"Core", "CoreUObject", "Engine", "TheModuleYouNeed"
});
- For Internal APIs, add include path:
PublicIncludePaths.Add("Engine/Source/Runtime/SomeModule/Private");
3. API Method Not Found
Error:
error C2039: 'SomeMethod': is not a member of 'SomeClass'
Solution:
- Search UE source for alternative implementations
- Check if the method was renamed or moved in newer UE versions
- Use similar patterns from other code in the project
Design Principles
MCP Tool Design
-
Generic over Specific - One generic tool > multiple specific tools
- โ
Use
get_assets(asset_class="X")
- โ Don't create
get_X_assets() for each type
-
Reflection Driven - Handle any type via UE reflection
- Use
spawn_actor(actor_class) not spawn_light(), spawn_mesh()
-
Atomic Operations - Complete operation in one call
- Use
build_material_graph() not multiple add_node() + connect()
-
Batch Processing - Reduce round-trips with batch tools
Code Organization
mcps/unreal_render_mcp/tools/
โโโ __init__.py # Export all tools
โโโ material.py # Material operations
โโโ blueprint.py # Blueprint operations
โโโ actor.py # Actor operations
โโโ ...
plugins/unreal/UnrealMCP/RenderingMCP/Plugins/UnrealMCP/Source/UnrealMCP/
โโโ Public/Commands/
โ โโโ EpicUnrealMCP*Commands.h
โโโ Private/Commands/
โโโ EpicUnrealMCP*Commands.cpp
Adding New MCP Tool
Step 1: Python Tool Definition
Create or edit file in mcps/unreal_render_mcp/tools/:
@with_unreal_connection
def new_tool(param: str) -> Dict[str, Any]:
"""Tool description."""
return send_command("new_command", {"param": param})
Step 2: C++ Command Handler
Add to header file:
TSharedPtr<FJsonObject> HandleNewCommand(const TSharedPtr<FJsonObject>& Params);
Add to cpp file:
else if (CommandType == TEXT("new_command"))
{
return HandleNewCommand(Params);
}
TSharedPtr<FJsonObject> FEpicUnrealMCP*Commands::HandleNewCommand(const TSharedPtr<FJsonObject>& Params)
{
return ResultObj;
}
Step 3: Register Tool
In server.py:
from tools import new_tool
mcp.tool()(new_tool)
In tools/__init__.py:
from module import new_tool
__all__ = [..., "new_tool"]
UE Source Reference
- UE Source Location:
E:\UE\UE_5.7
- API Headers:
Engine/Source/Runtime/*/Public/
- Internal Headers:
Engine/Source/Runtime/*/Private/
After Adding New Feature
-
Compile and Verify
# Step 1: Compile
cd d:\CodeBuddy\rendering-mcp
powershell -ExecutionPolicy Bypass -File Build.ps1
# Step 2: Start UE Editor (user can help with this)
# The UE project is at: plugins/unreal/UnrealMCP/RenderingMCP/RenderingMCP.uproject
# Step 3: Test MCP tool immediately
# Use mcp_call_tool to verify the new functionality works
-
Update Documentation
- Update this skill if new patterns emerge
- Update project rules if new conventions established
- Document any UE version-specific quirks
-
Update Related Skills
- If adding Niagara features โ update
ue-niagara-workflow
- If adding Material features โ update
ue-material-workflow
- If adding Rendering features โ update
ue-rendering-pipeline
Common UE 5.7 API Patterns
Accessing Private Properties via Reflection
When a class uses UCLASS(MinimalAPI), getter methods may not be exported. Use reflection:
if (FStrProperty* Prop = CastField<FStrProperty>(Obj->GetClass()->FindPropertyByName(TEXT("PrivateProperty"))))
{
FString Value = Prop->GetPropertyValue_InContainer(Obj);
}
Enum to String Conversion
UEnum* MyEnum = StaticEnum<EMyEnumType>();
if (MyEnum)
{
FString EnumName = MyEnum->GetNameStringByValue((int64)EnumValue);
}
Inheritance in Cast Checks
Always check derived classes before base classes:
if (UNiagaraNodeFunctionCall* FuncNode = Cast<UNiagaraNodeFunctionCall>(Node))
{ ... }
else if (UNiagaraNodeCustomHlsl* HlslNode = Cast<UNiagaraNodeCustomHlsl>(Node))
{ ... }
if (UNiagaraNodeCustomHlsl* HlslNode = Cast<UNiagaraNodeCustomHlsl>(Node))
{ ... }
else if (UNiagaraNodeFunctionCall* FuncNode = Cast<UNiagaraNodeFunctionCall>(Node))
{ ... }