The Vibe Coder's Bible
Chapter 25

RPG-MCP: The Model Narrates, The Engine Rules

The model narrates the world. The engine decides what is true.

Chapter 25 - RPG-MCP: The Model Narrates, The Engine Rules

Part: VI - AI-Native Case Studies From The Mnehmos Ecosystem

Thesis

A tabletop RPG engine is an unusual place to learn software architecture. It is also a surprisingly clear one. The rules of the game create an unambiguous separation between what the model is allowed to decide and what the engine owns.

Key Line

The model narrates the world. The engine decides what is true.

Why Games Clarify The Design Problem

In a game, the rules are the product.

If the game’s rules engine enforces that a character has twelve hit points and a sword swing does two-to-eight points of damage, those constraints have to be real. A model that narrates “the hero shrugs off the blow” when the hit points said zero is not being creative. It is breaking the game.

Games make the control design problem visible because the consequences of letting the model own state are immediate and obvious. A model that invents inventory items the player did not earn is cheating. A model that fudges dice rolls toward the heroic outcome is corrupting the game. A model that narrates a different world than the one the state describes is writing fiction, not running a game.

These are the same problems AI-assisted software development faces. The consequences are just less visible when the domain is code instead of dragons.

The RPG-MCP Architecture

ProveCalc’s engine returns one number for one question and can forget everything once the audit trail is written. RPG-MCP’s engine has to remember thousands of numbers - hit points, inventory, spell slots, quest flags, relationships - across a session with no defined end. That difference is what makes the state substrate, not just the verdict, the central design problem here.

RPG-MCP is a reference implementation of the embodied agentic AI pattern built on Model Context Protocol.

The scale matters: 195 tools consolidated to 32 action-based tools. That 85% reduction in tool surface area is not an aesthetic choice. It is a token economy decision. Fewer, broader tools mean less overhead per action and more context available for the game itself.

The 32 tools organize into four categories:

  • Combat tools: resolve attacks, apply damage, check conditions, advance initiative
  • Inventory and spell tools: manage items, track spell slots, enforce resource limits
  • World tools: persist locations, NPCs, quests, and world state
  • Meta-tools: tool discovery and event subscriptions

Backing the tools: 1,889 passing tests validating D&D 5e rules. The tests are not commentary. They are the enforcement layer. If the engine accepts an action that should be illegal, a test should catch it.

The State Substrate

The engine uses four components, and each one owns exactly one job.

Zod schemas (src/schema) define what actions are syntactically possible. Every tool call is validated against a typed schema before the engine processes it. The model cannot pass malformed input. The schema is the contract between the model’s proposal and the engine’s acceptance.

Rules engine (src/engine) decides which of those syntactically possible actions are legal right now. It is the deterministic core. It decides whether an action is legal, what its effects are, and what state transitions follow. It does not ask the model. It applies the rules.

SQLite persistence (src/storage) owns everything that must outlive the conversation. Character sheets, inventory, spell slots, quest progress, NPC relationships - these exist in a database, not in the conversation. When the model loses its context, the game does not lose its state.

Dice system owns chance. Every roll a rule calls for - an attack, a saving throw, a skill check - is generated by the dice tool, not proposed by the model. The engine reads the result; it does not ask the model what the die showed.

Four components, four jobs: schemas define what is possible, the rules engine decides what is legal, SQLite decides what persists, and the dice system decides what is left to chance. The model touches none of the four directly. It calls them.

What The Model Can Do

The model handles everything that benefits from language.

  • Narrating combat outcomes from the engine’s resolved results.
  • Writing NPC dialogue that reflects the character’s faction, history, and disposition.
  • Describing environments, atmosphere, and scene transitions.
  • Suggesting player options in natural language.
  • Interpreting ambiguous player intent and routing it to the correct tool.

The model is a rendering layer and an interpretation layer. It makes the deterministic game state legible and interesting.

What The Model Cannot Do

The model cannot change state directly.

It cannot add an item to the player’s inventory by describing it. It must call the inventory tool, which validates the call against the schema, which routes it through the engine, which applies the business rules, which writes to SQLite.

It cannot roll dice. It calls the dice tool. The engine owns the randomness.

Never let the model roll the dice. A die roll is typed randomness: a declared range, a known distribution, a result that can be logged and reproduced from its seed. Model output also varies from run to run, but that variation is untyped - it has no declared range and no owner. Letting the model report what the die showed, instead of calling the tool that rolls it, would swap a designed source of chance for an opinion wearing its costume. RPG-MCP does not make that swap anywhere in the combat loop.

It cannot heal a character by narrating recovery. It calls the HP tool. The engine applies the change.

It cannot break the rules by describing a different outcome. If the attack missed, the model narrates a miss. It does not have access to a different state.

The model’s narration is generated from the state the engine returned. It does not produce a state and then describe it. It receives a state and then describes it.

The Trust Boundary In Practice

A common failure mode in early AI game systems was letting the model hold state in its context window.

“You have a health potion” in the conversation is not the same as health_potion: 1 in the inventory table.

When the conversation window fills and old messages are truncated, the potion disappears. When a new session starts, the potion is gone. When a second agent or client connects, the potion does not exist.

State in the conversation is ephemeral. State in the database is durable.

This is not a game-specific insight. Every AI-assisted application that lets the model “remember” things in conversation context instead of persisting them to a real store is making the same mistake. The game case just makes the failure obvious.

The Narration-From-State Pattern

The most important design decision in RPG-MCP is the direction of generation.

The model does not produce a narrative and then reconcile it with state.

The engine produces state. The model generates narrative from that state.

The sequence is:

  1. Player action arrives in natural language.
  2. Model interprets intent and calls the appropriate tool.
  3. Engine validates, executes, and returns the new state.
  4. Model narrates the outcome using the returned state as ground truth.

If the attack roll was a fifteen and the enemy’s armor class is fourteen, the engine resolves a hit. The model narrates a hit. If the roll was a twelve, the engine resolves a miss. The model narrates a miss.

The model never decides whether the hit landed. The engine does. The model describes what the engine decided.

This makes the model’s output two different kinds of thing wearing one voice. Step 2 is a proposal: a tool call the schema will validate and the engine may accept or reject. Step 4 is not a proposal at all. It is commentary on a decision that has already been made and already been written to SQLite. Narration cannot be rejected the way a tool call can, because narration never had the standing to change anything in the first place. Treating a vivid description as if it were itself a state change is exactly the failure mode external persistence exists to prevent.

Control Mapping

RiskControl
Model invents inventory itemsSQLite persistence; items only exist if the engine created them
Model fudges dice rollsEngine owns all randomness; model calls a tool
Model breaks rulesRule validator rejects illegal tool calls
Narration contradicts stateNarration is generated from engine-returned state
State lost on session endSQLite survives context window limits
Model hallucinates NPC factsNPC state is persisted; model reads from store

A tool call that fails schema validation or fails the rules engine’s legality check does not vanish quietly. It is worth keeping as a record: what the model tried, why it failed, and when. That record is a traceable proposal, not a world event. The character’s inventory does not change. The enemy’s hit points do not change. The fictional world is exactly as it was before the attempt. What changed is the trace, which now shows that the model tried something the engine would not allow. A rejected proposal changes the trace. It never changes the world.

What This Teaches

Games are a laboratory for AI control design because the rules are explicit and the violations are visible.

The doctrine that emerges from RPG-MCP is not game-specific:

  • External state beats context-window memory every time.
  • Schemas validate what the model proposes before the engine acts.
  • The engine owns the decision. The model owns the description.
  • Tests specify the rules. The model cannot break a rule that a passing test enforces.
  • Narration follows state; it does not precede it.

Chapter 9 treats typed tools as the model’s action vocabulary in general; the 32 action-based tools here are that argument with the vocabulary already built. Chapter 14 makes the same case for durable state at the level of an entire project; SQLite here is that argument scoped to one campaign.

Software systems with real consequences need the same separations. The health points are different. The principle is the same.

Practical Artifact - State Substrate Checklist

QuestionWhat it protects
Is state persisted in a real store, or held in conversation context?Prevents state loss on session end or context truncation
Does the model call a tool to change state, or describe a change directly?Prevents narration-as-mutation
Does the engine validate the tool call before executing it?Prevents illegal state transitions
Are schemas defined for every tool call the model can make?Prevents malformed input from reaching the engine
Does narration come from engine-returned state, not model invention?Prevents state contradiction
Are the rules tested independently of model behavior?Prevents rule drift as the model changes
Can the state be recovered without the conversation history?Prevents chat-log dependency

The state substrate checklist applies to any system where an AI agent takes actions with real consequences. The domain changes. The questions do not.

Practical Artifact - Architecture Card

The same eleven questions this part asks of every system, answered for RPG-MCP.

FieldRPG-MCP
Model may propose or interpretPlayer intent in natural language; which tool to call; narration and dialogue generated from engine-returned state
Source of truthThe rules engine for legality and effects; SQLite for everything that must persist
Assumed model capabilityNatural-language intent parsing, a consistent narrative voice, mapping ambiguous player requests onto the correct tool
Specification (ex ante)Zod action schemas, the current game state fed into context, NPC and faction history
Verifier (ex post)Zod schema validation, then the rules engine’s legality check, backed by 1,889 tests
Durable stateSQLite (src/storage): character sheets, inventory, spell slots, quest progress, NPC relationships
Commit boundaryThe rules engine applies a validated, legal tool call and writes the result to SQLite; narration follows only after that write
Randomness & reproducibility ownerThe dice system. Every roll is generated, logged, and returned by the engine - never proposed by the model
After rejectionAn illegal or malformed tool call is rejected by the schema or the rules engine; SQLite does not change and the world does not move
Trace preservedRejected and accepted tool calls, applied state transitions, the event trail tied to each SQLite write
Escape metricAny narration describing a state the engine never wrote - an item, a hit-point change, or a fact that exists in conversation but not in SQLite

Practical Artifact

0/7 checked