Architecture¶
UE-MCP has two main components: a TypeScript MCP server that handles the AI protocol, and a C++ plugin that runs inside the Unreal Editor and exposes engine APIs over WebSocket.
flowchart LR
AI[AI Assistant] -->|stdio / MCP protocol| MCP[MCP Server<br/>TypeScript / Node.js]
MCP -->|WebSocket<br/>JSON-RPC 2.0<br/>port 9877| Plugin[C++ Bridge Plugin<br/>UE_MCP_Bridge]
Plugin -->|UE C++ API| Engine[Editor Subsystems<br/>Asset Registry<br/>Blueprint Compiler<br/>etc.]
MCP -->|direct filesystem| FS[Config INI<br/>C++ Headers<br/>Asset Directories]
MCP Server (TypeScript)¶
Entry point: src/index.ts
The server creates an McpServer instance (from @modelcontextprotocol/sdk), registers 19 category tools, and communicates with the AI client over stdio.
Key Modules¶
| Module | Purpose |
|---|---|
index.ts |
Tool registration, MCP server lifecycle |
bridge.ts |
EditorBridge — WebSocket client, JSON-RPC messaging, auto-reconnect |
project.ts |
ProjectContext — path resolution, INI parsing, C++ header parsing |
deployer.ts |
First-run deployment: copy plugin, mutate .uproject |
editor-control.ts |
Start/stop/restart the Unreal Editor process |
instructions.ts |
AI-facing server instructions (embedded documentation) |
types.ts |
ToolDef, ActionSpec, categoryTool() factory |
github-app.ts |
GitHub App auth for agent feedback issue submission |
Tool Registration Pattern¶
All tools use the categoryTool() factory:
export const levelTool: ToolDef = categoryTool(
"level", // tool name
"Actors, selection, components...", // description
{
get_outliner: bp("get_outliner"), // bridge action
get_current: { handler: localHandler }, // local action
},
"- get_outliner: List actors...", // AI-facing docs
);
Two action types:
- Bridge actions (
bp()) — forwarded to the C++ plugin over WebSocket - Local actions — handled in Node.js (filesystem operations like INI parsing, C++ header reading)
Bridge Communication¶
The EditorBridge maintains a WebSocket connection to ws://localhost:9877.
Protocol: JSON-RPC 2.0
// Request
{
"jsonrpc": "2.0",
"id": "req-42",
"method": "get_outliner",
"params": { "classFilter": "StaticMeshActor" }
}
// Response
{
"jsonrpc": "2.0",
"id": "req-42",
"result": { "actors": [...] }
}
- Timeout: 30 seconds per request
- Reconnect: Automatic every 15 seconds if disconnected
- Thread safety: All responses are correlated by request ID
C++ Bridge Plugin¶
Location: plugin/ue_mcp_bridge/
Module type: Editor-only
The plugin runs a raw WebSocket server on a dedicated thread, dispatches incoming JSON-RPC requests to registered handler functions, and executes them on the game thread.
Core Classes¶
| Class | Purpose |
|---|---|
FBridgeServer |
WebSocket server (raw platform sockets, no third-party libs) |
FHandlerRegistry |
Maps method names to C++ handler functions |
FGameThreadExecutor |
Queues tasks to the game thread (required for UE API access) |
Handler Categories¶
21 C++ handler groups are registered in BridgeServer.cpp:
| Handler | Coverage |
|---|---|
| EditorHandlers | Console, Python, PIE, viewport, sequencer, build, logs, perf |
| AssetHandlers | CRUD, import, search, datatables, textures |
| BlueprintHandlers | Read/write, graphs, compilation, node types |
| LevelHandlers | Actors, components, levels, volumes, lights |
| ReflectionHandlers | Class/struct/enum reflection, gameplay tags |
| MaterialHandlers | Materials, instances, expressions |
| AnimationHandlers | Anim BPs, montages, skeletons, blendspaces |
| AudioHandlers | Playback, ambient sounds, cues |
| WidgetHandlers | UMG widgets, editor utilities |
| FoliageHandlers | Foliage painting and types |
| LandscapeHandlers | Terrain sculpting and painting |
| NetworkingHandlers | Replication config |
| NiagaraHandlers | VFX systems and emitters |
| PCGHandlers | Procedural generation graphs |
| GasHandlers | Gameplay Ability System |
| GameplayHandlers | Physics, collision, navigation, AI, input, game framework |
| PhysicsHandlers | Collision and physics properties |
| SequencerHandlers | Level sequences |
| SplineHandlers | Spline actors |
| DialogHandlers | Modal dialog management |
| DemoHandlers | Neon Shrine demo builder |
Plugin Dependencies¶
The C++ plugin links against a wide range of UE modules:
- Core: Core, CoreUObject, Engine, Json, JsonUtilities, GameplayTags
- Editor: UnrealEd, AssetRegistry, BlueprintGraph, Kismet, KismetCompiler, PropertyEditor
- Systems: Landscape, Niagara, PCG, Sequencer, UMG, GameplayAbilities, NavigationSystem, AIModule
- Tools: LiveCoding, MaterialEditor, EditorScriptingUtilities, DataValidation
Hybrid Architecture¶
A key design principle: read operations work without the editor.
| Operation Type | Requires Editor? | How |
|---|---|---|
| INI config parsing | No | Direct filesystem |
| C++ header reflection | No | Regex-based parsing |
| Asset directory listing | No | Filesystem scan |
| Blueprint reading | Yes | C++ bridge |
| Actor placement | Yes | C++ bridge |
| Material authoring | Yes | C++ bridge |
| PIE control | Yes | C++ bridge |
| Build pipeline | Yes | C++ bridge |
This means the AI can explore project structure, read configs, and understand C++ code even when the editor isn't running.
Path Resolution¶
The ProjectContext handles path formats:
| Input | Resolved To |
|---|---|
/Game/MyAsset |
<ProjectDir>/Content/MyAsset |
/MyPlugin/Assets/Foo |
<ProjectDir>/Plugins/MyPlugin/Content/Assets/Foo |
| Absolute path | Used as-is |
| Relative path | Relative to project root |
Data Flow Example¶
Here's what happens when the AI calls blueprint(action="read", assetPath="/Game/BP_Player"):
sequenceDiagram
participant AI as AI Assistant
participant MCP as MCP Server
participant WS as WebSocket
participant Plugin as C++ Plugin
participant GT as Game Thread
participant UE as Blueprint Subsystem
AI->>MCP: blueprint(action="read", assetPath="/Game/BP_Player")
MCP->>MCP: Resolve action → bridge method "read_blueprint"
MCP->>WS: JSON-RPC request
WS->>Plugin: Receive on bridge thread
Plugin->>GT: Queue to game thread
GT->>UE: Load asset, reflect properties, read graphs
UE-->>GT: Blueprint structure
GT-->>Plugin: JSON result
Plugin-->>WS: JSON-RPC response
WS-->>MCP: Parse response
MCP-->>AI: Formatted result