This is the core product. A Node/TypeScript Model Context Protocol server that exposes Hayba's tool surface to an agent host (Claude / GPT / any MCP client) over stdio, and bridges those tools to a running Unreal Engine 5 editor over a TCP seam.
Agent host ──stdio──▶ @hayba/mcp ──TCP──▶ UE5 C++ plugin
(Claude/GPT) (this package) (unreal/HaybaMCPToolkit)
One protocol across two language boundaries. The TCP envelope is the single most important invariant in the repo — see
../../CONTEXT.mdfor the domain language and../../docs/adr/for the recorded decisions. (docs/ARCHITECTURE.md, referenced by the root README, is a planned long-form expansion of the CONTEXT.md seam section.)
- MCP module — the interface is the set of MCP tools plus their Zod
schemas. The server is started in
src/index.ts: it registers catalog resources (pcgex://catalog/{category}), registers tools viaregisterTools, starts the local web dashboard, connects aStdioServerTransport, and background-probes the visual sidecar. - TCP client seam —
src/tcp-client.tsis the Node adapter that talks to the UE plugin'sFHaybaMCPTcpServer. Both sides must agree on a length-prefixed JSON envelope{ cmd, id, params, auth? }. - Schema registry —
src/tools/schema-registry.tsrecords the Zod shape of every tool at registration time so signatures are derived from the same schema used to validate inputs — never a hand-maintained dict that drifts.
Requires Node ≥ 22.5 (see engines in package.json;
older Node crashes on the node:sqlite-adjacent native deps).
npm install # from the repo root (npm workspaces)
npm run build -w @hayba/mcp # builds the dashboard, then `tsc`
node mcp-tools/hayba-mcp/dist/index.jsScripts (package.json):
| Script | Action |
|---|---|
build |
build:dashboard then tsc |
build:server |
tsc only (skip the dashboard) |
dev |
tsc --watch |
start |
node dist/index.js |
test |
vitest run |
typecheck |
tsc --noEmit |
The package also exposes a hayba-mcp bin (./dist/index.js), so an MCP
host can launch it directly once built.
npm testhere (tsc --noEmit+ vitest) is the authoritative local gate. Run it before pushing.
All via environment variables (src/config.ts):
| Var | Default | Purpose |
|---|---|---|
UE_TCP_HOST |
127.0.0.1 |
UE plugin host |
UE_TCP_PORT |
52342 |
UE plugin port (plugin auto-falls back 52343–52350) |
DASHBOARD_PORT |
52360 |
Local web dashboard (kept clear of the UE 52342–52350 walk) |
HAYBA_CODE_MODE |
on (off to disable) |
Progressive tool discovery (see below) |
HAYBA_NODE_CATALOG |
resolved | Override PCGEx node_catalog.json path |
HAYBA_PCGEX_DB |
resolved | Override PCGEx pcgex_registry.db path |
HAYBA_CRITIQUE_ENABLED / HAYBA_CRITIQUE_THRESHOLD |
on / 15.0 |
Terrain self-critique |
Resource paths (node_catalog.json, pcgex_registry.db) are resolved by
walking a fallback list — new plugin layout, workspace Resources/, legacy
Hayba_PcgEx_MCP layout — so existing installs keep working.
By default the server exposes only three meta-tools instead of the full ~100-tool catalog:
list_tool_categories— enumerates the handler domains and the command names within each (src/tools/code-mode/list-tool-categories.ts); disabled tools are filtered out.get_tool_signature— derives a command's parameter schema from the Zod registry on demand, with a "did you mean" suggestion on a miss (src/tools/code-mode/get-tool-signature.ts).python_run— executes a script through UE'sPythonScriptPluginover the TCP seam for anything the typed commands don't cover (src/tools/python/python-run.ts); filesystem/subprocess (Tier 3) access is gated behindallow_unsafe.
The full catalog is registered eagerly only when HAYBA_CODE_MODE=off
(see the if (config.codeMode) return; guard in
src/tools/index.ts). This is a deliberately deep
module: a tiny interface hiding a large surface, so a multi-domain task
doesn't pay the token cost of every schema up front.
src/tcp-client.ts (UETcpClient) connects to
127.0.0.1:52342 by default. Wire format:
- Length-prefixed JSON. A 4-byte little-endian length header precedes the UTF-8 JSON body.
- Request:
{ cmd, id, params }(TcpCommand). - Response:
{ id, ok, data?, error? }(TcpResponse), correlated back to the caller byid. - The client tolerates partial reads (it buffers until a full frame arrives)
and rejects all pending requests on socket close. The matching adapter is
the UE plugin's
FHaybaMCPTcpServer; the plugin publishes its actual port toSaved/HaybaMCP/instances/<pid>.jsonfor multi-editor setups.
addons/visual-embeddings is a Python FastAPI
sidecar (CLIP / SpatialCLIP / OWL-ViT) used for spatial grounding and physics
validation. src/index.ts background-probes it at startup
(pingSidecar) and caches availability so visual tools and
hayba_check_ue_status can branch on it without paying connect-timeout
latency. It is optional and degraded-mode aware — the server runs
without it. Setup: addons/visual-embeddings/README.md
and ../../docs/getting-started.md (Tier 2).
Other addons:
addons/workflows—SKILL.mdworkflow guides (hayba-new-scene,hayba-refine-scene,hayba-debug-level,hayba-pcg-build) a Claude Code host surfaces for matching tasks (Tier 3).dashboard/— the Vite/React local web dashboard served bysrc/dashboard/server.ts.
- Add a handler module under
src/tools/(or a domain subfolder) exporting a Zodschemaand a handler of typeToolHandler. - Register it in
src/tools/index.tsvia the wrappedserver.tool(...). Registration also callsrecordSchema(name, { shape, cost, returns })so the schema registry knows the command — regardless of whether Code Mode eagerly registers it. - If the command is dispatched into UE, ensure the UE plugin has a matching
handler (see
../../unreal/HaybaMCPToolkit/README.md) and that both sides agree on the{ cmd, id, params }envelope. - Run
npm test -w @hayba/mcp(tsc --noEmit+ vitest).
Eagerly-registered tools are only exposed to the agent when Code Mode is off; under Code Mode they are reached through
python_run/ discovered vialist_tool_categories. Recording the schema keepsget_tool_signatureaccurate either way.
src/
index.ts MCP server entrypoint (stdio + dashboard + sidecar probe)
tcp-client.ts UE TCP adapter (length-prefixed JSON envelope)
config.ts env-driven config + resource path resolution
resources.ts pcgex://catalog/{category} resources
catalog.ts PCGEx node catalog access
tools/
index.ts registerTools — the single registration point
schema-registry.ts Zod-shape registry feeding get_tool_signature
code-mode/ list_tool_categories, get_tool_signature
python/ python_run
actor|scene|editor|visual|material|plumb/ … domain tool modules
agents/ dashboard/ … supporting modules
addons/workflows SKILL.md workflow guides
dashboard/ Vite/React local dashboard
The Python visual sidecar lives at ../visual-sidecar.
../../CONTEXT.md— domain language, the protocol seam../../docs/adr/— recorded architectural decisions../../unreal/HaybaMCPToolkit/README.md— the UE5 plugin (the other adapter on the seam)../visual-sidecar/README.md— the Python visual sidecar