UnrealEngine Bridge
Claude Code, working inside your Unreal editor. This bridge gives Claude the abilities Epic's own MCP doesn't ship: run real editor Python, see the viewport continuously, light scenes with one command, reason about space with surface normals, and stay honest about every result.
58 MCP tools · 20 mounted by default · 635 tests · Changelog · Security
The one-paragraph story
UE 5.8 ships Epic's official Unreal MCP — 830 tools once you enable AllToolsets. That's the commodity control plane: spawn, transform, materials, Blueprints, Sequencer. So this bridge stopped competing and specialized. We live-probed Epic's entire surface, wrote the verdict for every one of our tools into EPIC_MCP_MATRIX.md, and flipped the default: you get our differentiated core out of the box, Epic handles the basics, and the 36 overlapping tools stay one env var away.
How it works
Two MCP servers, one editor. Claude uses both.
graph LR
subgraph Claude Code
A[MCP Client]
end
subgraph B1["This bridge — Python"]
B[MCP Server<br/><i>FastMCP · stdio</i>]
B --> C[Tiered Registry<br/><i>core: 20 · full: 56</i>]
C --> D[Remote Control Bridge<br/><i>httpx · circuit breaker</i>]
end
subgraph Unreal Editor
E[Remote Control API<br/><i>localhost:30010</i>]
E --> F[Editor Runtime]
G[ViewportPerception<br/><i>localhost:30011</i>]
G --> F
H[Epic Unreal MCP<br/><i>localhost:8000 · UE 5.8</i>]
H --> F
end
A -- stdio --> B
A -. HTTP /mcp .-> H
D -- HTTP --> E
C -. viewport capture .-> G
style A fill:#5CFFDB,color:#05050D
style B fill:#5CFFDB,color:#05050D
style C fill:#5CFFDB,color:#05050D
style D fill:#12121F,color:#fff
style E fill:#FFCC33,color:#05050D
style F fill:#12121F,color:#fff
style G fill:#FFCC33,color:#05050D
style H fill:#FFCC33,color:#05050D
Who does what:
Quick start
You need: UE 5.7 or 5.8 · Python 3.11+ · the Remote Control API plugin enabled (ships with the engine).
1 — Install
git clone https://github.com/JosephOIbrahim/UnrealEngine_Bridge.git
cd UnrealEngine_Bridge
pip install -e .
2 — Open the project
Open UnrealEngine_Bridge.uproject. Check the Output Log for "Remote Control Web Server started" — that's localhost:30010 up.
On UE 5.8, the ModelContextProtocol and AllToolsets plugins self-enable (they're staged Optional in the project). Start Epic's server from the console: ModelContextProtocol.StartServer.
3 — Connect Claude Code
The repo ships a ready .mcp.json — open the repo folder in Claude Code and both servers are configured. For other projects, copy it and fix the path.
4 — Try it
"Set golden hour and snap the crates to the terrain."
Claude uses ue_apply_mood_preset and ue_snap_to_ground — two things no other UE MCP can do.
Want the commodity tools from this bridge instead of Epic's? Set the env var and restart the server:
"unreal": { "command": "python", "args": ["-m", "ue_mcp.mcp_server"], "env": { "UE_MCP_PROFILE": "full" } }
What's mounted by default (the core 20)
These are the tools Epic's MCP does not have — verified against all 830 of theirs (the matrix).
🐍 Editor Python & console (2)
👁 Perception (4)
🌅 Lighting & atmosphere (5)
📐 Spatial reasoning (4)
🧩 Scene gaps Epic left open (3)
❤️ Bridge health (2)
The commodity tier (36 tools, UE_MCP_PROFILE=full)
Epic's MCP covers these — the matrix cites the exact equivalent for every row. They stay in the codebase, tested and honest, for UE 5.7 or as a fallback:
Experimental tier (UE_MCP_PROFILE=all): ue_undo / ue_redo — honest not-implemented slots. The UE Python API has no scriptable editor-transaction route; these say so instead of pretending.
🧊 UE ↔ X3D round-trip harness (new in v0.3.0)
Hand Claude a level as open X3D it can read, edit, and validate — then write it back losslessly. A thin, fully-tested slice: no live editor needed to prove an edit is safe.
The one invariant it defends:
deserialize( serialize( level ) ) == level
Lossless round trip, plus malformed edits rejected on paper before any mutation. If both hold, the bridge is trustworthy — if either fails, nothing else matters.
from x3d_bridge import Actor, serialize, deserialize, validate
x3d = serialize([Actor(guid="Rock_01", mesh="/Game/Meshes/SM_Rock",
t=(420.0, 0.0, 155.0))])
ok, errors = validate(x3d) # the paper boundary
level = deserialize(x3d) # lossless
Status — honest, per the house rule:
- ✅ 55 tests — round-trip · validation battery · apply-op sequence — all green
- ✅ Basis
Bindependently re-derived and confirmed three ways - ⏳
Bis analytic — not yet calibrated against a live glTF export (round-trip is basis-agnostic, so this is fidelity-only, never correctness) - ⏳ A library today — not yet exposed as MCP tools
Why trust the results? Honesty as architecture
This bridge's tools cannot silently lie — that's enforced, not promised:
- Exec-simulated codegen tests. Every generated editor script is compiled and executed against a strict fake
unrealmodule in CI. Phantom APIs raise. Dropped arguments fail a sentinel gate. Hard-coded success prints fail honesty contracts. - Read-back verification. Writes that UE can silently ignore (cloner layout names) are read back before being reported "applied".
- Honest statuses. The viewport fallback reports
capture_status: timeoutinstead of an empty image withsuccess: true. Not-implemented tools say "not implemented". - 635 tests, including scripted-failure contracts for every historical lying-tool bug.
graph TB
subgraph Python layer
MCP["MCP Server<br/><code>ue_mcp/mcp_server.py</code>"]
Reg["Tiered Registry<br/><i>core / full / all</i>"]
Tools["Tool Modules (14)<br/><code>ue_mcp/tools/</code>"]
Val["Validation & AST Sandbox<br/><code>_validation.py</code>"]
RC["Remote Control Bridge<br/><code>remote_control/</code>"]
Met["Metrics & Circuit Breaker"]
end
subgraph Test layer
Sim["Exec-Sim Harness<br/><i>strict fake unreal · honesty contracts</i>"]
end
subgraph Unreal Editor
RCAPI["Remote Control API<br/><i>REST · :30010</i>"]
VP["ViewportPerception plugin<br/><i>GPU readback · :30011</i>"]
EPIC["Epic Unreal MCP<br/><i>HTTP+SSE · :8000 · UE 5.8</i>"]
end
MCP --> Reg --> Tools
Tools --> Val
Tools --> RC --> Met
RC -- HTTP --> RCAPI
Tools -. capture .-> VP
Sim -. gates every generated script .-> Tools
style MCP fill:#5CFFDB,color:#05050D
style Reg fill:#5CFFDB,color:#05050D
style Tools fill:#5CFFDB,color:#05050D
style Sim fill:#12121F,color:#fff
style RCAPI fill:#FFCC33,color:#05050D
style VP fill:#FFCC33,color:#05050D
style EPIC fill:#FFCC33,color:#05050D
Resilience
Network surface & trust model
Everything is localhost, single trusted operator: Remote Control (:30010), ViewportPerception (:30011, off by default), and — on 5.8 — Epic's MCP (:8000, no auth, serial on the game thread; Epic's EULA §6(e) governs what your LLM provider may do with transmitted data). Don't expose any of them to untrusted networks.
Full trust model and hardening guidance: SECURITY.md.
Project structure
UnrealEngine_Bridge/
├── ue_mcp/ # MCP server package
│ ├── mcp_server.py # FastMCP entry point (stdio) + health tools
│ ├── metrics.py # Telemetry + observability
│ ├── ue_logging.py # Structured JSON logging
│ └── tools/ # 14 modules · 56 tools · tiered registry in __init__.py
├── remote_control/ # UE5 HTTP bridge (circuit breaker, codegen, polling)
├── x3d_bridge/ # UE↔X3D round-trip harness (coords · grammar · validate · apply)
├── usd_bridge/ # USD file I/O package (parked, out of the ship path)
├── Plugins/
│ ├── UEBridge/ # Editor panel, file watcher (C++)
│ └── ViewportPerception/ # GPU readback + HTTP endpoint (C++)
├── docs/
│ ├── EPIC_MCP_MATRIX.md # Retirement contract-of-record (probe-grounded)
│ └── epic_mcp/ # Raw probe captures of Epic's 830-tool surface
├── scripts/probe_epic_mcp.py # Re-probe Epic's surface per engine version
├── tests/ # 635 tests, incl. tests/exec_sim/ + tier gates
├── smoke_live.py # Live-editor smoke harness (on-demand)
└── .mcp.json # Two-server config: this bridge + Epic's MCP
Development
Run the tests
pip install -e ".[dev]"
python -m pytest -q # 635 tests
Lint
ruff check ue_mcp/ remote_control/ tests/
Add a tool (each step is checked by CI)
- Create
ue_mcp/tools/your_module.pywith aregister(server, ue)function - Decorate tools with
@server.tool(...); validate inputs via_validation.py - Wire the module into
ue_mcp/tools/__init__.py— and classify the tool inTIERS(an unclassified tool fails CI) - Add a sentinel entry in
tests/exec_sim/registry.py(a missing entry fails CI) - Add tests
License
Released under the MIT License — Copyright (c) 2026 Joseph Ibrahim.