Security model

Secure by default

An MCP server for Unreal lets a program create, change and delete assets, run console commands and even run Python in your editor. EngineWire's defaults keep that to your own machine and to clients that hold your project's token, and make destructive work a deliberate, per-call step.

Updated Covers EngineWire 0.6 beta (npm @beta)

The defaults

AreaDefault
NetworkBoth routes listen on 127.0.0.1 only. The WebSocket listener uses ports 8090 and 8091; the native HTTP server is off until you enable it, then uses port 3000.
Capability tokenRequired on both routes.
ConsentRequired on every call to 62 capabilities: all deletes, plus some other writes.
Console commandsFiltered: no command chaining, no quit or crash commands.
Asset paths/Game, /Engine, /Script, /Temp, /Niagara, plus any prefixes you add.
The plugin's own settingsOut of reach of automation, so an assistant can't lift its own limits.
TelemetryNone. The plugin and server talk only to each other and to your MCP client.

How a request is checked

The C++ plugin is the authority. The Node.js server checks requests early so it can fail fast, but the plugin re-checks every request, from either route, before it reaches the editor's queue. A refused request does no editor work at all. The checks run in order:

  1. Capability token. Missing or wrong: 401 Invalid capability token.

  2. Scope. The token must hold the scope the capability needs: SCOPE_NOT_GRANTED otherwise.

  3. Consent. Destructive capabilities need a matching grant: CONSENT_REQUIRED otherwise.

  4. Project, paths, console and quota. PATH_NOT_PERMITTED, PROJECT_NOT_PERMITTED, COMMAND_BLOCKED or QUOTA_EXCEEDED.

Capability tokens

The first time the editor starts with the plugin, it generates a random 32-byte token and writes it, as 64 hex characters, to <YourProject>/Saved/MCP/capability-token. Native HTTP clients send it in the X-MCP-Capability-Token header; the stdio server reads the file itself (through UE_PROJECT_PATH) and presents it in its WebSocket handshake.

  • Tokens are compared in constant time and never written to logs, receipts or health output.
  • A session can't switch tokens halfway through.
  • The file is readable by your OS user like the rest of the project. Saved/ is normally not committed; keep it that way, and tighten permissions if it sits on a shared drive.

To rotate the token, delete Saved/MCP/capability-token (or clear the Capability Token setting), restart the editor and update your HTTP clients.

Turning the token off

Unticking Require Capability Token lets any program on your machine drive the editor through either route. That can be acceptable on a single-user machine where nothing else runs. Even then, the native server refuses requests that come from web pages (an Origin header), so a website open in your browser can't reach the editor.

Scopes and scoped tokens

Every capability requires one of four scopes: Read, Write, Destructive or Admin. Membership is exact: holding Write does not grant Read, and an action the catalog doesn't know demands Admin, so unknown requests are refused by default. The main token is Admin.

For anything narrower, add entries under Security › Scoped Tokens in the plugin settings. Each scoped token can have its own scopes (never Admin), allowed path prefixes such as /Game/Sandbox/, allowed projects, and per-minute request and tool-call quotas. Typical uses: a read-only token for an assistant that should only look, a token confined to one folder for an experimental agent, or a rate-limited token on a shared machine.

62 capabilities declare a consent mode: explicit, or elevated for the most destructive, such as bulk deletes. describe returns the exact grant; the call must send it back unchanged:

json · consent field on an execute call
"consent": { "capability": "control_actor.delete", "acknowledge": "explicit", "nonce": "62A12661-4F6A-1C97-339E-69921EE9E2A7" }
  • A grant covers one call to one capability. On the native route its nonce makes it single-use: a replay is refused with CONSENT_REUSED.
  • It is never inferred from localhost, from earlier calls or from an idempotency key.
  • Consent is not permission: the caller still needs the capability's scope.

Consent makes deleting a step the model has to take on purpose, rather than a side effect of a loosely worded prompt. To approve such calls yourself, use your client's tool-approval setting for the unreal tool.

Other safeguards

  • Paths. File-system paths are checked for traversal and symbolic links, once when accepted and again just before use.
  • Console. Chaining (;, &&, ||, |, backticks, newlines) is refused, as are quit, exit, shutdown, crash and similar, and attempts to reach Python or a shell through the console.
  • Python. system_control.execute_python exists. It needs Write scope and explicit consent per call, and scripts are limited to 1 MB. Anything that can run Python can do anything the editor can, so treat that consent as a real decision.
  • Rate limits. Native HTTP allows 16 sessions and 32 connections, and per session 600 requests and 120 tool calls a minute.

Remote and LAN access

Both routes are loopback-only by default. Reaching the editor from another machine takes Allow Non Loopback plus a Listen Host in the plugin, a firewall rule, and the token, which stays required: the native server refuses to bind to a LAN address without it. The WebSocket route supports TLS. The native server speaks plain HTTP, so beyond a network you fully trust, reach it through an SSH tunnel or a TLS reverse proxy rather than exposing the port.

FAQ

Can the AI wreck my project?

It can change and delete things; that is the point. Deletes need a per-call consent grant, control_editor.undo steps back through editor transactions, and partial failures are reported rather than hidden. Use source control anyway, and commit before a big job.

Does my project leave my machine?

The plugin and server send nothing anywhere and collect no telemetry. Your AI client does send tool results (asset names, property values, screenshots) to its model provider. Fab and MetaHuman capabilities go through Epic's services, only when you run them.

How do I report a vulnerability?

Privately, through GitHub's private vulnerability reporting, not a public issue.

How does this compare with Epic's plugin?

Epic documents its Unreal MCP as having no authentication layer. See Epic's Unreal MCP vs EngineWire.