Skip to main content
Glama
Pliskin92

dreamingazeroth-mcp

by Pliskin92
README.md
# dreamingazeroth-mcp

MCP server for **Dreaming Azeroth**, a WotLK 3.3.5a private server running AzerothCore + mod-playerbots. It gives an AI client — Claude Code, Claude Desktop, or anything else that speaks [Model Context Protocol](https://modelcontextprotocol.io) — read access to the realm's databases and, behind explicit opt-in gates, the ability to run GM commands, edit config and code, and apply content changes.

Companion repos: [dreamingazeroth-gui](https://github.com/Pliskin92/dreamingazeroth-gui) (web panel and the AzerothCore install script) and [dreamingazeroth-addons](https://github.com/Pliskin92/dreamingazeroth-addons) (client addons).

Designed to run **on the server box itself**: MySQL and SOAP are both reached over loopback, so nothing new has to be exposed to the network.

## What it is not

This does not talk to Blizzard's Battle.net API. Everything comes from your own `acore_auth` / `acore_characters` / `acore_world` / `acore_playerbots` schemas and your live worldserver, so custom items, custom loot and bot activity all show up exactly as they are on your realm.

## Capabilities

Four tiers, each independently enabled. Reads always work; **everything else is off until you turn it on.**

| Tier | Env var | What it unlocks |
| --- | --- | --- |
| `read` | — always on | Every database query: characters, accounts, guilds, items, quests, loot, auctions, logs, server status |
| `soap` | `AC_ENABLE_SOAP` | GM commands through the running worldserver: announce, kick, teleport, mail, reload, account admin, shutdown |
| `write` | `AC_ENABLE_WRITE` | Editing files inside `AC_WRITABLE_PATHS`, and applying SQL with automatic backups |
| `exec` | `AC_ENABLE_EXEC` | `systemctl` service control, CMake builds, `mysqldump` backups |

A tool whose tier is disabled is still listed, so the model can see it exists — it just fails with the exact env var to set.

## Tools

<details>
<summary><b>Ops and monitoring</b> (read)</summary>

- `ac_server_status` — services, population, database reachability, realm list, live SOAP banner
- `ac_online_players` — who is connected, with real players separated from RNDBOT playerbots
- `ac_population_report` — accounts, characters by level/class/race/faction, gold totals
- `ac_server_logs` — tail `Server.log` / `Auth.log` or the systemd journal, with a `contains` filter
- `ac_db_health` — schema sizes, largest tables, MySQL connection state
- `ac_account_lookup` — accounts by name/email/id/IP with GM level, bans and characters
</details>

<details>
<summary><b>Players</b> (read)</summary>

- `ac_character_search` — partial-name search with level/class/online filters
- `ac_character_profile` — full profile, optionally with equipment, stats, talents, skills, social
- `ac_character_inventory` — equipped gear and bags joined to `item_template`
- `ac_guild_info` — guild details and roster, or every guild ranked by size
- `ac_character_mail` — inbox with money and item attachments
</details>

<details>
<summary><b>Game content</b> (read)</summary>

- `ac_item_search` / `ac_item_details` — items, plus what drops them, who sells them, which quests reward them
- `ac_creature_search` — NPCs with loot tables and spawn points
- `ac_quest_lookup` — quests with objectives and rewards
- `ac_spell_lookup` — server-side spell data (limited by design; see Known limits)
- `ac_db_describe` — tables and columns, for confirming schema before writing SQL
- `ac_sql_query` — read-only `SELECT` escape hatch for anything not covered
</details>

<details>
<summary><b>Economy</b> (read)</summary>

- `ac_auction_search` — AH price statistics per item, split by bot vs player sellers
- `ac_economy_report` — gold in circulation, wealthiest characters, guild banks, gold in mail
- `ac_playerbots_status` — bot population, level spread, and their share of AH supply
</details>

<details>
<summary><b>GM commands</b> (soap)</summary>

- `ac_gm_commands` — the catalogue of runnable commands and their parameters
- `ac_gm_command` — run one by key with typed arguments
- `ac_announce` — broadcast chat text or an on-screen banner
- `ac_player_action` — kick, revive, summon, teleport an online character
- `ac_send_mail` — mail gold and items (the safe way to grant anything)
- `ac_reload` — reload `worldserver.conf` or one world table
- `ac_server_shutdown` — graceful shutdown/restart with a player countdown
- `ac_account_admin` — create accounts, reset passwords, set GM level, ban/unban
- `ac_save_all` — flush online characters to MySQL before reading their rows
</details>

<details>
<summary><b>Code, config and content</b> (write / exec)</summary>

- `ac_server_layout` — paths, installed modules, enabled capabilities, and the workflow for each kind of change
- `ac_list_files` / `ac_read_file` — browse and read the source tree and configs
- `ac_write_file` — write inside the allowlist, keeping a timestamped `.bak`
- `ac_apply_sql` — transactional SQL with a `dryRun` mode and `mysqldump` backups
- `ac_read_config` — grep settings out of `.conf` files without dumping them whole
- `ac_service_control` — status always; start/stop/restart with `exec`
- `ac_build` — CMake rebuild after a C++ change
- `ac_git_status` — read-only git against the source or a module
</details>

Plus 5 prompts (`health-check`, `investigate-player`, `add-content`, `tune-rates`, `economy-review`) and two resources: `ac://guide` and `ac://schema`.

## Two things that will bite you otherwise

**Online characters are stale in the database.** Worldserver holds logged-in characters in memory and only flushes on a timer and at logout. Any character query for someone who is online can be minutes behind. Call `ac_save_all` first when the exact number matters. Every affected tool says so in its output rather than letting you assume the row is current.

**Never write to a live player's rows.** `UPDATE characters SET money = ...` for someone who is online gets silently overwritten at the next save — the in-memory copy wins. Grant items and gold with `ac_send_mail`, change accounts with `ac_account_admin`. Both go through the running worldserver, so the change sticks and the server's own bookkeeping stays correct.

## Which path for which change

| Change | How | Restart needed? |
| --- | --- | --- |
| Content — items, loot, vendors, NPCs, quests | `ac_apply_sql`, then `ac_reload` on the table | No |
| A setting in `worldserver.conf` | `ac_write_file`, then `ac_reload` target `config` | Only for settings not re-read live |
| Module config, e.g. `playerbots.conf` | `ac_write_file`, then restart worldserver | Usually yes |
| C++ in the core or a module | `ac_write_file`, `ac_build`, restart | Yes |

Reach for SQL before C++ — most gameplay changes on AzerothCore are data, and data changes apply live.

## Install

On the server, as the user that owns the AzerothCore checkout:

```bash
git clone https://github.com/Pliskin92/dreamingazeroth-mcp.git
cd dreamingazeroth-mcp
./install/install-mcp.sh --with-systemd --start
```

The script builds, deploys to `/opt/dreamingazeroth-mcp`, creates `.env` from `.env.example`, pulls `DB_PASS` out of `~/azerothcore/.db_credentials`, generates an `MCP_AUTH_TOKEN`, and installs the systemd unit. Re-running it is safe and never touches an existing `.env`.

Verify:

```bash
curl -s http://127.0.0.1:8080/readyz | jq
```

### Enabling the write and exec tiers

Edit `/opt/dreamingazeroth-mcp/.env`:

```bash
AC_ENABLE_SOAP=true
SOAP_USER=panel_soap          # any GM account
SOAP_PASS=...

AC_ENABLE_WRITE=true
AC_WRITABLE_PATHS=/home/youruser/azerothcore/source/modules,/home/youruser/azerothcore/env/dist/etc

AC_ENABLE_EXEC=true
```

SOAP also needs `SOAP.Enabled = 1` in `worldserver.conf`.

`AC_ENABLE_WRITE` needs the systemd unit to allow those paths — `ProtectHome=read-only` is on by default, so uncomment and adjust `ReadWritePaths=` in the unit file.

`AC_ENABLE_EXEC` needs passwordless sudo for the service actions:

```
# /etc/sudoers.d/dreamingazeroth-mcp
youruser ALL=(root) NOPASSWD: /bin/systemctl start azerothcore-worldserver, \
                              /bin/systemctl stop azerothcore-worldserver, \
                              /bin/systemctl restart azerothcore-worldserver, \
                              /bin/systemctl start azerothcore-authserver, \
                              /bin/systemctl stop azerothcore-authserver, \
                              /bin/systemctl restart azerothcore-authserver
```

Scope it to exactly those units. A blanket `NOPASSWD: ALL` would make the MCP endpoint equivalent to root on the box.

## Connecting a client

**Claude Code**, over the LAN from your desktop:

```bash
claude mcp add --transport http dreamingazeroth \
  http://azeroth.local:8080/mcp \
  --header "Authorization: Bearer $MCP_AUTH_TOKEN"
```

That needs `HOST=0.0.0.0` and `MCP_AUTH_TOKEN` set in `.env`.

**stdio**, when the client runs on the server itself:

```json
{
  "mcpServers": {
    "dreamingazeroth": {
      "command": "node",
      "args": ["/opt/dreamingazeroth-mcp/dist/index.js", "--stdio"]
    }
  }
}
```

## Security

The endpoint can read your entire player database and, with the gates open, change the running realm. It binds to `127.0.0.1` by default.

- **`MCP_AUTH_TOKEN` is mandatory** for any non-loopback bind. The server logs a warning at startup if it is unset.
- **`azeroth` is LAN-only** (no public IP, no port forwarding — see the gui repo's TODO). Keep it that way; there is no reason to expose this to the internet.
- **SOAP commands are an allowlist, not a passthrough.** You pick a command by key and supply typed parameters — free-text command strings are never sent. This is deliberate: the previous version of this stack shipped a SOAP command-injection hole (see the `uncompliantexperience` audit referenced in the gui repo), and structuring the interface this way is what prevents that class of bug rather than trusting each call site to escape correctly.
- **AzerothCore's console parser has no quoting.** It splits arguments on whitespace, full stop — `account create "My Name" pw` really does create an account called `"My`. Arguments are typed `bare` / `quoted` / `rest` / `int` accordingly, and a value that cannot be expressed safely is rejected with an explanation instead of being mangled. Newlines and control characters are refused everywhere, since they could smuggle in a second command.
- **File access is a realpath-checked allowlist.** A symlink inside a writable root cannot be used to escape it.
- **`ac_sql_query` is read-only** — positive check for `SELECT`/`SHOW`/`DESCRIBE`/`EXPLAIN`, a keyword denylist for anything hidden in a subquery, and a row cap.
- **Destructive tools require `confirm: true`.** Not a substitute for the capability gates — a second, per-call deliberate step.

## Known limits

- **Spell data is mostly client-side.** Stock AzerothCore reads spells from the client's DBC files; `spell_dbc` only holds custom or overridden entries. `ac_spell_lookup` returns what the server actually knows and says so when a spell is not there, rather than inventing an answer.
- **Column names drift between forks.** This targets the [mod-playerbots/azerothcore-wotlk](https://github.com/mod-playerbots/azerothcore-wotlk) `Playerbot` branch. Where a schema difference is known — `creature.id1` vs `creature.id`, `talent_dbc` vs `Talent` — it is handled, but run `ac_db_describe` before trusting a hand-written query.
- **`ac_build` is slow.** A full rebuild is tens of minutes and saturates CPU. It will degrade a live realm.
- **`acore_playerbots` is module-owned.** Read it; do not write it. mod-playerbots rewrites that schema on its own schedule.
- **Multi-item mail sends one mail per item.** The console parser cannot express several `id:count` pairs in one argument, so `ac_send_mail` splits them and says so in its result.

## Development

```bash
npm install
npm run dev            # tsx watch, HTTP transport
npm run stdio          # stdio transport against a local .env
npm run typecheck
npm test
```

Layout:

```
src/
  ac/          AzerothCore integration: db pools, SOAP, file sandbox, process runner, WotLK constants
  tools/       MCP tools grouped by area (ops, characters, content, economy, admin, devops)
  util/        Cache, formatting, errors
  config.ts    Environment parsing and capability gates
  http.ts      Streamable HTTP transport, sessions, auth, CORS, health
  stdio.ts     stdio transport
  server.ts    Wires backends into an McpServer
```

Maintenance

ActivitySlowing
ResponsivenessNo issues