Skip to content
Jigwright
HullForge docs

How it works

Two processes, and why it is built that way.

HullForge is two programs, not one.

The two halves

The editor plugin is C++ running inside Unreal. It holds every tool, and it is the only part that touches your project. It opens a TCP listener on loopback and does nothing until something connects.

The connector is a compiled binary that Claude Desktop launches. It speaks MCP over stdin and stdout to Claude, and a small length-prefixed JSON protocol over the socket to the editor. It holds no tools of its own.

Claude Desktop  <--MCP/stdio-->  connector  <--127.0.0.1-->  Unreal editor

Why not one process

Embedding an MCP server directly in the C++ plugin would mean one program instead of two, which sounds simpler. It is not, for three reasons.

The MCP surface changes far more often than the editor bindings. Splitting them means the protocol layer can be rebuilt in seconds without recompiling a C++ module and restarting Unreal.

The editor’s game thread is precious. Everything that touches a UObject has to run on it, and anything slow there freezes the editor. Keeping the protocol, framing, retries and transport outside means only the actual work is marshalled onto that thread.

Crash isolation. A fault in protocol handling takes down a small external process, not your editor with unsaved work in it.

How the connector finds the editor

You configure nothing. Each running editor advertises itself in two places:

File Purpose
<project>/Saved/HullForge/session.json Project-local, useful when debugging
%LOCALAPPDATA%/HullForge/sessions/<project>-<pid>.json User-global, how clients discover editors

Each holds a port, a random session token, the project name and path, and a process id. Both are written when the editor starts listening and removed when it closes. Entries left behind by a crash are swept on the next startup, and clients check the process id anyway, so a dead editor never masquerades as a live one.

This is why several projects can be open at once, and why nothing needs reconfiguring when the port changes.

Why the tool list changes on its own

The connector declares the MCP listChanged capability and watches that registry. When an editor appears, it tells Claude to re-fetch the tool list; when one goes away, it does the same.

That is what removes the restart. MCP servers are launched by the client, so a connector that starts before the editor would otherwise report an empty list forever, because the client has no reason to ask again.

Two tools are implemented in the connector itself rather than the editor, so they are always available, including when no editor is running. hf_bridge_status reports which editors it can see and what to do if the answer is none, and hf_list_tool_areas reports what areas exist. That means “nothing is here” is never a silent state: an empty list would be baffling, whereas two tools that explain themselves is a diagnosis.

Two more, hf_enable_tool_areas and hf_disable_tool_areas, appear only when catalog mode is on, because a tool that would do nothing is worse than a tool that is absent. That is the same listChanged mechanism again: switching an area on re-fetches the list without a restart.

What crosses the wire

Only what a tool returns. The connector holds no state between calls beyond a short deduplication cache, and nothing is written to disk except the session files described above.

Every mutating call carries an operation_id. If the transport drops and the call is retried, the editor recognises the id and returns the original result rather than applying the change twice.