UnrealMCP — AI Bridge for Unreal Engine 5
Control the Unreal Engine 5 editor from any MCP client: Blueprints, materials, Niagara.
Open source Open in the app JSON README (API)
About
Control the Unreal Engine 5 editor from any MCP client: Blueprints, materials, Niagara.
Details
- Kind
- MCP servers
- Topic
- Media, design & games
- Publisher
- aadeshrao123
- Origin
- official
- Category
- ferramentas
- Transport
- local
- Version
- 1.3.1
- Stars
- 38
- Forks
- 8
- Last push
- 2026-08-06T06:36:48Z
- Repository state
- ativo
- Language
- C++
- License
- MPL-2.0
- Added
- 2026-08-29 03:02:21
- Updated
- 2026-08-29 03:02:21
- Origin id
io.github.aadeshrao123/unreal-mcp
README
<!-- mcp-name: io.github.aadeshrao123/unreal-mcp -->
# UnrealMCP — AI Bridge for Unreal Engine 5
**Control the Unreal Engine 5 editor from Claude Code, Cursor, Windsurf, or any MCP client.**
Build materials, wire Blueprint graphs, author Niagara systems, spawn actors, edit data tables and
profile performance, all by asking for it. **288 commands across 15 categories**, no leaving your
terminal.
[](LICENSE)
[](https://www.unrealengine.com/)
[](https://modelcontextprotocol.io/)
[](https://codefizz.dev/?utm_source=github&utm_medium=readme&utm_campaign=community_badge)
> ### This is the community edition
>
> It is **stable and feature complete for what it covers**. It is not abandoned, and it is not in
> active development either: new subsystem work now goes into
> **[CodeFizz Editor Agent](https://codefizz.dev/?utm_source=github&utm_medium=readme&utm_campaign=community_notice)**,
> the maintained commercial build. Everything here keeps working, issues still get read, and the
> MIT licence is permanent.
>
> If you want Control Rig, PCG, Sequencer, Mutable, Procedural Vegetation, audio and MetaSounds,
> Behavior Trees and EQS, or packaged binaries for UE 5.6 / 5.7 / 5.8, that lives in Pro.
---
## Community edition vs Pro
| | **Community** (this repo) | **CodeFizz Editor Agent** (Pro) |
|---|---|---|
| **Commands** | 288 | **900+** |
| **Categories** | 15 | **28** |
| **Engine support** | Build it yourself | **5.6, 5.7, 5.8** |
| **Blueprints, Materials, Niagara, StateTree** | Yes | Yes, and deeper |
| **Control Rig, PCG, Sequencer** | No | Yes |
| **Mutable, Procedural Vegetation** | No | Yes |
| **Audio, MetaSounds, Sound Cues** | No | Yes |
| **Behavior Trees, EQS** | No | Yes |
| **Insights profiling** | Basic | Full trace analysis |
| **Install** | Clone, build, configure | One command, no compiler needed |
| **Updates** | Community pace | Shipped continuously |
| **Support** | GitHub issues | Priority, private Discord |
[**See the full command list →**](https://codefizz.dev/tools?utm_source=github&utm_medium=readme&utm_campaign=community_table)
· [**Docs**](https://codefizz.dev/docs?utm_source=github&utm_medium=readme&utm_campaign=community_table)
· [**3 day free trial**](https://codefizz.dev/account?utm_source=github&utm_medium=readme&utm_campaign=community_trial)
> **Already on UE 5.8?** Epic now ships a first-party MCP server in 5.8 (Experimental, localhost
> only). It is worth trying before you buy anything. This repo and Pro both also cover **5.6 and
> 5.7**, which Epic's does not.
---
## Two ways to use this repo
| | CLI | MCP Server |
|---|---|---|
| **Install** | `npm install -g unrealcli` | `pip install unrealmcp` |
| **Dependencies** | None (single binary) | Python 3.10+ |
| **Works with** | Claude Code (via Bash) | Claude Code, Cursor, Windsurf, VS Code, Gemini CLI, Rider, Zed, Amazon Q |
| **Protocol** | Direct TCP | MCP over stdio |
Both talk to the same C++ plugin inside the editor. Use whichever fits your workflow, or both.
---
## Quick Start
### Option A: CLI (Recommended for Claude Code)
```bash
# 1. Install
npm install -g unrealcli
# 2. Go to any UE5 project and install the plugin
cd YourProject/
ue-cli init
# 3. Open the editor, then verify
ue-cli health_check
```
That's it. No Python, no config files, no MCP setup.
### Option B: MCP Server (For Cursor, Windsurf, etc.)
```bash
# 1. Clone the plugin into your project
git clone https://github.com/aadeshrao123/Unreal-MCP.git Plugins/UnrealMCP
# 2. Install the Python MCP server
pip install unrealmcp
# 3. Add to your AI tool's config (see MCP Setup section below)
```
---
## How It Works
```
┌──────────────────────────────────────────┐
│ Unreal Engine 5 Editor │
│ │
│ C++ Plugin (UnrealMCPBridge) │
│ TCP server on localhost:55557 │
│ 288 commands: materials, blueprints, │
│ niagara, statetree, actors, data │
│ tables, profiling, and more │
└──────────────┬───────────────────────────┘
│ TCP/JSON
┌──────────────┴───────────────────────────┐
│ │
┌─────────┴─────────┐ ┌─────────┴──────────┐
│ CLI (ue-cli) │ │ MCP Server │
│ Go binary │ │ Python (unrealmcp)│
│ Direct TCP │ │ stdio → TCP │
│ │ │ │
│ Claude Code │ │ Cursor, Windsurf, │
│ (via Bash tool) │ │ VS Code, Rider... │
└───────────────────┘ └────────────────────┘
```
The C++ plugin runs inside the editor and exposes 288 commands over TCP. The CLI and MCP server are two different front doors to the same plugin.
---
## CLI Reference
### Installation
```bash
# From npm (recommended)
npm install -g unrealcli
# Or download binary directly from GitHub Releases
# https://github.com/aadeshrao123/Unreal-MCP/releases
```
**Platforms:** Windows (x64), macOS (Intel + Apple Silicon), Linux (x64 + ARM64)
### Setup
```bash
# Navigate to your UE5 project
cd MyProject/
# Install the C++ plugin (one-time)
ue-cli init
# → Creates Plugins/UnrealMCP/ with C++ source
# → Patches .uproject to enable the plugin
# → Open editor to compile, then you're ready
# Verify everything works
ue-cli doctor
```
### Usage
```bash
# Every command follows this pattern:
ue-cli <command> [--flag value]
# Examples:
ue-cli health_check
ue-cli find_assets --class-type material --path /Game
ue-cli spawn_actor --name MyCube --type StaticMeshActor --location "[0,0,100]"
ue-cli get_data_table_rows --data-table-path /Game/Data/DT_Items
ue-cli save_all
# For complex params, use --json:
ue-cli build_material_graph --json '{"material_path":"/Game/M_Test","nodes":[...],"connections":[...]}'
# Or pipe from stdin:
echo '{"material_path":"/Game/M_Test","nodes":[...]}' | ue-cli build_material_graph --json -
```
### Help & Discovery
```bash
# See all commands grouped by category
ue-cli --help
# See flags for a specific command
ue-cli find_assets --help
# Dump all commands with descriptions, flags, and examples (for AI assistants)
ue-cli list_commands
```
### Global Flags
| Flag | Description |
|------|-------------|
| `--port <int>` | TCP port override (default: auto-discover from port file) |
| `--timeout <int>` | Timeout in seconds (default: 30, large ops: 300) |
| `--json <string>` | Full params as JSON string (use `-` for stdin) |
| `--version` | Print version |
### Key Commands
#### Assets
```bash
ue-cli find_assets --class-type material --path /Game/Materials
ue-cli list_assets --path /Game --class-filter blueprint
ue-cli get_asset_properties --asset-path /Game/Materials/M_Base
ue-cli import_asset --source-file "C:/Art/texture.png" --destination-path /Game/Textures
ue-cli save_asset --asset-path /Game/Materials/M_Base
ue-cli save_all
```
#### Blueprints
```bash
ue-cli create_blueprint --name BP_MyActor --parent-class Actor
ue-cli add_component_to_blueprint --blueprint-path /Game/BP_MyActor --component-class StaticMeshComponent
ue-cli add_event_node --blueprint-name BP_MyActor --event-name BeginPlay
ue-cli compile_blueprint --blueprint-name BP_MyActor
ue-cli read_blueprint_content --blueprint-path /Game/BP_MyActor
```
#### Materials
```bash
ue-cli create_material --name M_Red --path /Game/Materials
ue-cli build_material_graph --material-path /Game/Materials/M_Red \
--nodes '[{"type":"Constant3Vector","pos_x":-400,"properties":{"Constant":"(R=1,G=0,B=0)"}}]' \
--connections '[{"from_node":0,"to_node":"material","to_pin":"BaseColor"}]'
ue-cli create_material_instance --parent-path /Game/Materials/M_Base --name MI_Red
```
#### Data Tables
```bash
ue-cli get_data_table_schema --data-table-path /Game/Data/DT_Items
ue-cli get_data_table_rows --data-table-path /Game/Data/DT_Items
ue-cli add_data_table_row --data-table-path /Game/Data/DT_Items --row-name CopperOre \
--data '{"DisplayName":"Copper Ore","StackSize":100}'
ue-cli update_data_table_row --data-table-path /Game/Data/DT_Items --row-name CopperOre \
--data '{"StackSize":200}'
```
#### Actors & Level
```bash
ue-cli get_actors_in_level
ue-cli spawn_actor --name MyCube --type StaticMeshActor --location "[0,0,100]"
ue-cli spawn_blueprint_actor --blueprint-path /Game/BP_MyActor --location "[500,0,0]"
ue-cli find_actors_by_name --pattern "Light"
ue-cli get_world_info
ue-cli take_screenshot
```
#### Performance Profiling
```bash
# Record → Stop → Analyze
ue-cli performance_start_trace --channels "cpu,gpu,frame"
# ... play the game ...
ue-cli performance_stop_trace
ue-cli performance_analyze_insight --query diagnose
ue-cli performance_analyze_insight --query flame --count 20
ue-cli performance_analyze_insight --query search --filter "ConveyorProcessor"
```
#### Enhanced Input
```bash
ue-cli create_input_action --asset-path /Game/Input/IA_Jump --value-type Boolean
ue-cli create_input_mapping_context --asset-path /Game/Input/IMC_Default
ue-cli add_key_mapping --context-path /Game/Input/IMC_Default --action-path /Game/Input/IA_Jump --key SpaceBar
```
#### Niagara VFX
```bash
# Create a system from an emitter template, then tweak it
ue-cli create_niagara_system --asset-path /Game/VFX/NS_Sparks \
--template "/Niagara/DefaultAssets/FX_Sparks.FX_Sparks"
ue-cli get_niagara_system_info --asset-path /Game/VFX/NS_Sparks
ue-cli set_niagara_module_input --asset-path /Game/VFX/NS_Sparks \
--emitter-name Sparks --stack SpawnStack \
--module-name "Spawn Rate" --input-name SpawnRate --value 250
ue-cli compile_niagara_system --asset-path /Game/VFX/NS_Sparks
# Spawn it in the level
ue-cli spawn_niagara_effect --asset-path /Game/VFX/NS_Sparks --location "[0,0,200]"
```
#### StateTree
```bash
# Create a StateTree, add a state with a task, compile
ue-cli create_statetree --asset-path /Game/AI/ST_Enemy
ue-cli add_statetree_state --asset-path /Game/AI/ST_Enemy --state-name Patrol
ue-cli add_statetree_task --asset-path /Game/AI/ST_Enemy \
--state-name Patrol --task-type "MassEnemyNestPatrolTask"
ue-cli add_statetree_transition --asset-path /Game/AI/ST_Enemy \
--from-state Patrol --trigger OnEvent --event-tag "Enemy.SeePlayer"
ue-cli compile_statetree --asset-path /Game/AI/ST_Enemy
```
#### Mass Config Traits (Surgical Editing)
```bash
# Modify a single trait property without touching the rest of the trait array
ue-cli get_mass_config_traits --asset-path /Game/Mass/Enemy_Config
ue-cli set_mass_config_trait_property --asset-path /Game/Mass/Enemy_Config \
--trait-class MassMovementTrait --property-name MaxSpeed --property-value 600
```
#### Widgets (UMG)
```bash
ue-cli get_widget_tree --widget-blueprint-path /Game/UI/WBP_HUD
ue-cli add_widget --widget-blueprint-path /Game/UI/WBP_HUD --widget-class TextBlock \
--parent-widget-name RootCanvas --widget-name TitleText \
--widget-properties '{"Text":"Hello World"}'
```
### Diagnostics
```bash
# Check entire setup
ue-cli doctor
# Output:
# [ok] Project MyProject/MyProject.uproject
# [ok] Plugin directory Plugins/UnrealMCP/ exists
# [ok] Plugin source Source/UnrealMCPBridge/ exists
# [ok] UProject entry UnrealMCP plugin listed and enabled
# [ok] Port file port 55557
# [ok] TCP connection Connected to 127.0.0.1:55557
# [ok] Health check Bridge is responsive
# All checks passed. ue-cli is ready to use.
```
---
## MCP Server Setup
For AI tools that use the Model Context Protocol (Cursor, Windsurf, VS Code, etc.).
### Requirements
- **Unreal Engine 5.7** (tested on 5.7, may work on earlier 5.x versions)
- **Python 3.10+**
- **UE5 Plugins** (enabled automatically by the `.uplugin`):
- `PythonScriptPlugin`
- `EditorScriptingUtilities`
- `EnhancedInput`
### Install
```bash
pip install unrealmcp
```
### Setup Script (Alternative to Manual Config)
The setup script installs the `unrealmcp` pip package and creates the MCP config for your AI tool automatically.
**Windows:**
```cmd
cd Plugins\UnrealMCP
install.bat
```
**macOS / Linux:**
```bash
cd Plugins/UnrealMCP
bash install.sh
```
The script asks where to create the MCP config:
| Scope | What it does | When to use |
|-------|-------------|-------------|
| **Project** | Creates config next to your `.uproject` | Only want UnrealMCP in this project |
| **Global** | Creates config in your user folder | Want UnrealMCP in all projects |
### Configure Your AI Tool
<details>
<summary><b>Claude Code</b> — <code>.mcp.json</code> (project root)</summary>
```json
{
"mcpServers": {
"unreal": {
"type": "stdio",
"command": "unrealmcp"
}
}
}
```
</details>
<details>
<summary><b>Cursor</b> — <code>.cursor/mcp.json</code></summary>
```json
{
"mcpServers": {
"unreal": {
"command": "unrealmcp"
}
}
}
```
</details>
<details>
<summary><b>VS Code / Copilot</b> — <code>.vscode/mcp.json</code></summary>
```json
{
"servers": {
"unreal": {
"command": "unrealmcp"
}
}
}
```
</details>
<details>
<summary><b>Windsurf</b> — <code>~/.codeium/windsurf/mcp_config.json</code></summary>
```json
{
"mcpServers": {
"unreal": {
"command": "unrealmcp"
}
}
}
```
</details>
<details>
<summary><b>Gemini CLI</b> — <code>.gemini/settings.json</code></summary>
```json
{
"mcpServers": {
"unreal": {
"command": "unrealmcp"
}
}
}
```
</details>
<details>
<summary><b>JetBrains / Rider</b> — <code>.junie/mcp/mcp.json</code></summary>
```json
{
"servers": [
{
"name": "unreal",
"command": "unrealmcp"
}
]
}
```
</details>
<details>
<summary><b>Zed</b> — <code>~/.config/zed/settings.json</code></summary>
```json
{
"context_servers": {
"unreal": {
"source": "custom",
"command": { "path": "unrealmcp" }
}
}
}
```
</details>
<details>
<summary><b>Amazon Q</b> — <code>.amazonq/mcp.json</code></summary>
```json
{
"mcpServers": {
"unreal": {
"command": "unrealmcp"
}
}
}
```
</details>
---
## All 288 Commands
| Category | Count | Highlights |
|----------|------:|-----------|
| [Core](#core-2) | 2 | health_check, execute_python |
| [Asset Management](#asset-management-16) | 16 | find/list/import/duplicate/rename/delete/save |
| [Blueprints](#blueprints-22) | 22 | create, compile, variables, functions, graph nodes |
| [Materials](#materials-35) | 35 | create, build_material_graph, material functions, Substrate |
| [Data Tables](#data-tables-8) | 8 | full CRUD on rows + schema introspection |
| [Data Assets](#data-assets-12) | 12 | data assets + **surgical Mass Config trait editing** |
| [Actors & Level](#actors--level-19) | 19 | spawn, transform, properties, screenshot |
| [Enhanced Input](#enhanced-input-21) | 21 | actions, mapping contexts, triggers, modifiers |
| [Widgets — UMG](#widgets--umg-11) | 11 | widget tree, add/move/rename, slot props |
| [**Niagara VFX**](#niagara-vfx-96) | **96** | systems, emitters, stack bindings (nested), scratch pad authoring, graph CRUD, DI member functions, source-menu discovery |
| [**StateTree**](#statetree-33-new) | **33** | states, tasks, evaluators, transitions, conditions, bindings |
| [Performance Profiling](#performance-profiling-3) | 3 | record .utrace + smart analysis (diagnose/spikes/flame) |
| [Debug](#debug-2) | 2 | token tracking, debug toggle |
### Core (2)
| Command | Description |
|---------|-------------|
| `health_check` | Verify the bridge is running |
| `execute_python` | Run arbitrary Python in the editor |
### Asset Management (16)
| Command | Description |
|---------|-------------|
| `find_assets` | Search Asset Registry by class/path/name |
| `list_assets` | List assets in a directory |
| `get_asset_info` | Asset metadata |
| `get_asset_properties` | All editable properties |
| `set_asset_property` | Set a property |
| `find_references` | Find dependents/dependencies |
| `import_asset` | Import external file (PNG, FBX, etc.) |
| `import_assets_batch` | Batch import |
| `duplicate_asset` | Copy to new location |
| `rename_asset` | Rename/move (auto-fix references) |
| `delete_asset` | Delete (checks references) |
| `save_asset` / `save_all` | Save dirty assets |
| `open_asset` | Open in editor |
| `sync_browser` | Navigate Content Browser |
| `get_selected_assets` | Currently selected assets |
### Blueprints (22)
| Command | Description |
|---------|-------------|
| `search_parent_classes` | Find valid parent classes |
| `create_blueprint` | Create from any parent class |
| `compile_blueprint` | Compile |
| `read_blueprint_content` | Full structure readout |
| `analyze_blueprint_graph` | Graph analysis |
| `add_component_to_blueprint` | Add component |
| `create/get/set_blueprint_variable` | Variable management |
| `set_blueprint_variable_properties` | Modify variable settings |
| `create/delete/rename_blueprint_function` | Function management |
| `add_function_input/output` | Function parameters |
| `get_blueprint_function_details` | Function inspection |
| `get/set_blueprint_class_defaults` | CDO properties |
| `add_blueprint_node` | Add graph node (23+ types) |
| `add_event_node` | Add event (BeginPlay, Tick, etc.) |
| `connect_blueprint_nodes` | Wire nodes together |
| `delete_blueprint_node` | Remove node |
| `set_blueprint_node_property` | Edit node properties |
### Materials (35)
| Command | Description |
|---------|-------------|
| `create_material` | Create with blend/shading mode |
| `create_material_instance` | Create with parameter overrides |
| `build_material_graph` | Build complete node graph atomically |
| `get_material_info` | Inspect properties/params/textures |
| `set_material_properties` | Bulk-set material properties |
| `add/delete/move/duplicate_material_expression` | Manage nodes |
| `connect_material_expressions` | Wire nodes |
| `set_material_expression_property` | Set node property |
| `disconnect_material_expression` | Break connection |
| `layout_material_expressions` | Auto-layout |
| `recompile_material` | Force recompile |
| `get_material_errors` | Compilation errors |
| `get/set_material_instance_parameter` | MI parameter overrides |
| `list_material_expression_types` | Discover node types |
| `get_expression_type_info` | Node pins & properties |
| `search_material_functions` | Find Material Functions |
| `validate_material_graph` | Diagnose issues |
| `trace_material_connection` | Trace data flow |
| `cleanup_material_graph` | Remove orphaned nodes |
| `add_material_comments` | Comment boxes |
| `create/get_material_function` | Material Function management |
| `build_material_function_graph` | Build MF graph |
| `add/set_material_function_input/output` | MF pins |
| `validate/cleanup_material_function` | MF diagnostics |
| `apply_material_to_actor/blueprint` | Apply materials |
| `get_available_materials` | List materials |
| `get_actor/blueprint_material_info` | Material slot info |
### Data Tables (8)
| Command | Description |
|---------|-------------|
| `get_data_table_schema` | Column names and types |
| `get_data_table_rows` / `get_data_table_row` | Read rows |
| `add_data_table_row` | Add with initial data |
| `update_data_table_row` | Partial update |
| `delete_data_table_row` | Delete row |
| `duplicate_data_table_row` | Copy row |
| `rename_data_table_row` | Rename row |
### Data Assets (12)
| Command | Description |
|---------|-------------|
| `create_data_asset` | Create any UDataAsset subclass |
| `get/set_data_asset_property(ies)` | Read/write properties (single or batch) |
| `list_data_assets` | Browse by path/class |
| `list_data_asset_classes` | Discover all loaded UDataAsset subclasses |
| `get_property_valid_types` | Valid dropdown values for a property slot |
| `search_class_paths` | Find class paths |
| `get_mass_config_traits` | Inspect all traits on a Mass Entity Config asset |
| `add_mass_config_trait` | Append a new trait to a Mass Config (non-destructive) |
| `set_mass_config_trait_property` | **Surgical** in-place edit of a single trait property — never replaces the Traits array |
| `remove_mass_config_trait` | Remove a single trait by index or class without affecting siblings |
### Actors & Level (19)
| Command | Description |
|---------|-------------|
| `spawn_actor` | Spawn built-in actor types |
| `spawn_blueprint_actor` | Spawn BP actor |
| `spawn_actor_from_class` | Spawn from class name |
| `get_actors_in_level` | List all actors |
| `find_actors_by_name` | Search by name pattern |
| `get_actor_properties` | Read actor properties |
| `set_actor_transform` | Set location/rotation/scale |
| `delete_actor` | Remove from level |
| `get_selected_actors` | Viewport selection |
| `get_world_info` | Level info |
| `set_static_mesh_properties` | Mesh assignment |
| `set_physics_properties` | Physics config |
| `set_mesh_material_color` | Material color |
| `apply_material_to_actor/blueprint` | Apply material |
| `get_actor/blueprint_material_info` | Material slots |
| `get_available_materials` | List materials |
| `take_screenshot` | Capture viewport |
### Enhanced Input (21)
| Command | Description |
|---------|-------------|
| `create_input_action` | Create UInputAction |
| `get/set_input_action_properties` | Action properties |
| `add/remove_input_action_trigger` | Action triggers |
| `add/remove_input_action_modifier` | Action modifiers |
| `list_input_actions` | Browse actions |
| `create_input_mapping_context` | Create UInputMappingContext |
| `get_input_mapping_context` | Read mappings |
| `add/remove/set_key_mapping` | Key bindings |
| `add/remove_mapping_trigger/modifier` | Per-mapping overrides |
| `list_input_mapping_contexts` | Browse contexts |
| `list_trigger_types` / `list_modifier_types` | Discover types |
| `list_input_keys` | Valid key names |
### Widgets — UMG (11)
| Command | Description |
|---------|-------------|
| `get_widget_tree` | Widget hierarchy |
| `add_widget` | Add to parent |
| `remove/move/rename/duplicate_widget` | Widget operations |
| `get/set_widget_properties` | Widget properties |
| `get/set_slot_properties` | Layout slot properties |
| `list_widget_types` | Available widget classes |
### Niagara VFX (96)
End-to-end Niagara authoring — read the full stack, mutate any binding (top-level or nested), author scratch-pad dynamic inputs from scratch, spawn arbitrary graph nodes including data-interface member functions, and discover every valid option the editor's dropdowns expose. Built on Niagara's exported ViewModel / Stack Graph APIs with safe replication of non-exported helpers.
#### Systems
| Command | Description |
|---------|-------------|
| `create_niagara_system` | Create from emitter template or empty |
| `get_niagara_system_info` | System metadata, emitters, parameters |
| `list_niagara_systems` | Browse Niagara systems by path |
| `delete_niagara_system` | Delete a system |
| `compile_niagara_system` | Force recompile |
| `set_niagara_system_property` | Set top-level system property |
| `get_niagara_system_errors` | Compilation errors / warnings |
| `get_niagara_particle_stats` | Per-emitter particle stats |
| `get/set_niagara_playback_range` | Preview playback range |
#### Emitters
| Command | Description |
|---------|-------------|
| `get_niagara_emitters` | List emitters in a system |
| `add_niagara_emitter` | Add from template |
| `remove_niagara_emitter` | Remove an emitter |
| `duplicate_niagara_emitter` | Copy emitter with new name |
| `reorder_niagara_emitter` | Change emitter index |
| `set_niagara_emitter_property` | Set emitter property |
| `get_niagara_emitter_attributes` | Particle attributes (Position, Velocity, etc.) |
#### Modules (Spawn / Update / Render stacks)
| Command | Description |
|---------|-------------|
| `get_niagara_modules` | List modules in any stack |
| `add_niagara_module` | Add module from script asset |
| `remove_niagara_module` | Remove a module |
| `set_niagara_module_enabled` | Enable/disable a module |
| `reorder_niagara_module` | Reorder within stack |
| `get_niagara_module_inputs` | Inspect module inputs with current values |
| `set_niagara_module_input` | Set literal value (auto-routes Module.* inputs to rapid-iteration; supports nested dot-paths like `"Spawn Count.int32001"`) |
| `set_niagara_dynamic_input` | Replace input with a dynamic input function (nested-path aware) |
| `set_niagara_curve` | Set curve points on a curve input |
| `get_niagara_module_versions` | List script versions |
#### Stack Input Binding Loop
| Command | Description |
|---------|-------------|
| `get_niagara_module_input_binding` | Resolve mode (Default/Local/Linked/Dynamic/Data/Expression) + target + **recursive children** for every input in one call |
| `clear_niagara_module_input` | Reset an input (or nested path) to default — equivalent to "Reset to Default" in the stack UI |
| `list_niagara_input_source_menu` | Reproduces the editor's source dropdown — engine dynamic-input assets + scratch-pad DIs + link parameters grouped by namespace |
#### Parameters & Bindings
| Command | Description |
|---------|-------------|
| `get_niagara_user_parameters` | List User-namespace parameters |
| `add_niagara_user_parameter` | Add a User parameter |
| `set_niagara_user_parameter` | Set a User parameter value |
| `remove_niagara_user_parameter` | Remove a User parameter |
| `link_niagara_parameter` | Bind module input to a parameter (supports nested dot-paths) |
| `get_niagara_rapid_iteration_parameters` | RI param introspection |
| `set_niagara_rapid_iteration_parameter` | Set RI param value |
| `list_niagara_available_parameters` | Enumerate well-known + user + scratch-pad-scoped parameters |
#### Renderers
| Command | Description |
|---------|-------------|
| `add_niagara_renderer` | Add Sprite/Mesh/Ribbon/Light renderer |
| `remove_niagara_renderer` | Remove a renderer |
| `get_niagara_renderer_info` | Renderer summary with per-binding detail (binding_name + bound_variable + type + dataset_variable) |
| `get_niagara_renderer_properties` | Full renderer property dump |
| `set_niagara_renderer_property` | Set renderer property |
| `set_niagara_renderer_binding` | Bind renderer attribute to particle data |
#### Scratch Pad — CRUD & Apply
| Command | Description |
|---------|-------------|
| `create_niagara_scratch_pad_module` | Create per-emitter scratch module (module / dynamic_input / function) |
| `list_niagara_scratch_pad_modules` | List scratch pads on a system |
| `duplicate_niagara_scratch_pad_module` | Duplicate with new name |
| `rename_niagara_scratch_pad_module` | Rename in-place |
| `delete_niagara_scratch_pad_module` | Remove from system |
| `apply_niagara_scratch_pad` | Commit edit-copy → asset (Apply button) |
| `apply_and_save_niagara_scratch_pad` | Apply + save asset (Apply & Save button) |
| `create_niagara_module_asset` | Create reusable standalone Niagara Module Script asset |
#### Script Properties (Details Panel)
| Command | Description |
|---------|-------------|
| `get_niagara_script_properties` | Read Category, Description, Keywords, ModuleUsageBitmask, ProvidedDependencies, RequiredDependencies, LibraryVisibility, bDeprecated, bExperimental, NumericOutputTypeSelectionMode, ScriptMetaData, ConversionUtility |
| `set_niagara_script_properties` | Batch-set any subset (supports `TArray<FName>` like ProvidedDependencies and `TArray<FNiagaraModuleDependency>`) |
#### Script Parameters (Input / Output)
| Command | Description |
|---------|-------------|
| `list_niagara_script_parameters` | Inputs + outputs on a scratch pad / standalone script |
| `add_niagara_script_parameter` | Add input or output parameter with any registered type (incl. data interfaces) |
| `remove_niagara_script_parameter` | Remove — **cascades to Map Get / Map Set pin cleanup automatically** |
| `rename_niagara_script_parameter` | Rename across asset + edit-copy graphs |
#### Graph Introspection
| Command | Description |
|---------|-------------|
| `get_niagara_graph_nodes` | List every node with `verbosity` (summary/connections/full) + `type_filter` + `name_filter`. Three resolver modes: scratch pad, emitter stack graph, standalone script |
| `get_niagara_node_info` | Deep single-node inspect by `node_index` / `node_class` / `node_id` with pin layout, links, and type-specific fields (`op_name`, `function_script`, `hlsl_preview`, `input_name`/type) |
| `trace_niagara_connection` | BFS upstream/downstream with `pin_name` filter — see the dependency chain without dumping the whole graph |
| `validate_niagara_graph` | Classify orphaned / dead-end / missing-input nodes (skips `+Add` placeholders) |
#### Graph Node CRUD
| Command | Description |
|---------|-------------|
| `add_niagara_graph_node` | Spawn Op / FunctionCall / **DataInterfaceFunction** / ParameterMapGet / ParameterMapSet / Reroute / Input node. DI member functions (e.g. `Array.Length`) use `UNiagaraDataInterface::GetFunctionSignatures` — same path as the right-click "Functions" submenu |
| `delete_niagara_graph_node` | Delete by index or GUID, mirrors on asset + edit-copy |
#### Pin Management
| Command | Description |
|---------|-------------|
| `add_niagara_map_get_pin` | Add a typed output pin to a Map Get (e.g. `Module.MyParam` as Vector) |
| `add_niagara_map_set_pin` | Add a typed input pin to a Map Set (e.g. `Particles.Velocity`) |
| `add_niagara_node_pin` | Add a pin to any UNiagaraNodeWithDynamicPins-derived node |
| `rename_niagara_node_pin` | Rename a pin on a dynamic-pin node |
| `remove_niagara_node_pin` | Remove a dynamic pin |
| `connect_niagara_pins` | Wire two pins with UEdGraphSchema_Niagara::TryCreateConnection validation |
| `disconnect_niagara_pins` | Break a pin connection |
#### Custom HLSL
| Command | Description |
|---------|-------------|
| `set_niagara_scratch_pad_hlsl` | Write HLSL source into the scratch pad's Custom HLSL node (creates pins as needed) |
| `add_niagara_custom_hlsl_input` | Add an input pin to a Custom HLSL node |
| `add_niagara_custom_hlsl_output` | Add an output pin to a Custom HLSL node |
| `rename_niagara_custom_hlsl_pin` | Rename a pin (also rewrites `{PinName}` references in the HLSL body) |
| `remove_niagara_custom_hlsl_pin` | Remove a pin |
#### Events & Simulation Stages
| Command | Description |
|---------|-------------|
| `add_niagara_event_handler` | Add event handler stage |
| `add_niagara_simulation_stage` | Add simulation stage |
| `get_niagara_event_handlers` | Inspect handlers on emitter |
#### Level Spawning
| Command | Description |
|---------|-------------|
| `spawn_niagara_effect` | Spawn at world location |
| `control_niagara_effect` | Activate / deactivate / restart |
| `add_niagara_component` | Add NiagaraComponent to a Blueprint |
| `get_niagara_actors` | Find spawned Niagara actors |
#### Discovery (zero-guess authoring)
| Command | Description |
|---------|-------------|
| `list_niagara_modules` | All available Niagara module scripts |
| `list_niagara_emitter_templates` | Emitter templates |
| `list_niagara_data_interfaces` | Available data interfaces (DI_*) |
| `list_niagara_data_interface_functions` | **Member functions on a DI class** (Array.Length, Array.Get, etc.) — pass result to `add_niagara_graph_node(node_type="DataInterfaceFunction")` |
| `list_niagara_parameter_types` | Parameter type registry |
| `list_niagara_node_types` | Spawnable node classes with pin schema |
| `get_niagara_node_type_info` | Pin schema for a node class or script asset |
| `search_niagara_functions` | Find Niagara script assets by usage + name |
| `get_niagara_schema_actions` | Full graph right-click menu — same source the editor uses. Returns `op_name` / `function_script` / `input_name` for direct use with `add_niagara_graph_node` |
| `describe_niagara_type` | Type query — `FNiagaraTypeRegistry` types + **UEnum / UScriptStruct reflection fallback** for script-property enums and custom types |
| `get_niagara_data_interface_schema` | Walk a DI class's editable property schema |
| `find_niagara_scratch_pad_usage` | Reverse lookup — where is this scratch pad referenced? |
| `resolve_niagara_built_in_dynamic_input` | AssetRegistry scan for engine-shipped DI scripts (no more hardcoded paths) |
### StateTree (33, NEW)
Read and author StateTree assets — states, tasks, evaluators, transitions, conditions, parameters, and bindings. Schema-aware: works with both `StateTreeSchemaBase` and Mass schema variants.
#### Reading
| Command | Description |
|---------|-------------|
| `get_statetree_info` | Asset summary (schema, states, evaluators) |
| `get_statetree_full_info` | Full recursive dump (states + tasks + transitions + bindings) |
| `get_statetree_states` | List all states (flat) |
| `get_statetree_state` | Single state details by ID/name |
| `get_statetree_node` | Inspect any node (task/evaluator/condition) |
| `get_statetree_evaluators` | Global evaluators |
| `get_statetree_global_tasks` | Global tasks |
| `get_statetree_parameters` | Tree parameters |
| `get_statetree_bindings` | All property bindings |
| `get_statetree_transition_targets` | Valid transition targets for a state |
| `search_statetree_nodes` | Search nodes by name / type |
#### Authoring
| Command | Description |
|---------|-------------|
| `create_statetree` | Create new StateTree asset |
| `set_statetree_schema` | Set schema (e.g. Mass schema) |
| `add_statetree_state` | Add a state (parent or root) |
| `add_statetree_task` | Add task to a state |
| `add_statetree_evaluator` | Add global evaluator |
| `add_statetree_global_task` | Add global task |
| `add_statetree_condition` | Add enter / transition condition |
| `add_statetree_transition` | Add transition (event / completed / delegate) |
| `add_statetree_parameter` | Add tree parameter |
| `add_statetree_binding` | Bind property between nodes |
| `compile_statetree` | Compile after edits |
#### Modification
| Command | Description |
|---------|-------------|
| `set_statetree_state_property` | Edit state property |
| `set_statetree_node_property` | Edit task / evaluator / condition property |
| `set_statetree_transition_property` | Edit transition property |
| `set_statetree_color` | Set state color |
#### Removal
| Command | Description |
|---------|-------------|
| `remove_statetree_state` | Remove a state |
| `remove_statetree_node` | Remove a task / evaluator / condition |
| `remove_statetree_transition` | Remove a transition |
| `remove_statetree_binding` | Remove a binding |
| `remove_statetree_parameter` | Remove a parameter |
#### Discovery
| Command | Description |
|---------|-------------|
| `list_statetree_node_types` | All available task / evaluator / condition types |
| `list_statetree_enum_values` | Enum values for property dropdowns |
### Performance Profiling (3)
| Command | Description |
|---------|-------------|
| `performance_start_trace` | Start recording .utrace |
| `performance_stop_trace` | Stop and auto-load |
| `performance_analyze_insight` | Smart analysis (diagnose, spikes, flame, hotpath, search, histogram, etc.) |
### Debug (2)
| Command | Description |
|---------|-------------|
| `set_mcp_debug` | Enable token tracking |
| `get_mcp_token_stats` | Token usage stats |
---
## Usage Examples
These work with both the CLI and MCP server. With the CLI, the AI calls `ue-cli` via Bash. With MCP, the AI calls tools directly.
### Create a Material
```
Create a red metallic material at /Game/Materials/M_RedMetal
with roughness 0.3 and metallic 1.0
```
The AI will call `create_material`, then `build_material_graph` to wire up constant nodes to Base Color, Metallic, and Roughness pins.
### Spawn Actors
```
Spawn 5 point lights in a circle around the origin at height 300
```
The AI will call `spawn_actor` with `actor_type: "PointLight"` five times with calculated positions.
### Blueprint Creation
```
Create a Blueprint actor called BP_HealthPickup based on Actor,
add a Sphere Collision component and a Static Mesh component,
set it up so on BeginOverlap it prints "Health Picked Up"
```
The AI will use `create_blueprint`, `add_component_to_blueprint`, `add_event_node`, `add_blueprint_node`, and `connect_blueprint_nodes`.
### Profile Performance
```
Start a performance trace, play for 10 seconds, stop it,
then diagnose the bottlenecks
```
The AI will call `performance_start_trace`, wait, `performance_stop_trace`, then `performance_analyze_insight` with `query: "diagnose"`.
### Data Table Management
```
Show me the schema of DT_Items, then add a new row called
"IronIngot" with StackSize 100
```
The AI will call `get_data_table_schema`, then `add_data_table_row` with the appropriate data.
---
## Configuration
### Custom Port
Add to `Config/DefaultEngine.ini`:
```ini
[UnrealMCP]
Port=55557
```
### Environment Variable
```bash
# Force a specific port (overrides port file)
set UNREAL_MCP_PORT=55560
```
### Multiple Editor Instances
Each editor picks a unique port automatically. The CLI and MCP server read the port from `Saved/UnrealMCP/port.txt`. Use `--port` flag or `UNREAL_MCP_PORT` env var to target a specific instance.
---
## Architecture
### Plugin Structure
```
Plugins/UnrealMCP/
├── UnrealMCP.uplugin # Plugin manifest
├── cli/ # Go CLI source (ue-cli)
│ ├── cmd/ # Command definitions (288 commands)
│ ├── internal/bridge/ # TCP client
│ ├── internal/project/ # Plugin embedding & project detection
│ └── npm/ # npm package wrapper
├── unrealmcp/ # Python MCP server
│ ├── _tcp_bridge.py # TCP communication
│ └── tools/ # Tool modules (one per category)
├── Source/UnrealMCPBridge/ # C++ editor plugin
│ ├── Public/ # Headers
│ └── Private/ # Implementation + command handlers
└── .github/workflows/release.yml # CI: builds + GitHub Release + npm publish
```
### Communication Protocol
TCP with length-prefix framing:
```
[4 bytes: big-endian payload length] [N bytes: UTF-8 JSON]
```
Request: `{"type": "command_name", "params": {...}}`
Response: `{"status": "success", "result": {...}}`
---
## Adding Custom Commands
### CLI Side (Go)
Add a `CommandSpec` to the appropriate `cmd/*.go` file:
```go
{
Name: "my_command",
Group: "mygroup",
Short: "What it does",
Long: "Detailed description.",
Example: "ue-cli my_command --param value",
Params: []ParamSpec{
{Name: "param", Type: "string", Required: true, Help: "Description"},
},
},
```
### MCP Side (Python)
Create a new file in `unrealmcp/tools/`:
```python
# unrealmcp/tools/my_tools.py
from unrealmcp._bridge import mcp
from unrealmcp._tcp_bridge import _call
@mcp.tool()
def my_command(param: str) -> str:
"""Description shown to the AI assistant."""
return _call("my_command", {"param": param})
```
Register it in `unrealmcp/tools/__init__.py`:
```python
from unrealmcp.tools import my_tools # noqa: F401
```
### C++ Side
Add a command handler in `Source/UnrealMCPBridge/Private/Commands/` and register it in `ExecuteCommand()`.
---
## Supported AI Tools
| Tool | Interface | Config File | Status |
|------|-----------|------------|--------|
| **Claude Code** | CLI or MCP | Bash (CLI) / `.mcp.json` (MCP) | Tested |
| **Cursor** | MCP | `.cursor/mcp.json` | Tested |
| **VS Code / Copilot** | MCP | `.vscode/mcp.json` | Supported |
| **Windsurf** | MCP | `~/.codeium/windsurf/mcp_config.json` | Supported |
| **Gemini CLI** | MCP | `.gemini/settings.json` | Supported |
| **JetBrains / Rider** | MCP | `.junie/mcp/mcp.json` | Supported |
| **Zed** | MCP | `~/.config/zed/settings.json` | Supported |
| **Amazon Q** | MCP | `.amazonq/mcp.json` | Supported |
---
## Troubleshooting
| Problem | Solution |
|---------|----------|
| "Connection refused" | Is the UE5 editor running? Check Output Log for `MCP Bridge initialized on port XXXXX` |
| `ue-cli doctor` shows port file missing | Editor hasn't started yet, or check `Saved/UnrealMCP/port.txt` |
| Commands timeout | Large operations (profiling, complex graphs) have 300s timeout. Use `--timeout 600` to increase |
| Multiple editors | Use `--port <num>` or `UNREAL_MCP_PORT` env var to target a specific instance |
| Plugin not compiling | Ensure `PythonScriptPlugin`, `EditorScriptingUtilities`, `EnhancedInput` are enabled |
| Python import errors | Run `pip install fastmcp requests` — make sure the Python on your PATH matches your AI tool's |
| Plugin not loading | Verify `UnrealMCP.uplugin` has `"Type": "Editor"` and required plugins are available in your engine build |
---
## Releases & Distribution
| Channel | Command |
|---------|---------|
| **npm** | `npm install -g unrealcli` |
| **GitHub Releases** | [Download binaries](https://github.com/aadeshrao123/Unreal-MCP/releases) |
| **pip** (MCP only) | `pip install unrealmcp` |
Releases are automated via GitHub Actions. Push a tag to trigger:
```bash
git tag v1.2.2 && git push origin v1.2.2
# → Builds 5 platform binaries
# → Creates GitHub Release
# → Publishes to npm + PyPI
```
---
## Contributing
- **Bug?** [Open an issue](https://github.com/aadeshrao123/Unreal-MCP/issues/new)
- **Feature idea?** [Open an issue](https://github.com/aadeshrao123/Unreal-MCP/issues/new)
- **Code?** [Fork](https://github.com/aadeshrao123/Unreal-MCP/fork), make changes, open a PR
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
---
## Enterprise & Studio Integration
Need Unreal MCP integrated into your studio's production pipeline? I work directly with game studios to build custom AI-assisted workflows on top of this tool.
**What I offer:**
- **Pipeline Integration** — Set up Unreal MCP within your existing build system, CI/CD, and team workflow so every artist and developer can use AI assistants with your Unreal project out of the box
- **Custom Tool Development** — Build MCP commands tailored to your studio's proprietary formats, internal tools, and specific production needs that the open-source version doesn't cover
- **AI Workflow Design** — Design and implement how your team uses AI assistants (Claude, Cursor, Copilot) with Unreal Engine — from material creation to level design to asset pipelines
- **Advanced Material & Substrate Systems** — Procedural material generation, Substrate workflows, complex shader pipelines — fully automated through MCP
**Get in touch:**
- Email: [aadeshrao80@gmail.com](mailto:aadeshrao80@gmail.com)
- LinkedIn: [linkedin.com/in/aadeshyadav](https://www.linkedin.com/in/aadeshyadav/)
- Discord: `destroyerpal`
- Portfolio: [aadeshyadav.vercel.app](https://aadeshyadav.vercel.app/)
---
## Custom Development & Support
Need help with your Unreal project? I'm available for contract work across the full UE5 C++ stack, from gameplay and multiplayer to editor tooling and Mass Entity systems. See [SUPPORT.md](SUPPORT.md) for details.
[aadeshrao80@gmail.com](mailto:aadeshrao80@gmail.com) · [LinkedIn](https://www.linkedin.com/in/aadeshyadav/) · [Portfolio](https://aadeshyadav.vercel.app/) · Discord: `destroyerpal`
---
## License
MPL-2.0 — see [LICENSE](LICENSE) for details.