Skip to content

Repository files navigation

acore-data

MCP server providing unified query access to 475 AzerothCore game datastores — DBC binary files, SQL tables, SQL overlays, and auxiliary stores. Plus terrain/pathfinding queries against MMap navmesh data, creature spawn analysis, database state audit, encounter rollups, record digests, mod configuration lookup, and C++ enum decoding. Exposes twelve tools (query, lookup, list, spawns, dbversion, encounter, travel, explain, config, enums, sql, terrain) over the JSON-RPC based Model Context Protocol.

Overview

AzerothCore stores game data in four categories of datastores. This server gives any MCP-compatible client (LLM, IDE plugin, CLI) a single entry point to query all of them by name, with automatic name resolution, type-aware field annotation, and smart SQL routing.

Category Count Description
dbc_backed ~112 Binary .dbc files loaded into packed C structs, with optional SQL overlay (*_dbc tables)
sql_objectmgr ~95 ObjectMgr SQL tables — creature templates, gameobjects, items, quests, gossip, etc.
sql_manager ~48 Tables loaded by other singleton managers (SpellMgr, PoolMgr, GameEventMgr, LootStore, …)
sql_auxiliary ~171 Discovered SQL tables not in the static registry

For the full technical reference on how each category is loaded in AzerothCore, see docs/datastores/README.md.

Tools

query

Query any datastore by name. Accepts a DBC file name ("Spell"), SQL table name ("quest_template"), or C++ struct name ("SpellEntry").

Parameter Type Description
name string Required. Datastore name. Use lookup to find valid names.
id number Primary key for O(1) lookup. If a filter is also given, both must match (AND).
filter object Named field filters. Supports $like / $ilike patterns.
fields array Select fields by index [38, 39] or name ["BaseLevel", "SpellLevel"]. Strict: unknown names are errors with suggestions.
limit number Max records to return (default 100).
compact boolean Strip null/zero fields (default true).
annotate boolean DBC rows as legacy per-field arrays with index/type/sql_column/source (default false = flat {name: value} rows). On SQL tables, attaches column types.
hints boolean Include field_references / referenced_by cross-reference metadata (default false).
links boolean Add metadata.links: one-hop relation map (related NPC/item/spell names) for the returned rows (default false; capped at 25 rows × 10 fields).
resolve boolean or array Resolve type-specific data fields. true = all, or ["dbc", "sql", "loot"].
resolve_max number Max items per loot table resolution (default 10). Use 0 for unlimited.

Result shape: rows are flat {field: value} objects. id/row_index lookups return a single object (or a specific error if the id is absent / does not match the filter); filter and unconstrained queries return a list. Locale arrays (e.g. name[0..15]) collapse to a scalar (or a list of non-empty values).

Examples:

query(name="Spell", id=118)
→ O(1) lookup for Polymorph, ~1 KB flat object

query(name="quest_template", filter={"Title": {"$ilike": "%murloc%"}})
→ SQL $ilike search across all quest titles

query(name="gameobject_template", id=180013, resolve=true)
→ Returns gameobject data with data[0-19] annotated (lockId, lootId, spellId, etc.)

query(name="quest_template", id=46, links=true)
→ metadata.links: quest NPC (Guard Thomas), required item (Torn Murloc Fin), reward items

query(name="Spell", id=118, fields=[38, 39])
→ Only BaseLevel and SpellLevel fields

For DBC-backed stores that also have an SQL overlay table, query merges both sources — SQL overlay data replaces or supplements the binary DBC data, and errors report which source failed.

lookup

Get schema and metadata for any datastore. Resolves by C++ struct name, SQL table, DBC file, or store variable (e.g. sSpellStore).

Parameter Type Description
query string Required. Name to resolve.
detail string "schema" (default) — full field list. "summary" — 10 sample fields.

Returns the per-field mapping (index, name, type, sql_column, plus notes/references where available), referenced_by cross-references, and access hints (e.g. sSpellStore.LookupEntry(id) -> SpellEntry const*). SQL-native tables additionally list live columns as name:type [PK].

Examples:

lookup(query="SpellEntry")
→ Full schema with all 183 fields, SQL columns, and cross-references

lookup(query="creature_template", detail="summary")
→ Compact 10-field sample + live SQL columns from the database

lookup(query="sSpellStore")
→ Resolves store variable to SpellEntry with access pattern hints

list

List available datastores with optional search and category filtering.

Parameter Type Description
search string Filter by struct name, table, DBC file, or store variable.
category string "all" (default), "dbc_backed", "sql_objectmgr", "sql_manager", "sql_auxiliary".
limit number Max entries to return (default 50). When truncated, metadata.total reports the full count.

Examples:

list(category="dbc_backed")
→ First 50 DBC-backed stores with field counts (total reported in metadata)

list(search="Quest")
→ Stores matching "Quest" in struct name, table, or DBC file

spawns

Creature spawn analysis for a creature_template entry — total world spawns, per-map breakdown (with map names resolved from DBC), and sample positions. Read-only; uses the creature, creature_template and map/Map.dbc tables. No mod required — works on any azerothcore-wotlk install.

Parameter Type Description
entry number Required. creature_template entry (the creature id).
map number Restrict the analysis to a single map ID.
limit number Sample positions to return (default 3, max 20).

Examples:

spawns(entry=32820)
→ Wild Turkey: 3125 spawns, map 0 (Eastern Kingdoms), sample positions

spawns(entry=1)
→ template exists but has_world_spawn=false (Waypoint, GM-only)

dbversion

Database state audit for this install — no arguments. Reports the core/DB version row (acore_world.version), per-database SQL update state (RELEASED/ARCHIVED/CUSTOM/MODULE/PENDING counts plus applied/pending totals), pending update names, and which of the four AzerothCore databases are present. acore_playerbots only exists with mod-playerbots; its absence is reported as installed: false, not an error.

Examples:

dbversion()
→ core_version (with fork/branch marker), db_version, per-DB tables/applied/pending,
  mod_playerbots_installed=true|false

enums

C++ enum decoder — indexes every named enum in the AzerothCore source tree (~1,044 enums, ~17.7k members, one cached scan) and resolves magic numbers. Answers "what does this value mean?" (enums(enum='Mechanics', value=17)MECHANIC_POLYMORPH) without the agent grepping the source. The source tree is optional (override with ACORE_SRC_ROOT); absence is a clean error.

Parameter Type Description
enum string Exact enum name.
value number Value to decode (with enum=) or scan across all enums.
member string Member-name substring for reverse lookup (with enum=).
search string Case-insensitive substring match on enum names.

Examples:

enums()
→ 1044 enums, 17713 members, largest enums by size

enums(enum="Mechanics", value=17)
→ MECHANIC_POLYMORPH (src/server/shared/SharedDefines.h)

enums(enum="SpellEffects")          full value table (capped)
enums(value=17)                     which enums contain 17 (ambiguity note)

config

mod-playerbots configuration index — indexes playerbots.conf.dist (setting → default + line) and the C++ GetOption call sites that read each key in one cached pass. Answers "what does this setting do / what's its default / where is it used" without reading the 900-line conf or grepping the mod. The mod source tree is optional (override its location with PLAYERBOTS_ROOT); absence is a clean error.

Parameter Type Description
key string Exact setting key → full detail incl. code refs.
search string Case-insensitive substring match on key names (capped 50).
rebuild boolean Force re-scanning the mod conf + source.

Examples:

config()
→ 888 settings, 384 code refs, counts by prefix

config(search="strategy")
→ EnableNewRpgStrategy, Max/MinRandomBotChangeStrategyTime, ...

config(key="AiPlayerbot.RandomBotCombatStrategies")
→ default "", conf line 1370, code ref: PlayerbotAIConfig.cpp:459

explain

Agent-friendly digest of a single record from any datastore — wraps the query pipeline (annotate + links) and distills it to: a one-line summary, the non-trivial fields (capped at 20, name pinned first), one-hop cross-references with resolved target names, and source provenance. For DBC-backed stores it reports which fields the live SQL overlay changed vs the vanilla DBC (overlay_overrides), and flags overlay-only records (ids that exist only in the *_dbc overlay tables, as in this reduced build).

Parameter Type Description
name string Required. Datastore name.
id number Required. The record's primary key (0 allowed).

Examples:

explain(name="Spell", id=118)
→ Polymorph (dbc) — 46 fields with values, 20 shown — 4 cross-reference(s)

explain(name="Spell", id=19)
→ SWORDSPECIAL (DND) — overlay-only record (no vanilla DBC row)

explain(name="quest_template", id=46)
→ Bounty on Murlocs — starters/enders: Guard Thomas, reward items resolved

encounter

Map/instance encounter rollup — what is in this place. Top creatures by spawn count with level ranges, rank (0=normal 1=rare 2=elite 3=worldboss) and loot item names for the top 5; top game objects (ores, doors, chests); instance metadata (script, allow_mount) when the map is an instance; and the mod-playerbots travel graph size when installed. Read-only, acore_world based — works on any azerothcore-wotlk install.

Parameter Type Description
map number Required. Map id.
limit number Max creatures to list (default 20, max 100).

Examples:

encounter(map=43)
→ Wailing Caverns (instance_wailing_caverns): Druid of the Fang (19, rare),
  Deviate Lasher (19), ... with loot; travel graph: 10 nodes / 1968 points

travel

Inspect the mod-playerbots travel graph and verify paths against the MMap navmesh — no running server needed. Three modes (all read-only; requires acore_playerbots, its absence is a clean error):

Parameter Type Description
map number Required. Map id.
node number Node mode: node details + named neighbours (capped 50 each).
from / to number Path mode: decode the stored path between two nodes (requires both).
verify boolean Path mode: check each point against MMap ground (default true; degrades to a note where the install has no .map data for the map).

Examples:

travel(map=0)
→ 644 nodes, 3010 edges, 295623 path points, sample named nodes

travel(map=0, node=0)
→ "Human start" + neighbours (Goldshire innkeeper, Northshire Valley spirithealer, ...)

travel(map=0, from=0, to=2776)
→ "Human start" → "Elwynn Forest Goldshire": 103 path points + navmesh_verification

sql

Execute raw SQL queries with automatic database routing and typo suggestions.

Parameter Type Description
query string Required. SQL query (SELECT, INSERT, UPDATE, DELETE only).

Features:

  • Smart routing — automatically directs queries to acore_world, acore_characters, or acore_auth based on table name
  • Typo suggestions — suggests correct table and column names on errors
  • Safety — blocks DROP, TRUNCATE, ALTER, GRANT, REVOKE
  • Context hints — e.g. empty loot_template results suggest trying questitem tables

Examples:

sql(query="SELECT entry, name FROM creature_template WHERE entry = 1")
→ Routes to acore_world

sql(query="SELECT id, username FROM account LIMIT 5")
→ Auto-routes to acore_auth

sql(query="SELECT * FROM creature_templat LIMIT 1")
→ Error with suggestion: "Did you mean: creature_template?"

terrain

Query map, VMap, and MMap terrain data — terrain height, liquid, area IDs, navmesh tiles, and cross-tile pathfinding on the Detour navmesh.

Parameter Type Description
subcommand string Required. One of: list_maps, list_tiles, height, liquid, area, coord, tile_info, vmap_info, tile_stats, map_info, pathfind.
mapId string or number Map ID (numeric) or name (e.g. "Eastern Kingdoms", "571").
x, y, z number World coordinates (required by subcommand).
tileX, tileY number Tile coordinates 0-63 (for tile-level queries).
data_type string "maps", "vmaps", or "mmaps" (for list_tiles, tile_info).
x1, y1, z1, x2, y2, z2 number Start/end coordinates (for pathfind).
flying boolean Ignore height constraints (for pathfind, default false).

Subcommands:

Subcommand Purpose
list_maps List all maps with file counts (ADT, VMap, MMap)
list_tiles List tiles for a map (maps, vmaps, or mmaps)
height Terrain height at (x, y)
liquid Liquid type/height at (x, y, z)
area Area table ID at (x, y)
coord Convert world coordinates to grid/tile
tile_info MMap/VMap tile header info
vmap_info VMap model info for a tile
tile_stats Navmesh statistics for a tile (poly count, vertex count)
map_info MMap navmesh parameters for a map
pathfind A* pathfinding between two points with cross-tile support

Pathfinding:

The pathfind subcommand runs A* on the Detour navmesh with on-demand tile loading, cross-tile external edge resolution, and funnel-algorithm corridor steering. Coordinates are in world space. The AC world→Detour transform (world_y, world_z, world_x) is applied automatically.

terrain(subcommand="height", mapId=0, x=1620, y=1530)
→ {"height": 52.34, "map_id": 0, "position": {"x": 1620, "y": 1530}}

terrain(subcommand="list_tiles", mapId=571, data_type="mmaps")
→ 433 MMap tiles for Wintergrasp

terrain(subcommand="tile_stats", mapId=571, tileX=23, tileY=24)
→ {"poly_count": 3639, "vert_count": 5832, "tile": [23, 24]}

terrain(subcommand="pathfind", mapId=571, x1=4683, y1=3824, z1=355, x2=4538, y2=3230, z2=403)
→ {"found": true, "distance": 649.0, "raw_path_length": 38, "smooth_path_length": 3,
   "smooth_path": [{"x": 4683, "y": 3824, "z": 355}, {"x": 4528, "y": 3244, "z": 357}, {"x": 4538, "y": 3230, "z": 403}]}

Cross-tile pathfinding works automatically: tiles are loaded on-demand as the A* search expands, and external edges (DT_EXT_LINK) are resolved by finding matching polygons in neighbor tiles via BV-tree search. Long-distance paths (2000+ yards) across many tiles are supported.

Type Resolver

The resolve parameter on query enables type-aware field resolution for tables whose fields change meaning based on a type column. Resolution types:

  • "dbc" — resolve to DBC entries (e.g. LockEntry, SpellEntry, MapEntry)
  • "sql" — resolve to SQL tables (e.g. quest_template, gossip_menu, page_text)
  • "loot" — expand loot templates into item lists with names

Registry-driven resolution

Any table with cross-reference metadata in datastore_registry.json gets automatic field resolution via _resolve_generic(). Fields like faction, lootId, spellId are resolved to their target entries by name.

Specialized table resolvers

In addition to generic registry-driven resolution, these tables have dedicated resolver modules that enrich results with custom data:

Table Resolver module What it resolves
gameobject_template resolvers/gameobject.py type-aware data[0-19] annotation (lockId, lootId, spellId …)
smart_scripts resolvers/smart_scripts.py EVENT_ID/ACTION_ID/TARGET_ID → enum names + value meaning
quest_template resolvers/quest.py starter/ender NPCs, POIs, quest chain (prev/next/breadcrumb)
conditions resolvers/condition.py polymorphic SourceType → entity name, ConditionType (~49 types: AURA, QUEST, ITEM, ALIVE, CLASS, etc.), TYPEID/GENDER/RACE enums
achievement_criteria_data resolvers/achievement_criteria.py CriterionType-specific field interpretation
item_template resolvers/item.py loot template for openable items (Flags & 0x04)
Spell (DBC) resolvers/spell.py cast conditions from conditions table with full enum resolution
query(name="quest_template", id=4512, resolve=true)
→ Start/ender NPCs, chain info, POIs, plus faction/spell/item refs

query(name="Spell", id=15698, resolve=true)
→ Cast conditions: "OBJECT_ENTRY_GUID(UNIT)=creature_template [Cursed Ooze], NOT_ALIVE"

query(name="item_template", id=11912, resolve=["loot"])
→ Openable item → 6x Empty Cursed Jar, 6x Empty Tainted Jar

query(name="conditions", filter={"SourceTypeOrReferenceId": 17, "SourceEntry": 15698}, resolve=true)
→ Polymorphic: source type name, condition type enum, resolved entity names

query(name="gameobject_template", id=12345, resolve=["loot"], resolve_max=20)
→ Expand loot template into up to 20 item names

Setup

Requirements

  • Python 3.10+
  • pymysql — installed via requirements.txt into .venv
  • Access to an AzerothCore MySQL instance (for SQL tools)
  • DBC binary files and DBCfmt.h from the AzerothCore source/build
  • MMap data files (.mmtile, .mm) for terrain/pathfinding queries (optional — terrain tool degrades cleanly without them)

Environment Variables

Variable Default Purpose
ACORE_DBC_PATH (alias DBC_PATH) /root/azerothcore-wotlk/env/dist/bin/dbc DBC binary directory
ACORE_FORMAT_FILE (alias DBC_FORMAT_FILE) /root/azerothcore-wotlk/src/server/shared/DataStores/DBCfmt.h DBC format strings
ACORE_DATA_PATH (alias DATA_PATH) /root/azerothcore-wotlk/env/dist/bin Terrain data base dir (uses maps/, vmaps/, mmaps/ subdirectories)
DB_HOST / DB_USER / DB_PASSWORD auto-detected Base DB connection (see below)
DB_PORT 3306 Base DB port
DB_NAME acore_world Base database name
DB_AUTH_{HOST,PORT,USER,PASSWORD,NAME} Per-database override for acore_auth
DB_CHAR_{HOST,PORT,USER,PASSWORD,NAME} Per-database override for acore_characters
ACORE_SRC_ROOT /root/azerothcore-wotlk AzerothCore source tree (enums tool; optional)
PLAYERBOTS_ROOT /root/azerothcore-wotlk/modules/mod-playerbots mod-playerbots tree (config tool; optional)
ACORE_SQL_TOOL_MODE full full = any statement (destructive blocked), readonly = SELECT only
ACORE_DATA_ROOT Project root for the pi bridge (see below)
ACORE_WORLDSERVER_CONF Path to your worldserver.conf when it lives outside the default locations (checked first)

Database configuration. When DB_HOST and DB_USER are unset, the server auto-detects from worldserver.conf (checked at ACORE_WORLDSERVER_CONF if set, then /root/azerothcore-wotlk/env/dist/etc/worldserver.conf, then ~/azerothcore-wotlk/env/dist/etc/worldserver.conf). The *DatabaseInfo lines may point Login (acore_auth) and Character (acore_characters) at a different MySQL host — detected differences are applied as per-database connection overrides, so a shared auth DB across realm machines works out of the box. acore_playerbots is not configured by worldserver and rides the base connection. Explicit DB_* env vars disable auto-detection entirely (single connection for all DBs). Precedence, merged per key: DB_AUTH_* / DB_CHAR_* env > worldserver.conf auto-detection > base config. If neither env vars nor a detectable worldserver.conf exist, the server warns on stderr and falls back to root@localhost.

Missing DBC path or format file produces a clear error at startup (and the server continues in SQL-only mode); missing terrain data warns and the terrain tool degrades cleanly per query.

Running

python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
.venv/bin/python3 server.py

Recommended: launch with the .venv Python (.venv/bin/python3). Without pymysql the server falls back to a mysql CLI subprocess — it works (params are interpolated and MYSQL_PWD is honored) but is slower.

If run via an MCP client, point the command at the venv's Python:

"command": ["/path/to/acore-data/.venv/bin/python3", "server.py"]

To test manually:

echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | .venv/bin/python3 server.py

pi (coding agent)

This project ships a first-class pi bridge at .pi/extensions/acore-data.ts. pi loads it automatically and registers all of the server's tools (fetched live via tools/list, so every current and future tool is available) as native pi tools. It hardcodes no paths or credentials — it inherits the ambient environment and the server self-configures (DBC path defaults + DB creds auto-detected from worldserver.conf). The project root is auto-located (in order): ACORE_DATA_ROOT env, pi's cwd, the extension's own symlink-resolved location (so a global ~/.pi/agent/extensions/acore-data.ts symlink works from any cwd), then ~/acore-data. To use a non-default project root or a non-default AzerothCore layout, export the relevant vars (ACORE_DATA_ROOT, DB_*, DBC_PATH, …) in pi's environment.

Windows

Fully supported (the server, tests, and pi bridge all run under PowerShell / Git Bash):

python -m venv .venv
.venv\Scripts\python.exe -m pip install -r requirements.txt
.venv\Scripts\python.exe server.py
  • The venv interpreter is .venv\Scripts\python.exe (POSIX: .venv/bin/python3, setup.sh is the POSIX twin). The pi bridge picks the right one automatically.
  • The ACORE_*/DB_* defaults point at /root/azerothcore-wotlk, so on Windows set them explicitly (e.g. a machine-local env.local.ps1, kept gitignored) — e.g. ACORE_DBC_PATH=C:\GIT\azerothcore-wotlk\env\dist\bin\dbc.
  • worldserver.conf auto-detection only helps if a conf exists locally; dev checkouts usually don't have one, so explicit DB_HOST/DB_USER/DB_PASSWORD pointing at the realm's MySQL (LAN or localhost) is the normal setup.
  • Client data layout is the same as Linux: env\dist\bin\{dbc,maps,vmaps,mmaps}. Populate via ./acore.sh client-data (Git Bash, from the AzerothCore checkout) or copy the directory from the realm machine.
  • Test note: the DB-free suites run as-is; one test_helpers test (chmod-000 inaccessible parent) skips on Windows because POSIX mode bits are no-ops there.

Design boundaries

This is a local agent tool for a single AzerothCore WotLK install: one process, stdio JSON-RPC, reading local DBC/terrain files and the local (or realm-shared) MySQL. It is deliberately not a service, and the following are non-goals rather than gaps:

  • No Docker/systemd packaging, SLA, or backup strategy — it runs next to the realm it describes. dbversion is the identity/health check by design.
  • No metrics, rate limiting, or HTTP health endpoint — the consumer is an LLM agent on a private stdio channel.
  • No structured error codes or JSON logging — actionable string errors with suggestions (did-you-mean, schema hints) are the right interface for an LLM consumer.
  • No eviction policy on the DBC cache — the store set is bounded (~114 DBCs, one reader per store); it is not a cache of unbounded working set.
  • No input validation beyond statement blocking on sql — it is a deliberate admin escape hatch; set ACORE_SQL_TOOL_MODE=readonly to restrict to SELECT.
  • Single-install scope — no multi-realm aggregation; point it at the install you care about.

Testing

# Regression suite — 21 tests, the output-shape/strictness/protocol contract
.venv/bin/python3 tests/test_regression.py

# Integration tests — 75 tests (requires running MySQL + DBC files)
.venv/bin/python3 tests/test_integration.py

# Fast unit tests — 40 tests (no DB)
.venv/bin/python3 tests/test_helpers.py

# Everything at once
.venv/bin/python3 -m pytest tests/ -q

Output-size baselines (for LLM context budgeting):

.venv/bin/python3 scripts/capture_output_sizes.py /tmp/after
.venv/bin/python3 scripts/capture_output_sizes.py --compare /tmp/before /tmp/after

Project Structure

acore-data/
├── server.py                    # MCP server entry point (JSON-RPC over stdio)
├── datastore_registry.json      # Static metadata for all 475 datastores
├── requirements.txt             # pymysql / pytest (pinned)
│
├── core/
│   ├── annotation.py            # DBC field annotation, filter conversion, schema errors
│   ├── database.py              # MySQL connection (pymysql), table discovery, smart routing,
│   │                            # per-DB credentials (shared-DB topologies)
│   ├── dbc.py                   # WDBC binary file reader
│   ├── enums.py                 # Shared enum dicts: condition types, SOURCE_TYPE, TYPEID
│   ├── enum_index.py            # C++ source-tree enum scanner (~1,044 enums, one cached pass)
│   ├── formats.py               # DBCfmt.h parser (format strings → field types)
│   ├── registry.py              # Datastore registry: name resolution, fuzzy matching
│   ├── type_resolver.py         # Dispatcher + generic registry-driven resolution engine
│   ├── resolvers/               # Specialized table-specific resolver modules
│   │   ├── __init__.py          # Resolver registry (table_name → func)
│   │   ├── gameobject.py        # data[0-19] annotation for GAMEOBJECT_TYPE subtypes
│   │   ├── smart_scripts.py     # EVENT_ID/ACTION_ID/TARGET_ID enum + value meaning
│   │   ├── quest.py             # Starter/ender NPCs, POIs, chain info (prev/next/breadcrumb)
│   │   ├── condition.py         # Polymorphic: SourceType → entity, ConditionType, enums
│   │   ├── achievement_criteria.py  # CriterionType-specific field interpretation
│   │   ├── item.py              # Loot template for openable items (Flags & 0x04)
│   │   ├── spell.py             # Cast conditions from `conditions` table with enum resolution
│   │   └── ref_utils.py         # Shared helpers: resolve_dbc_ref, resolve_sql_ref, …
│   └── terrain/                 # Terrain data: map/vmap/mmap readers, navmesh pathfinding
│       ├── coords.py            # World ↔ tile coordinate conversions
│       ├── map_reader.py        # ADT map file reader (height, liquid, area)
│       ├── vmap_reader.py       # VMap model file reader
│       ├── mmap_reader.py       # MMap navmesh tile index reader
│       ├── detour_parser.py     # Detour tile parser (polygons, BV tree, vertices)
│       ├── tile_manager.py      # On-demand tile loading, cross-tile link resolution
│       └── pathfinder.py        # A* search, corridor steering, cross-tile pathfinding
│
├── tools/
│   ├── __init__.py              # Tool schema registry, SQL-mode gate (ACORE_SQL_TOOL_MODE)
│   ├── query.py                 # Unified query tool (DBC + SQL + overlay merge)
│   ├── lookup.py                # Schema/metadata lookup tool
│   ├── list.py                  # Datastore listing tool
│   ├── sql.py                   # Raw SQL execution with routing and suggestions
│   ├── terrain.py               # Terrain/pathfinding tool (map/vmap/mmap, A* navmesh)
│   ├── spawns.py                # Creature spawn rollup (where does creature N spawn?)
│   ├── dbversion.py             # Server state: core/DB version, per-DB update state
│   ├── encounter.py             # Instance/map encounter rollup (creatures, gameobjects)
│   ├── travel.py                # mod-playerbots travel graph + navmesh path verification
│   ├── explain.py               # Agent-friendly single-record digest
│   ├── config.py                # mod-playerbots conf index (settings + C++ call sites)
│   └── enums.py                 # C++ enum decoder (magic numbers → MECHANIC_POLYMORPH …)
│
├── scripts/
│   ├── audit_registry.py        # Registry health gate (CI: structural signals must be 0)
│   ├── capture_output_sizes.py  # LLM context-budget output baselines + diff
│   ├── source_crossrefs.py      # FK heuristic cross-reference discovery
│   └── archive/                 # One-off registry migrations (idempotent no-ops)
│
├── generators/                  # Registry generation tooling (docs/datastores is the
│   ├── generate_registry.py     # human reference; --write regenerates the registry)
│   ├── generate_supplementary.py
│   └── … (cross-ref / annotation generators)
│
├── evals/
│   ├── run_eval.py              # LLM tool-calling eval harness (optional, time-costly)
│   └── report.py
│
├── .pi/extensions/
│   └── acore-data.ts            # pi bridge (spawns server.py over stdio JSON-RPC)
│
├── .github/workflows/
│   └── ci.yml                   # Fast suites + structural audit on push/PR
│
├── tests/
│   ├── test_helpers.py          # Fast unit tests (no DB)
│   ├── test_regression.py       # Rework contract: shape, strictness, links, protocol, audit
│   └── test_integration.py      # Integration tests (live DB + DBC)
│
└── docs/datastores/             # Technical reference for AzerothCore datastore internals
    ├── README.md                # Overview of DBC pipeline, SQL overlay, format strings
    ├── dbc-backed-stores.md
    ├── sql-objectmgr-stores.md
    ├── sql-manager-stores.md
    ├── sql-auxiliary-stores.md
    └── cross-reference.md

How It Works

   MCP Client (LLM / IDE / CLI)
         │
         │  JSON-RPC over stdio
         ▼
   server.py  ───────────────────────────────────────
         │
         ├─► registry.py        datastore_registry.json
         │     Name resolution, fuzzy matching        (475 entries)
         │
         ├─► tools/query.py     ┌──► dbc.py           .dbc binary files
         │     Unified query    │    WDBCReader        (Spell.dbc, Map.dbc, …)
         │                      │
         │                      ├──► database.py       MySQL
         │                      │    Smart routing     (acore_world, _characters, _auth)
         │                      │
         │                      ├──► annotation.py     Field annotation
         │                      │    DBC ↔ SQL merge   + type-aware resolution
         │                      │
         │                      └──► type_resolver.py  gameobject_template
         │                                           data[] → lockId/lootId/spellId
         │
         ├─► tools/lookup.py    Schema + live SQL columns + cross-refs
         │
         ├─► tools/list.py      Category filtering + search
         │
          ├─► tools/sql.py       Raw SQL with routing + typo suggestions
          │
          └─► tools/terrain.py   Terrain queries + pathfinding
                                   (map/vmap/mmap, A* navmesh)

License

GPL-2.0 (GNU General Public License, version 2) — see LICENSE. This matches the license of the AzerothCore server it serves. No AzerothCore code is bundled — the server reads your own install's DBC files, terrain data and SQL schema at runtime.

About

MCP server and agent tooling for AzerothCore WotLK: unified queries over DBC, live SQL, terrain and playerbots data

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages