Contents Β· What it does Β· How it works Β· Quick start Β· The unreal tool Β· Configuration Β· Security Β· Engine plugins Β· Docker Β· Documentation Β· Development Β· Community
What it does
ποΈ Levels and actors Spawn one actor or hundreds in a single call, place and attach them, find the ones sunk into the floor, and load, stream and save levels.
π§© Blueprints and UI Create Blueprints, variables and components, build whole event graphs in one batch, and lay out UMG widgets, with a preview image to check them.
π¨ Materials and worlds Material graphs and instances, procedural textures, lighting, landscapes, foliage, Niagara effects and PCG graphs.
πΉοΈ Gameplay Characters and animation, Gameplay Ability System, AI (Behavior Trees, State Trees, EQS), inventory, networking and Enhanced Input.
π¬ Cinematics and audio Level Sequences, cameras, Movie Render Queue and Take Recorder; Sound Cues and MetaSounds.
π§ͺ Play and verify Run Play-In-Editor with synthetic input, take screenshots the model can see, read logs, profile, run Python, and package builds.
Nearly 400 capabilities in all, behind a single MCP tool. The assistant finds them by searching in plain words, so nobody has to learn their names. The full list is the generated Action Reference.
How it works
The EngineWire plugin runs inside the editor and does all the work, on the editor's game thread. Clients reach it in one of two ways, and both expose the same single tool, unreal:
Everything listens on 127.0.0.1 and requires the project's capability token unless you change it.
Quick start
The Quick Start page walks through this with screenshots. You need Unreal Engine 5.0 to 5.8 and a project with C++ code; a Blueprint-only project can use prebuilt binaries.
1. Add the plugin
Download EngineWire-plugin-<version>.zip from the newest v0.6 pre-release on the Releases page, and copy the EngineWire folder it contains into your project:
MyGame/Plugins/EngineWire/
Or use a clone of this repository: copy plugins/EngineWire/, or reference the folder from your .uproject with "AdditionalPluginDirectories": ["C:/Path/To/Unreal_mcp/plugins"].
Open the project and let Unreal rebuild the plugin. When it's loaded, the status bar shows MCP off. If you see "Engine modules cannot be compiled at runtime", build the project once in Visual Studio, Rider or Xcode. More in Installation.
https://github.com/user-attachments/assets/d8b86ebc-4364-48c9-9781-de854bf3ef7d
Build the plugin once on a machine with the engine and a compiler, then hand out the zip. No compiler is needed on the target machine:
node scripts/package-plugin.mjs "C:/Program Files/Epic Games/UE_5.7"
This writes build/EngineWire-v<version>-UE5.7-<Platform>.zip, where <version> is the package.json version (currently 0.6.0-beta-f). Unzip it into YourProject/Plugins/. Binaries only work with the engine minor and platform they were built for: a 5.6 build won't load in 5.5, 5.7 or 5.8.
2. Connect your client
Route A Β· Native HTTP (no Node.js)
-
In Edit βΊ Project Settings βΊ Plugins βΊ EngineWire, tick Enable Native MCP Server (port
3000by default), then restart the editor. The status bar now readsMCP :3000 (0). -
Read the capability token the plugin generated:
<YourProject>/Saved/MCP/capability-token. Treat it like a password. -
Add the server to your client and send the token in the
X-MCP-Capability-Tokenheader. Claude Code:claude mcp add --transport http unreal-engine http://127.0.0.1:3000/mcp --header "X-MCP-Capability-Token: <token>"Or in a project
.mcp.json(Claude Code), reading the token from an environment variable:{ "mcpServers": { "unreal-engine": { "type": "http", "url": "http://127.0.0.1:3000/mcp", "headers": { "X-MCP-Capability-Token": "${UNREAL_MCP_TOKEN}" } } } }Cursor (
.cursor/mcp.json) takes the sameurlandheaderswithouttype. VS Code, Windsurf and others: Connecting Clients. -
Check it: when the client connects, the count in the status bar goes up.
A client connected straight to /mcp loses its session whenever the editor closes or crashes, and has to reconnect by hand. The package's proxy command sits in between over stdio: while the editor is down every call answers NOT_CONNECTED, and the first call after it is back reaches it, with no reconnect. It keeps the editor's last tool list, so a session that starts before the editor still gets the real tool.
{
"mcpServers": {
"unreal-engine": {
"command": "npx",
"args": ["-y", "unreal-engine-mcp-server@beta", "proxy"],
"env": { "UE_PROJECT_PATH": "C:/Path/To/YourProject" }
}
}
}
The token is found the same way as on Route B (MCP_AUTOMATION_CAPABILITY_TOKEN, else the project's token file). UNREAL_MCP_URL points it at another endpoint (default http://127.0.0.1:3000/mcp). Route B survives editor restarts the same way on its own.
Route B Β· stdio (Node.js 20.19+)
Add this to your client's MCP configuration, for example Claude Desktop's claude_desktop_config.json:
{
"mcpServers": {
"unreal-engine": {
"command": "npx",
"args": ["-y", "unreal-engine-mcp-server@beta"],
"env": {
"UE_PROJECT_PATH": "C:/Path/To/YourProject"
}
}
}
}
UE_PROJECT_PATH (the project folder or its .uproject) is how the server finds the capability token and the plugin's port, so nothing else needs setting. Keep the @beta tag: without it, npm installs 0.5.30, which doesn't match a 0.6 plugin.
3. Try it
With the editor open, ask your assistant to "list the actors in the current level", "spawn a point light 300 units above the origin", or "take a screenshot of the viewport". If it doesn't connect, see Troubleshooting.
The unreal tool
Both routes expose exactly one MCP tool, unreal, with four operations. Only the contract the model is about to use gets loaded, instead of hundreds of tool schemas:
{ "operation": "search", "query": "spawn actor" }
{ "operation": "describe", "tool": "control_actor", "action": "spawn" }
{
"operation": "execute",
"tool": "control_actor",
"action": "spawn",
"params": { "classPath": "/Script/Engine.PointLight", "actorName": "KeyLight", "location": [0, 0, 300] }
}
- Parameters are strict. An undeclared name is refused with
UNDECLARED_PARAMETERand the list of allowed names; every error carries an executablenextCall. - Deletes need consent. 62 capabilities (all destructive ones, plus some writes) only run with the
consentGrantfromdescribe, passed back as a top-levelconsentfield. - Names. Both routes accept the
tool+actionpair; the stdio route also accepts a capability id, such as"capability": "control_actor.spawn".
Full reference with real replies: Using the Gateway.
Migrating from direct tool calls
The single unreal tool is permanent on both routes; there is no opt-out and no 23-tool listing to restore. A client that still calls a canonical tool name directly (tools/call with name: "manage_asset", name: "control_actor", β¦) receives a bounded, copy-paste-executable DIRECT_TOOL_CALL_REMOVED receipt instead of a routed call. Its nextCall drills exactly one level: { "operation": "search" } for an unknown name, { "operation": "describe", "tool": "<tool>" } when no action was given, or { "operation": "execute", "tool": "<tool>", "action": "<action>", "params": { ... } } when the call already named an action. Run that nextCall through unreal to finish the migration. See Upgrading.
Protocol versions
Both routes negotiate the MCP protocol version at initialize. The native /mcp transport supports 2025-11-25 (latest), 2025-06-18 and 2025-03-26; the stdio server also accepts the legacy 2024-11-05 and 2024-10-07. An unsupported MCP-Protocol-Version header on the native route gets HTTP 400. Both also answer server/discover without a session, listing those versions, so a client on the newer 2026-07-28 revision falls back to initialize. Details: docs/protocol.md.
These route requests inside the gateway; clients never list them. More in the Tools Reference.
Configuration
Most setups touch one setting: Enable Native MCP Server for Route A, or UE_PROJECT_PATH for Route B. Everything is listed on the Configuration page.
Plugin settings (Project Settings βΊ Plugins βΊ EngineWire, saved in Config/DefaultGame.ini):
Environment variables (Route B only, in the client's env block):
Security
- Local by default. Both routes listen on
127.0.0.1only. LAN access needs Allow Non Loopback, and the native server refuses to bind off-loopback unless Require Capability Token is on. - Capability token. Generated per project at
<Project>/Saved/MCP/capability-token(a value typed into Capability Token overrides it) and compared in constant time. Delete the file and restart the editor to rotate it. - Consent for destructive work. Deletes and some other writes need a per-call consent grant, which the plugin checks itself.
- Guard rails. Asset paths are limited to
/Game,/Engine,/Script,/Temp,/Niagaraplus configured prefixes, and a content path may also sit under a mount the connected editor reports; arguments the server treats as files (such asfilePath, andoutputPatheven where it names an asset) never use the reported mounts; console commands that chain or quit the editor are blocked; the plugin's own settings are out of reach of automation.
Details: Security. Please report vulnerabilities privately through GitHub security advisories.
Engine plugins
The bridge declares its engine-plugin dependencies, so Unreal enables them together with it.
The plugin targets every Unreal Engine minor from 5.0 to 5.8. If it fails to build on yours, please open an issue with the build log.
Docker
The image runs the stdio server. It has to reach the editor's WebSocket on 127.0.0.1, so use host networking (Linux), and pass the token because the container can't read your project folder:
docker build -t unreal-mcp .
docker run -i --rm --network host -e MCP_AUTOMATION_CAPABILITY_TOKEN=<token> unreal-mcp
Use -i without -t: a TTY corrupts the MCP stream on stdout.
Documentation
Development
npm install
npm run build # clean + compile TypeScript to dist/
npm run dev # run from source with ts-node
npm run lint # ESLint (CI fails on any warning)
npm run type-check # tsc --noEmit, sources and tests
npm run test:unit # Vitest unit tests (no Unreal required)
npm run test:smoke # offline mock-mode MCP check (needs built dist/)
npm run test:params # strict parameter audit
npm run registry:generate # capability records -> generated contracts, native shards, action reference
npm run registry:check # fail if generated artifacts drift
npm run manifest:check # fail if the gateway manifest drifts
npm run eval:check # search-ranking corpus
npm run version:check # all version sources agree
npm test # integration suite (needs a live Unreal Editor + bridge)
The capability records in src/tools/catalog/capabilities/records/ are the single source of truth; every *.generated.* file, the plugin's MCP/Generated/ shards and the action reference are generated from them. Never hand-edit generated files. How to add a capability: Development.
CI runs, in order: ESLint (npx eslint . --max-warnings=0), type-check, unit tests, registry:check, manifest:check, headers:check, the strict parameter audit (test:params) and eval:check, then a blocking runtime dependency audit (npm audit --omit=dev --audit-level=moderate) and an informational full-tree audit. A Node 20.19 / 26 matrix adds build and test:smoke. Plugin packaging runs only when an Unreal Engine root is configured, because CI runners don't ship an engine. Release archives exclude Binaries/, Intermediate/ and Saved/.
Community
Contributing: keep pull requests small and focused, with a Conventional Commits title; include reproduction steps for bugs; follow the existing code style. See CONTRIBUTING.md.
License
MIT. See LICENSE.