DOCUMENTATION

MCP Server

The MCP server is a small Python process that exposes both backends as tools for an MCP client: the Unreal plugin over HTTP, and the Blender add-on over its socket. Your client talks to one server, and the server talks to whichever editor the tool belongs to.

How it fits together

                            ┌─ HTTP POST 127.0.0.1:8791 ──► MifBridge (Unreal editor)
client ── MCP (stdio) ──► server.py
                            └─ framed JSON 127.0.0.1:8792 ─► MifBlender (Blender add-on)

Two transports and no shared dispatch. Unreal tools go to the editor's HTTP API, and the Blender tools, the ones named bl_*, go to the add-on's socket.

Install and run

cd <YourProject>/Plugins/MifBridge/Content/Python/MifBridge/mcp-server
pip install -r requirements.txt

python server.py           # stdio transport
python server.py --debug   # plus request/response tracing on stderr

It needs Python 3.10 or newer. The dependencies are the MCP SDK and requests. A copy from GitHub keeps the server in tools/mcp-server/ instead.

Connect a client

With Claude Code, the editor can do this for you: SETUP ▸ Set up Claude Code in the MifBridge panel installs the dependencies into a private environment and registers the server with the editor's own port and token. See Installation.

By hand, add a project-scoped .mcp.json (or put the same block in your user config):

{
  "mcpServers": {
    "mif-bridge": {
      "command": "python",
      "args": ["<YourProject>/Plugins/MifBridge/Content/Python/MifBridge/mcp-server/server.py"],
      "env": {
        "MIF_BRIDGE_URL": "http://127.0.0.1:8791/api",
        "MIF_BRIDGE_TOKEN": "change-me-to-match-the-editor"
      }
    }
  }
}

The server key (mif-bridge) is only a local name that sets the prefix your client shows on tool names. The token must match the editor's MIF_BRIDGE_TOKEN. Do not commit a real secret.

Cursor, Claude Desktop and Codex by name. From 1.2, the setup script writes the same checked entry into another client's own config, keeping the file's other servers and a backup of it: python Content/Python/MifBridge/setup_claude_code.py --project <folder with the .uproject> --client cursor (or claude-desktop, or codex; repeat --client for several). Nothing is written for a client you do not name.

Configuration

Variable Default Notes
MIF_BRIDGE_URL http://127.0.0.1:8791/api The editor's API base URL. Unset, it follows MIF_BRIDGE_PORT when that is set.
MIF_BRIDGE_TOKEN dev Must match the editor. Sent as the X-Mif-Token header.
MIF_BRIDGE_TIMEOUT 30 Per-request timeout in seconds. Raise it if compiles are slow.
MIF_BRIDGE_DEBUG unset 1 logs every request and response to stderr, like --debug.
MIF_AGENT the client's own name A name for the caller, sent as the X-Mif-Agent header and shown in the panel's Activity tab. Unset, the name the MCP client gives for itself is used.
MIF_TOOL_PACKS lean Which tool packs to load. See below.
MIF_GENERATIVE unset off switches the generative bl_gen_* tools off for every project. See Using MifBridge Without Generative AI.
MIF_BLENDER_HOST / MIF_BLENDER_PORT 127.0.0.1 / 8792 The Blender add-on's socket, where a session starts. A MifBlender on another port is found anyway; see below.
MIF_BLENDER_TOKEN falls back to MIF_BRIDGE_TOKEN Must match the add-on's Token preference.
MIF_BLENDER_CONNECT_TIMEOUT 3 A closed Blender reports "refused" in about 3 s instead of hanging.
MIF_BLENDER_PROBE_TIMEOUT 5 bl_status only.
MIF_BLENDER_TIMEOUT 180 Per Blender operation. Geometry work can be slow.

See Configuration for the editor's own variables and the port map.

Tool packs: load only what you need

Every tool definition a client loads is sent to the model on every turn, used or not, and MifBridge has several hundred tools. So by default the server registers only three: find_tools, mif_call and run_python. find_tools searches every tool, loaded or not, and names the pack that has it; mif_call calls any tool by name. Loading a pack registers its tools directly instead.

Pack Covers
core Orientation and the commonest reads and writes: self_audit, describe_endpoint, mif_help, find_tools, the pack tools, property reads and writes, and batch. Loaded with any named pack.
assets Unreal assets: find, create, rename, move and delete; import and export; materials and material instances; meshes; DataTables; collections; cooked content; MetaSounds; source control
animation Skeletons, animation sequences, montages and Animation Blueprints, Sequencer, Control Rig and IK, MetaHuman, Live Link, StateTrees
world Building a level: actors, the viewport camera and captures, levels and World Partition streaming, landscapes, foliage, water, PCG, navigation, collision and physics
rendering Lights and cameras, the viewport and captures, view layers, render settings and performance views
vfx_niagara Niagara: an emitter's module stack, renderers, emitter and system properties, event handlers, User parameters, compiling, and a placed effect's live particles
vfx_look How an effect looks: particle materials, flipbook atlases rendered in Blender, flicker lights, palettes, and effect recipes
vfx_volumes Volumetric effects: OpenVDB frames as a Sparse Volume Texture, the volume material, and real-time gas from the Niagara Fluids templates
blueprint_core Create, open, compile and save any Blueprint. Loaded with ui and systems
ui UMG widget trees, bindings and previews, live widgets, details panels, and pipeline recipes
systems Blueprint authoring: variables, functions and event graphs, nodes and pins, components, interfaces, graph patches, calling functions, and reading cooked Blueprints
dev Play-In-Editor, console commands, undo transactions, Live Coding, tracing and frame stats, project settings, automation tests, the game framework, gameplay abilities and tags
blender_core Start here for Blender: status, scene and object info, the call log, batch, undo, transforms, visibility, collections, scenes and .blend files
blender_modeling Primitives, mesh from data, curves, text, trees, rocks, ground cover, kit pieces and LODs, booleans, converting, the modifier stack, origins and the placement audit
blender_mesh_edit Editing a mesh's parts: selecting, deleting, bevel, bisect, clean-up and decimate, UVs, vertex colors, geometric queries and mesh quality, and a garment checked against its body
blender_materials Materials, Principled settings, procedural patterns, image textures, volumes, texture baking
blender_nodes Node groups, nodes and links, geometry-node groups, and the compositor
blender_lighting Lights, IES, light linking, light probes, cameras, aiming, the world, and the viewport's shading
blender_animation Keyframes, actions, NLA, drivers, armatures and bones, shape keys, weights, constraints, and sound on the timeline
blender_rigging Control rigs: Rigify metarigs, rig types, bone collections, generating and regenerating, IK/FK snapping, FK and IK controls over a deform skeleton, and a pose library
blender_motion Editing motion already keyed: motion paths, a pose change spread over frames, keys smoothed, thinned or blended, transforms matched between objects, action slots, NLA strips, and Grease Pencil drawing
blender_physics Rigid bodies, cloth, soft body, fluid, dynamic paint, force fields, baking, and particles
blender_render Render settings, stills and animations, color management, view layers, and comparing a render to a reference
blender_io Scene and mesh import and export, the game-ready recipe, the Blender-to-Unreal round trip, a whole kit sent to Unreal in one call, and generated assets
misc Anything no category rule places, so nothing is left out
  • Choose at startup with MIF_TOOL_PACKS in the server's environment, for example "MIF_TOOL_PACKS": "core,world" in .mcp.json. core comes with any named pack. Unset, or lean, is the three-tool default above; all registers every tool, as 1.0.0 did by default.
  • Add one mid-session. mif_list_packs shows every pack and what is loaded, and mif_enable_pack loads one. Clients that support tool-list updates show the new tools at once; otherwise, restart with the pack added to MIF_TOOL_PACKS.
  • Nothing becomes unreachable. Every tool belongs to a pack, and find_tools also searches the tools that are not loaded, naming the pack that has them.
  • Pack prompts. Each pack also appears as a prompt, mif-pack-<name>, which your client lists alongside its commands. It tells the agent what the pack is for, enables it, and carries the working rules. A prompt costs nothing until you pick it.

How it behaves

  • stdout is the protocol. It carries the MCP JSON-RPC stream, so all logging goes to stderr. Anything that prints to stdout would corrupt the stream.

  • Every tool returns the backend's JSON unchanged. ok, error and the read-back fields come straight from the editor.

  • Blender is connected lazily, on the first Blender call and never at startup. If Blender is closed, that call answers {"ok": false, "error": ...} naming the fix. It is never a server fault you have to debug.

  • Any Blender, on any port. From 1.2, each MifBlender records where it listens. bl_status lists the other live ones, and bl_status with port or pid switches the session to one, with no restart. When the usual port refuses and one other MifBlender is running, the refusal names it.

  • The Blender connection is one serialized socket, so a long operation blocks the ones behind it. bl_status limits its own wait, and when the line is busy it reports which operation holds it and for how long.

  • The timeouts are a ladder. The add-on abandons a job after 150 seconds, which must stay below MIF_BLENDER_TIMEOUT. That way Blender gives up first and the socket carries a real error, instead of the server abandoning a call that Blender goes on executing.

  • A write is never run twice. Every Unreal call carries a request id. When a write's reply times out, the answer says the outcome is unknown and is not retryable, with the id; the identical call sent again replays the first result, and request_status reads what became of it. A read that times out stays retryable.

  • It checks the versions it talks to. The plugin and the add-on report their protocol version and what they accept. When that disagrees with what the server's tools send, the first reply says which side is older, what it costs by name and how to update. A newer MifBridge seen by the plugin's update check is mentioned once, on the first reply from that editor.

Shaping a response

From 1.2, every tool takes a few reserved keys, in a direct call's arguments or inside mif_call's args. They are added to no schema, and the editor never sees them.

Key What it does
_select / _omit Keep or drop dotted paths of the answer, through lists row by row. ok and error are always kept, and a selected path found nowhere is named.
_page with _cursor _page 50 returns 50 items of the answer's longest list with a nextCursor. Later pages come from the server's copy of that one read, so the editor is not called again and no row is skipped or repeated.
_wait On a job-status tool, _wait 120 polls every 2 seconds until the job ends, sending a progress notification each time.

Editors and games the server starts

From 1.2, the server can run Unreal for you, as processes it owns:

  • mif_editor starts an editor for a .uproject on a free port with dialog-free flags, waits until the bridge answers as that process, and stops, restarts or lists the editors it started. It refuses to stop one while packages are unsaved, unless told to discard them. build builds the editor target, refused while an editor has the project open, with compiler errors returned by file and line.
  • mif_run starts the game standalone, or a packaged build, with named profiling flags and a trace from the first frame, and converts a map to World Partition or builds its HLODs through the engine's own commandlets.
  • mif_analyze_trace reads a recorded trace back with no window: the slowest timers on a thread and the frames over a budget. mif_ini reads a config key layer by layer, as the engine resolves it.

Updating from 1.0.0

The server moved from tools/mcp-server/ to Content/Python/MifBridge/mcp-server/, where Fab's rules put a plugin's Python. A config written for 1.0.0 names .../tools/mcp-server/server.py, which the update removes. Press SETUP ▸ Set up Claude Code again, which replaces its own earlier entry, or change that path in the config's args. A copy from GitHub is unchanged: it keeps tools/.

1.0.0 also registered every tool by default. 1.1 registers three and reaches the rest through find_tools and mif_call (see Tool packs); set MIF_TOOL_PACKS=all for the old behavior.

Upgrading from 0.2.0

The server moved from tools/ue5-mcp-bridge/ to tools/mcp-server/. An old .mcp.json keeps working, because a small forwarding shim is left at the old path and prints a deprecation notice to stderr. Update the path when convenient; the shim will be removed in a later release. This applies to the GitHub download: the store package, from Fab, mifshowcase.store or Gumroad, does not carry the shim, because no store release ever used the old path.