Skip to main content
Glama
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).