Grimoire
README.md
# Grimoire — UE5 Context Bridge
Read-only MCP server that gives Claude (or any MCP client) live access to your UE5 project — Blueprints, interfaces, variables, functions, event graphs, materials, structs, and Data Assets.
```
Claude → MCP Server (stdio) → IPC Bridge (TCP) → Unreal Host (in editor)
```
- **MCP Server:** Exposes tools to the client, routes requests over TCP
- **Unreal Host:** Runs inside the UE5 editor, executes queries via Unreal Python API
**Status:** Actively evolving. Inventory tools are solid; bounded live **flow / symbol / references** query is promoted and sealed on real project assets, but fidelity is still incomplete in places (see [Known Limitations](#known-limitations) and [CHANGELOG.md](./CHANGELOG.md)). Prefer bounded tools over dumping whole graphs.
---
## How It Works
See [METHODOLOGY.md](./METHODOLOGY.md) for how the UE5 Python API surface was mapped — including the dead ends.
At a high level Grimoire combines:
1. **SubobjectDataSubsystem** — component hierarchy
2. **JsonObjectGraphFunctionLibrary.stringify()** — variables, types, Data Asset values, live graph capture
3. **AssetExportTask T3D export** — function signatures, thin exec summaries, bindings
4. **Live pin decode + canonical index** — exact pin identity, links, and bounded flow walks
Requires the **Json Blueprint Utilities** plugin (built-in, free).
---
## What This Unlocks
Grimoire gives Claude live read access to your UE5 project. Combined with other MCP servers:
- **Grimoire + Notion** — architecture notes grounded in live Blueprints
- **Grimoire + GitHub** — issues / PR descriptions from actual graph state
- **Grimoire + Slack** — technical summaries without hand-describing systems
- **Grimoire alone** — in-editor reasoning, bug hunting, refactors
The pattern: **Grimoire provides UE5 context; other MCP servers act on it.**
---
## Prerequisites
- Python 3.10+
- UE5 project with **Python Script Plugin** enabled
- **Json Blueprint Utilities** plugin enabled (built-in, free, Epic Games)
- Claude Desktop or another MCP client
---
## Installation
### 1. Install Python dependencies
```bash
pip install -r requirements.txt
```
### 2. Configure the project
Copy the example config and set your UE5 project path (the folder containing your `.uproject` file):
```bash
cp config.toml.example config.toml
```
On Windows (PowerShell): `Copy-Item config.toml.example config.toml`
Edit `config.toml` and set `root` under `[project]`. `config.toml` is gitignored — keep your real paths local only. See `config.toml.example` for all available keys.
### 3. Install the Unreal Host
The editor must be able to import `ue5_host` on its Python path. Two common approaches:
- **Copy** — Copy the entire `ue5_host` folder into your project (e.g. paste it at `YourProject/Content/Python/ue5_host/`). No symlink required; this is the simplest option on Windows.
- **Symlink** — Point `Content/Python/ue5_host` at a single checkout elsewhere if you prefer not to duplicate files.
Target layout inside your UE5 project:
```
YourProject/
└── Content/
└── Python/
└── ue5_host/
├── ue5_host.py
├── handlers.py
└── __init__.py
```
You can also skip copy/symlink and pass a **full absolute path** to the startup script instead (see step 4).
### 4. Enable the Host in UE5
- Open your UE5 project
- **Edit → Project Settings → Plugins → Python**
- Under **Startup Scripts**, add: `ue5_host.ue5_host`
- Or the full path, e.g. `C:/path/to/grimoire-ue5/ue5_host/ue5_host`
- Restart the editor (or run the script manually once)
### 5. Register the MCP Server with Claude Desktop
Edit your Claude Desktop config (`%APPDATA%\Claude\claude_desktop_config.json` on Windows):
```json
{
"mcpServers": {
"ue5-context": {
"command": "python",
"args": ["-m", "ue5_mcp.mcp_server"],
"cwd": "C:/path/to/grimoire-ue5",
"env": {
"UE5_MCP_CONFIG": "C:/path/to/grimoire-ue5/config.toml"
}
}
}
}
```
Replace `cwd` and `UE5_MCP_CONFIG` with your actual paths. Add other MCP servers (Notion, GitHub, Slack etc) to the same config to enable multi-server workflows.
After pulling host changes, call `reload_host(confirm=True)` (or restart the editor). **New MCP tool schemas** (for example Rank 4 query tools) require restarting the MCP server process, not only `reload_host`.
---
## Tools
### Inventory (thin by default)
| Tool | Description |
|------|-------------|
| `ping` | Check if the UE5 editor host is reachable |
| `reload_host` | Reimport `ue5_host` modules without restarting the editor listener (`confirm=True`) |
| `list_blueprints` | List Blueprint assets (optional: `path_prefix`, `name_substring`) |
| `get_blueprint` | Thin Blueprint inspection: parent, components, variables, signatures, interfaces. **Omits** `functions[].body` by default |
| `list_components` | Components on a Blueprint actor |
| `get_variables` | Variables with types; additive `type_normalized` / `container`. `include_locals=True` for function-scope locals |
| `list_interfaces` | Blueprint Interfaces in the project |
| `get_interface` | Interface inspection (same path as Blueprint assets) |
| `asset_search` | Search assets by class and name |
| `find_event_bindings` | Bind / broadcast / handler sites + interface implementors. Prefer `blueprint_name` or `path_prefix` |
| `query_cache` | Query the SQLite cache by parent class, function, variable, or type reference |
| `get_data_asset` | Property values from a **PrimaryDataAsset instance** (not a DA Blueprint class) |
| `get_struct` | UserDefinedStruct fields and types |
| `get_material` | Material / MaterialFunction parameters, outputs, function calls |
### Opt-in depth on `get_blueprint`
| Flag | What you get |
|------|----------------|
| `include_body=True` | T3D exec **summaries** for single-entry function graphs. Multi-entry EventGraphs **hard-omit** body (`EVENTGRAPH_BODY_UNATTRIBUTED`) — do not treat empty/missing body as “no logic” |
| `include_flow=True` + `flow_graph_name` | Bounded live exec/data neighborhood under `flow`. Use `flow_event_name` or `EventGraph::Interact` to scope one entry |
### Rank 4 — bounded query (preferred for graphs)
| Tool | Description |
|------|-------------|
| `query_blueprint_flow` | Bounded exec/data walk from an entry or exact node/pin. Supports `EventGraph::EventName`. Returns shaped `node` / `hop` / `terminal` records with budgets — never a full snapshot |
| `query_blueprint_symbol` | Bounded function / event / interface **signature** (no body dump) |
| `query_blueprint_references` | Bounded BPI / delegate / variable / call-site joins for one Blueprint |
**Retrieval rule:** never ask for an entire EventGraph or raw serial dump as the answer format. Expand with `include_flow` / Rank 4 tools and raise `max_depth` / `max_records` intentionally when a walk comes back `FRONTIER_TRUNCATED` or record/byte-capped.
LLM-oriented QA expectations and reason codes: [qa/QA_BRIEF.md](./qa/QA_BRIEF.md).
---
## What Grimoire Can Read
### Blueprints
- **Parent class**, **components**, **variables** (with additive `type_normalized` / `container`)
- **Function / event signatures**; implemented interfaces when gen_class or ImplementedInterfaces JSON yields them
- **Additive BPI contracts** on implementors — `functions[].interface_contract` (native `inputs`/`outputs` are never overwritten)
- **Opt-in T3D body summaries** (flat opcodes — not branch-attributed truth)
- **Bounded live flow** — nodes, hops, unwired pin defaults / inbound data provenance on visited nodes
- **Reason-coded warnings** when data is omitted, partial, or budget-limited
### Data Assets
- **Configured instance properties** (not Blueprint class definitions)
- Wrong-kind matches fail fast with `DATA_ASSET_WRONG_KIND`
### Structs & materials
- UserDefinedStruct fields; material parameters, outputs, and function calls
### Cache
- SQLite persistence across sessions; dirty-flag invalidation after asset saves
---
### Thin body format (`include_body`)
When body is present, it is a **flat T3D exec summary**, not a full attributed CFG:
```
call SubscribeToStats_Player
set CachedInvComp
bind_delegate(OnInventorySheetUpdate)
branch
macro:IsValid
```
For branch conditions, wired producers, and pin literals, use **`include_flow` / `query_blueprint_flow`**.
---
## Known Limitations
Honest gaps — not silent failures:
- **Attributed control/data flow** — use Rank 4 / `include_flow`. Multi-event `include_body` is hard-omitted (`EVENTGRAPH_BODY_UNATTRIBUTED`) so LLMs do not treat mixed T3D chunks as per-event truth.
- **T3D LinkedTo gaps** — some macro / custom-event chains still yield `EVENTGRAPH_PARTIAL` when a body remains.
- **Flat body summaries** — `include_body` does not nest true/false branches.
- **Interface list still incomplete on some assets** — many Blueprints populate `interfaces[]`; some (e.g. certain components) still return empty with `INTERFACE_DATA_UNAVAILABLE`. `find_event_bindings` / Rank 4 references remain the fallback.
- **Collapsed graphs** — many recover to COMPLETE via JSON stringify fill; large merges may stay PARTIAL.
- **Ubergraph / tick-continuation** — unsupported / deferred; prefer scoped `path_prefix` / `blueprint_name` / `max_assets`.
- **Thin variables vs pin containers** — Map/Set fidelity lives on decoded pins / flow; thin lists expose additive `container` but still lean on element/key category in `type`.
- **Materials / levels / writes / cross-project** — not the current milestone (parked).
Some of these track UE5 Python / T3D export limits. Others are Grimoire scope choices (bounded retrieval over full-graph dumps).
---
## Switching Projects
- Update `config.toml`: change `[project].root` and optionally `[ipc].port`
- For multiple editors: set `UE5_MCP_PORT` per project (e.g. `65432`, `65433`)
- Restart Claude Desktop after config changes
---
## Troubleshooting
**Editor offline / Connection refused**
- Ensure the UE5 editor is open with your project loaded
- Confirm the host started (check Output Log for `UE5 Context Bridge: listening on...`)
- Verify `config.toml` port matches the host (default `65432`)
**Port conflict**
- Use a different port in `config.toml` and set `UE5_MCP_PORT` in environment
- Or run only one UE5 editor at a time
**Timeout**
- Increase `timeout_sec` in `config.toml` for large scans
- First call after MCP restart / `reload_host` can hit a short cold-start timeout — retry once
- Do **not** raise timeouts to “fix” wrong `get_data_asset` args; wrong-kind should fail fast
**Python startup script not running**
- Check that the Python Script Plugin is enabled
- Use the full absolute path to `ue5_host` in Startup Scripts if a relative path fails
**New tools missing from the client**
- Restart the MCP server process after pulling (schema is process-lifetime). `reload_host` alone is not enough for new tool definitions
**Cache stale after host code changes**
- Prefer `reload_host(confirm=True)`
- Cache DB: `YourProject/Saved/Grimoire/cache.db` (watchdog invalidates on asset save)
---
## Direction / Roadmap
**Done / in tree (see [CHANGELOG.md](./CHANGELOG.md)):** thin default Blueprint inspection, opt-in body/flow, Rank 4 bounded query, LLM UX honesty (body omit, inbound provenance, additive BPI contracts, budget reason codes), COLLAPSED promote path, Map/Set pin corpus, FPC delegate handler harden.
**Next (not claimed done):** broader interface-list coverage, deeper pure-chain provenance, anim graphs, write ops, levels, cross-project diff, setup automation.
---
## License & contributing
Grimoire is dual-licensed. **AGPL-3.0** applies by default; see [LICENSE](./LICENSE) for the full text and [DUAL_LICENSE.md](./DUAL_LICENSE.md) for commercial licensing.
Contributions, issues, and PR expectations: [CONTRIBUTING.md](./CONTRIBUTING.md).
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessUnresponsive