bg3-data-mcp
Allows launching and restarting Baldur's Gate 3 via Steam into the newest save, and discovers Steam installations and libraries to locate the game.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@bg3-data-mcpshow me the resolved stats for Shout_ActionSurge and which layer set each field"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
bg3-data-mcp
An MCP server (and CLI) for Baldur's Gate 3 modding: layered game-data lookup, static checks that catch what the engine silently ignores, in-game testing through Script Extender, and export to the Larian Toolkit for mod.io publishing. Works natively on Windows or under WSL, finds the game and tools itself, and isn't tied to any one mod.
Layered data: the base game read straight from the installed paks (
Shared→Gustav→GustavX→ hotfixPatch*.pak, via LSLib'sDivine.exe), so it always matches the current patch, plus your mod layers (unpacked folders or.paks) in load order. Every resolved field says which layer set it. Indexed: stats, English localization, root templates, progressions, lists, class descriptions, level maps, action resources, feats, MultiEffectInfos and named.lsfxeffects.Static checks:
bg3_lint_stats(values, functions and fields no shipped content uses - the engine drops them silently - missing references, spells that can't resolve) andbg3_lint_progressions(invalid node UUIDs, dangling lists, stacked choices).Running game (Script Extender): Lua eval, console commands, hot-loading stats without a restart, ground-truth comparison of what the game actually loaded, and a test framework: level up by XP, check a level against its progression, and TOML test cases run as real encounters (docs/TESTING.md).
Deploy and Toolkit: pack/deploy/enable any mod (
bg3_deploy), restart the game into the newest save, and generate or diff the Toolkit's editor copy (docs/TOOLKIT.md).
The SQLite index is cached per machine (see Configuration). A layer is rebuilt only when its sources' timestamps or sizes change; rebuilds are atomic, so a failed rebuild keeps serving the previous index.
Not affiliated with Larian Studios. Requires a legal copy of the game; nothing from the game is redistributed - data is read from your own install.
Resolution rules (stats)
The highest-ranked
new entry NAMEamong the active layers wins.using "NAME"(the entry's own name) inherits the previous layer's definition of NAME.using "OTHER"inherits OTHER, resolved across all active layers.No
using: the entry stands alone. A redefinition withoutusingreplaces the earlier one.Every resolved field records the layer and source that set it (e.g.
base/GustavDev,dnd55e).
Related MCP server: DesyncedMCP
Tools
Tool | Purpose |
| layers, load order, source timestamps, counts |
| re-index changed layers ( |
| manage mod layers |
| resolved stats entry: |
| what a layer changes about an entry compared with the layers below |
| find entries by name or field value; |
| everything mentioning a name or GUID (stats, templates, progressions, lists) |
| handle lookup or text search |
| root template resolved through its ParentTemplateId chain |
| class/subclass nodes merged by node UUID |
| spell/passive list by UUID or name |
| a spell's effects, animations, sounds and icon |
| spells like X, with visual kits to borrow |
| a MultiEffectInfo (or effect resource): component VFX names, bones, duration, looping, |
| find effects by name, every word in any order ("necrotic beam") -> GUIDs ready for |
| kill the game, run the layer's |
| grant exactly the XP for the next level; compare the host with its class/subclass progressions |
| data-driven in-game test cases (TOML in the mod repo) run as real encounters: see docs/TESTING.md |
| static checks before deploying: values the engine silently drops (vocabulary learned from the other layers), missing references, unknown resources; progression UUIDs, dangling lists, stacked choices |
| Larian Toolkit (mod.io publishing): where the Toolkit expects the mod, generate its editor copy (.stats/.tbl) from the game-ready files, and diff the two copies - formats learned from vanilla + dnd55e editor data |
| every stats entry a layer defines vs what the running game loaded (invalid values the engine dropped) |
Install
Works natively on Windows or under WSL; the game, Script Extender and LSLib are Windows programs either way.
Needs uv, Python 3.11+, and LSLib v1.20.4+
(releases; Vortex's bundled divine.exe is too old for current LSF files).
Windows (PowerShell):
git clone <this repo> C:\Mods\bg3-data-mcp
cd C:\Mods\bg3-data-mcp
copy layers.example.json layers.json # then list your mod folders (see below)
uv run python tests\env_check.py # what it found: game, Divine.exe, mod managers, Script Extender
uv run bg3-data refresh # first index build: a few minutes (extracts from the game paks)
claude mcp add bg3-data -- uv run --quiet --directory C:\Mods\bg3-data-mcp bg3-data-mcpWSL: keep the environment on the Linux filesystem (fast), the project anywhere:
export UV_PROJECT_ENVIRONMENT=$HOME/.cache/bg3-data-mcp/venv
cp layers.example.json layers.json # then list your mod folders
uv run python tests/env_check.py && uv run bg3-data refresh
claude mcp add bg3-data -e UV_PROJECT_ENVIRONMENT=$HOME/.cache/bg3-data-mcp/venv -- \
uv run --quiet --directory /mnt/d/path/to/bg3-data-mcp bg3-data-mcpConfiguration (layers.json)
Only your mod layers are required; everything machine-specific is discovered and can be overridden.
Paths may be written Windows-style (D:\\Mods\\MyMod) or WSL-style (/mnt/d/Mods/MyMod) - both work on both.
{
"mods": [
{"name": "dnd55e", "path": "C:\\BG3Mods\\dnd55e"},
{"name": "mymod", "path": "C:\\BG3Mods\\MyMod", "tests": "tests/bg3", "deploy": "optional custom command"}
],
"base": {"game_data": "E:\\Games\\Baldurs Gate 3\\Data"},
"divine": "C:\\Tools\\LSLib\\Packed\\Tools\\Divine.exe",
"game": {"launcher": "auto", "profile": "Public", "larian_dir": "...", "steam_exe": "...", "game_exe": "..."}
}Setting | Discovered from (when omitted) |
| Steam (registry + every library in |
|
|
|
|
|
|
|
|
mod | none: |
cache |
|
Mod managers
bg3_environment reports what manages the game's Mods folder. Vortex (detected from its deployment
manifest) and BG3 Mod Manager (detected while running) rewrite modsettings.lsx when they deploy or
export a load order, which disables mods they don't manage: re-run bg3_deploy afterwards (it re-enables the
mod after its dependencies), or add your dev mod to the manager. The in-game mod manager lists local paks
under Installed and needs nothing extra.
Script Extender bridge (running game)
These tools talk to the live game through the SE console, using the bundled bg3data/ps/se_inject.ps1
(AttachConsole + WriteConsoleInput, so no window focus is needed). Output is read back from the current
run's Extender Runtime log. Log file names are UTC; the bridge compares real modification times with
the game's start time.
Tool | Purpose |
| game running? PID and start time, this run's log, latest game state |
| run Lua (server/client); returns the return value as JSON plus printed lines. Runs in your live game. |
| one console line (e.g. |
| tail this run's log |
| ground truth: the entry as the game loaded it vs the index, field by field |
Hot loading (no restart)
Tool | Purpose |
| mirror a mod layer's stats |
| delete the loose |
| console |
SE only reads safe relative paths through the game's file system (absolute paths are rejected by
IsSafeRelativePath), which is why layers are mirrored as loose files. Entries created after startup must
be synced; the tool does that. Hot loading covers stats, loca and Lua. Progressions, lists and templates
load at startup and need a restart with a pak. Stats files with // comments load fine (the lines are skipped).
Measured 2026-09-30: all 661 Apotheosis entries in 3.0 s and 755 loca strings in 2.6 s. The edit → hot-load
one file → re-test loop takes about 3 s. Test-only: don't save while relying on hot-loaded entries.
Each eval is wrapped in unique BEGIN/END markers and pcall, so Lua errors come back as errors rather
than timeouts. SE replaces load() (its second argument must be an environment table). Console access is
serialised. Functor fields (SpellSuccess...) are exposed by SE as parsed userdata and can't be compared
as text. SE reports ComboCategory as empty.
Hardening
One SQLite connection shared by MCP worker threads, serialised with a lock (WAL mode).
Every tool catches errors and returns a readable message; free-text inputs are capped at 500 characters (SQLite's LIKE limit),
limitis clamped to 1-500, and output is capped at 24,000 characters.%and_in user text match literally (LIKE ESCAPE).Resolved entries are cached per layer stack; the cache is cleared on any rebuild.
Base extraction goes to a temp directory and is swapped in, so a failed extraction keeps the old cache.
The first call after a game patch rebuilds
base(about 80 s). Runuv run bg3-data refreshafter patches to do it ahead of time.
Tests
uv run python tests/stress_test.pydrives the real server over stdio with the official MCP client: protocol, correct answers, bad input, concurrency (400 calls, 32 at a time), refresh under load,.paklayer add and remove, and a full resolution sweep. It writestests/STRESS_REPORT.md.uv run python tests/ingame_check.py [--layers dnd55e] [--sample 400]compares resolved entries with the running game through SE. The deployed paks must match the layers. It writestests/INGAME_REPORT.md. The first run (2026-09-30) compared 400 entries (200 mod-overridden) and 7,844 fields: 18 mismatches (0.23%). 16 wereComboCategory(SE doesn't expose it) and 2 were one quirk (MULTIATTACKDEFENSE: the game didn't inherit DisplayName through dnd55e'susing). A targeted test of the 72 cases where "override re-parents viausing" and "usingignored on override" predict different values sided with the resolver's model 78:1.
Known limits
SpellAnimationGUIDs are animation slot keys mapped per race and body across about 2,500 content banks, so they aren't resolved to names yet. Copy them between spells as-is.About 0.7% of MultiEffectInfo components point at effect resources outside the indexed banks.
This server cannot be deployed
Maintenance
Related MCP Connectors
Savecraft serves real save game data and expert game knowledge to AI assistants.
Connect any AI to your Foundry VTT world: actors, combat, dice, journals, tokens, compendiums.
Campaign manager for D&D and TTRPG GMs: your AI reads and writes a live typed campaign database.
Control Unreal Engine to browse assets, import content, and manage levels and sequences. Automate…
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to search, browse, and manage mods across Nexus Mods, mod.io, Thunderstore, and Modrinth, as well as perform local diagnostics like detecting games and parsing crash logs.MIT
- FlicenseAqualityCmaintenanceEnables AI assistants to develop Desynced mods by providing direct access to the game's Lua API reference, base-game source, live logs, and installed mods, plus live control via a debugger link for evaluating and reloading Lua in the running game.9-
- AlicenseBqualityAmaintenanceEnables AI agents and scripts to inspect objects, call functions, and run Lua in a running UE4SS game via MCP, with no sockets or admin rights required.2624 PyPI1MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to build, run, and debug Godot projects by editing scenes and scripts, inspecting live game state, injecting input, capturing viewports, and examining native debugger state through 42 tools.European Union Public 1.2