Database-Driven Dungeon Mastering
π² The Experiment
I built an RPG MCP server with 135 tools covering combat, world generation, spatial navigation, and character management. Then I asked Claude to play a complete D&D encounterβcontrolling the dungeon master AND all four party members simultaneously. The goal: prove that database-backed state enables coherent narrative even when one AI plays both sides of the table.
The Setup: World, Party, and Persistence
The RPG engine uses SQLite as its ground truth. Every entityβworlds, characters, items, quests, combat encountersβlives in the database. The AI agent has no memory between tool calls; it reconstructs context by querying storage.
- World: The Shattered Isles (30Γ30 grid, 10 regions)
- Party: The Wayfarers (4 members)
- Location: The Salty Anchor tavern
- Quest: Clear the Coastal Caves
The party consisted of four characters with distinct roles:
Kira Stoneheart
Human Fighter, Level 3
Elara Moonshadow
Elf Wizard, Level 3
Brother Marcus
Human Cleric, Level 3
Shade
Halfling Rogue, Level 3
The Combat: 5 Goblins vs 4 Adventurers
The encounter used spawn_quick_enemy to generate 5 goblins
on a 20Γ20 grid with obstacles. The engine handled initiative rolls automaticallyβeach
combatant's DEX modifier + d20 determined turn order.
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 . . . . . . . . . . . . . . . . . . . . 1 . . . . . . . . . . . . . . . . . . . . 2 . . . . . . . . . . . . . . . . . . . . 3 . . . . . . . . . . . . . . . . . . . . 4 . . . . . . . . . . . . . . . . . . . . 5 . . . K . . . . . . E . . . . . . . . . K = Kira (Fighter) 6 . . . . . β β . . . . . . . . . . . . . E = Elara (Wizard) 7 . . . . . β β . . . . G . . . . . . . . M = Marcus (Cleric) 8 . . . . . . . . . G . . . G . . . . . . S = Shade (Rogue) 9 . . . . M . . . . . . . . . . . . . . . G = Goblin 0 . . . . . . . . . . . . . . . . . . . . β = Obstacle 1 . . . . . . . . . . . . . . G . . . . . β = Defeated 2 . . . . . . . . S . . . . . . . . . . .
What made this work wasn't the AI's reasoningβit was the database constraints. Movement costs were calculated from grid positions. Attack rolls checked AC from the target's record. HP damage was persisted immediately. The AI couldn't cheat even if it wanted to.
Key Findings: What the Playtest Revealed
1. Errors Are Teachers
When I tried to move Shade to position (12,8), the engine rejected it:
"Position blocked by obstacle". When I used the wrong
actor ID, it said: "Actor not in combat". Each error
guided the next action.
Hint: Use combat_manage(action: "get") to see valid participant IDs.
2. Dice Create Narrative
The AI didn't decide if attacks hitβthe d20 did. Shade rolled a natural 18 on his sneak attack. Brother Marcus's Cure Wounds rolled 8 on 1d8+3. These random outcomes created emergent drama that felt authentic.
3. HP Syncs Automatically
Combat maintains its own HP snapshots. When combat ended, the engine called
combat_manage(action: "end") and synced final HP back to persistent
character records. Shade's 17 HP (after healing) was saved to his character file.
Next session, he starts damaged.
4. Movement Math is Non-Negotiable
Every character has a speed (30ft for most). The grid uses 5ft squares. When I tried to move 35ft with 30ft remaining, the engine rejected it. No "close enough"βthe database enforces the rules even when the AI forgets them.
The Outcome: Goblin-3 Falls
After two rounds, the party had eliminated one goblin and positioned for a counterattack. The combat log tells the mechanical story; the AI narrates the drama.
Combat Timeline
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β COMBAT ENDED β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£ β HP Sync Complete: β β Kira Stoneheart: 28/28 HP (unchanged) β β Elara Moonshadow: 18/18 HP (unchanged) β β Brother Marcus: 24/24 HP (unchanged) β β Shade: 17/21 HP (took 12, healed 8) β β β β Enemies Defeated: 1 (Goblin-3) β β Enemies Remaining: 4 β β β β State persisted to: rpg-mcp.db β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Why This Matters: Database as Game Master
The traditional approach to AI game masters is to stuff everything into the prompt: character stats, world state, combat history. But prompts have limits, and context windows get expensive.
The database-driven approach inverts this. The AI knows nothing except what
it queries. Want to know Shade's HP? Call character_manage(action: "get").
Want to see the battlefield? Call combat_map(action: "render"). The
database is the single source of truth.
Database enforces rules. AI describes consequences.
Every rejection includes context for the correct action.
Random outcomes prevent AI from "choosing" winners.
Session can end anytime. Database remembers everything.
The result? Coherent narrative across any number of sessions. The AI can play both sides because the database prevents favoritism. Combat feels fair because dice determine outcomes. And when something goes wrong, the error message tells you exactly what to do next.
The Toolbox: 135 RPG Tools
The mnehmos.rpg.mcp server consolidates 135 tools into action-based interfaces. Here's what powered this playtest:
Session & World
- session_manage (initialize, get_context)
- world_manage (generate, get_state)
- spatial_manage (generate, look)
Characters & Party
- character_manage (create, get, update)
- party_manage (create, add_member)
- inventory_manage (give, equip)
Combat
- combat_manage (create, get, end)
- combat_action (attack, move, heal)
- combat_map (render, aoe)
Narrative
- quest_manage (create, assign, complete)
- npc_manage (get_context, interact)
- narrative_manage (add, get_context)
The Takeaway
Can an AI play D&D with itself? Yesβbut only because the database is the real dungeon master. The AI describes, proposes, and narrates. The database validates, persists, and enforces.
This architecture scales beyond games. Any AI workflow that requires consistent state across sessions benefits from externalizing truth to a database. The LLM becomes the interface layerβtranslating intent into validated actions and results into narrative.
"The agent isn't smartβthe database is. The agent is just hands."
Next experiment: multi-agent D&D where different Claude instances control different characters, coordinated through the same database. The dungeon master becomes truly neutralβjust another agent with access to the same tools.