Skip to main content
Glama
RPG-MCP-LITE-DESIGN.md23.3 kB
# RPG-MCP Lite: Design Specification ## Lightweight D&D 5e Engine • 48 Core Tools • Modular Architecture --- ## Design Philosophy **WHAT WE'RE BUILDING:** A text-only LLM-as-DM engine with full D&D 5e action economy, focused on tactical combat and session management. No procedural overworld generation—locations are narrative constructs. **WHAT WE'RE REMOVING:** - Perlin noise world generation - Grand Strategy (nations, diplomacy, turn management) - Corpse/Loot tables system (DM handles narratively) - Theft provenance tracking - Event inbox system - Complex workflow orchestration **WHAT WE'RE KEEPING:** - Full combat with spatial awareness - D&D 5e action economy - Conditions, boons, curses - Spellcasting with concentration - Skill checks and saves - Character & Party management - Session notes and memory --- ## Architecture: Three Modules ``` ┌─────────────────────────────────────────────────────────────┐ │ RPG-MCP LITE │ ├─────────────────────────────────────────────────────────────┤ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ COMBAT │ │ SPATIAL │ │ MAGIC │ │ │ │ MODULE │ │ MODULE │ │ MODULE │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ DATA LAYER │ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │ │Characters │ │ Sessions │ │ Locations │ │ Items │ │ │ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ TOOL SURFACE │ │ 49 Tools • Meticulous Zod Schemas │ └─────────────────────────────────────────────────────────────┘ ``` --- ## Tool Inventory (48 Tools) ### Module 1: COMBAT (15 tools) | # | Tool | Description | | --- | --------------------- | --------------------------------------------------------------------- | | 1 | `create_encounter` | Initialize combat with participants, positions, terrain | | 2 | `get_encounter` | Get current encounter state | | 3 | `execute_action` | Unified action handler (Supports Batching: attack, spell, dash, etc.) | | 4 | `advance_turn` | Progress to next combatant | | 5 | `end_encounter` | Conclude combat, cleanup | | 6 | `roll_initiative` | Roll/set initiative for combatants | | 7 | `apply_damage` | Deal damage (with type, resistance/immunity/vulnerability) | | 8 | `apply_healing` | Restore HP | | 9 | `roll_death_save` | D20 death saving throw | | 10 | `manage_condition` | Add/remove/query conditions (blind, charmed, etc.) | | 11 | `manage_effect` | Add/remove custom boons/curses/effects | | 12 | `move_combatant` | Move creature (with difficult terrain, opportunity attacks) | | 13 | `render_battlefield` | ASCII visualization of combat grid | | 14 | `modify_terrain` | Add/remove obstacles, difficult terrain, water, hazards | | 15 | `execute_lair_action` | Boss lair actions at init 20 | ### Module 2: SPATIAL (8 tools) | # | Tool | Description | | --- | ------------------------ | --------------------------------------------------------- | | 16 | `calculate_aoe` | Area of Effect: line, cone, cube, sphere, cylinder | | 17 | `measure_distance` | Distance between points/entities (feet/squares) | | 18 | `check_line_of_sight` | LoS with cover calculation (none/half/3-4/full) | | 19 | `get_creatures_in_range` | Find all creatures within X feet of point | | 20 | `check_cover` | Determine cover between attacker and target | | 21 | `place_prop` | Place interactive object (climbable, destructible, cover) | | 22 | `calculate_movement` | Path cost with difficult terrain, flying, jumping | | 23 | `get_adjacent_squares` | Get squares adjacent to a point/creature | ### Module 3: MAGIC (10 tools) | # | Tool | Description | | --- | --------------------- | ------------------------------------------------------------- | | 24 | `cast_spell` | Full spell resolution (slot, DC, attack, save, concentration) | | 25 | `check_concentration` | CON save after damage | | 26 | `break_concentration` | Manual concentration break | | 27 | `get_concentration` | Query active concentration | | 28 | `manage_spell_slots` | View/expend/restore spell slots | | 29 | `use_scroll` | Spell scroll usage (with Arcana check if needed) | | 30 | `create_aura` | Persistent area effect (Spirit Guardians, Paladin auras) | | 31 | `process_aura` | Trigger aura effects on movement/turn start | | 32 | `synthesize_spell` | Arcane Synthesis for improvised magic | | 33 | `get_spell_info` | Query spell database | ### Module 4: CHARACTERS (8 tools) | # | Tool | Description | | --- | ------------------ | ---------------------------------------------- | | 34 | `create_character` | Full character with class/race/stats/equipment | | 35 | `get_character` | Retrieve character sheet | | 36 | `update_character` | Modify character properties | | 37 | `list_characters` | Query characters (by type, party, etc.) | | 38 | `delete_character` | Remove character | | 39 | `roll_check` | Skill check, ability check, or saving throw | | 40 | `roll_dice` | Full dice suite (e.g. "4d6kh3", batch rolls) | | 41 | `take_rest` | Short or long rest (healing, slot recovery) | | 42 | `level_up` | Increase level, update HP/slots | ### Module 5: DATA (7 tools) | # | Tool | Description | | --- | --------------------- | ------------------------------------------- | | 42 | `manage_inventory` | Give/take/equip/unequip items | | 43 | `manage_party` | Create/update party, add/remove members | | 44 | `create_location` | Define a narrative location (room, area) | | 45 | `get_location` | Retrieve location details | | 46 | `add_session_note` | Plot threads, canonical moments, NPC voices | | 47 | `search_notes` | Query session notes by type/tag/text | | 48 | `get_session_context` | Aggregated context for LLM prompt | --- ## D&D 5e Coverage ### Conditions (Full PHB List) ```typescript type Condition = | "blinded" | "charmed" | "deafened" | "frightened" | "grappled" | "incapacitated" | "invisible" | "paralyzed" | "petrified" | "poisoned" | "prone" | "restrained" | "stunned" | "unconscious" | "exhaustion"; ``` ### Actions (Full Action Economy) ```typescript type Action = | "attack" | "cast_spell" | "dash" | "disengage" | "dodge" | "help" | "hide" | "ready" | "search" | "use_object" | "use_magic_item" | "use_special_ability"; type BonusAction = | "offhand_attack" | "cunning_action" | "spell" | "class_feature"; type Reaction = | "opportunity_attack" | "readied_action" | "spell" | "class_feature"; ``` ### Movement ```typescript interface MovementContext { speed: number; // Base speed in feet difficult_terrain: boolean; flying: boolean; swimming: boolean; climbing: boolean; jump_type?: "long" | "high"; jump_running?: boolean; prone_movement?: boolean; } ``` ### Cover Types ```typescript type Cover = "none" | "half" | "three_quarters" | "full"; // half: +2 AC, +2 Dex saves // three_quarters: +5 AC, +5 Dex saves // full: Cannot be targeted directly ``` ### Damage Types ```typescript type DamageType = | "slashing" | "piercing" | "bludgeoning" | "fire" | "cold" | "lightning" | "thunder" | "acid" | "poison" | "necrotic" | "radiant" | "force" | "psychic"; ``` ### Light Levels ```typescript type Light = "bright" | "dim" | "darkness" | "magical_darkness"; ``` --- ## Reference Tables (Embedded in Tool Descriptions) ### Damage by Level & Severity | Severity | Level 1-4 | Level 5-10 | Level 11-16 | Level 17-20 | | --------- | --------- | ---------- | ----------- | ----------- | | Setback | 1d10 | 2d10 | 4d10 | 10d10 | | Dangerous | 2d10 | 4d10 | 10d10 | 18d10 | | Deadly | 4d10 | 10d10 | 18d10 | 24d10 | ### Object HP by Size | Size | Fragile | Resilient | | ------ | -------- | --------- | | Tiny | 2 (1d4) | 5 (2d4) | | Small | 3 (1d6) | 10 (3d6) | | Medium | 4 (1d8) | 18 (4d8) | | Large | 5 (1d10) | 27 (5d10) | ### Object AC by Material | Material | AC | | ------------------- | --- | | Cloth, paper, rope | 11 | | Crystal, glass, ice | 13 | | Wood, bone | 15 | | Stone | 17 | | Iron, steel | 19 | | Mithral | 21 | | Adamantine | 23 | ### Travel Pace | Pace | Distance/Hour | Distance/Day | Effect | | ------ | ------------- | ------------ | --------------------- | | Fast | 4 miles | 30 miles | -5 passive Perception | | Normal | 3 miles | 24 miles | — | | Slow | 2 miles | 18 miles | Can stealth | ### Services | Service | Cost | | -------------------- | --------- | | Coach cab (city) | 1 cp | | Hireling (untrained) | 2 sp/day | | Hireling (skilled) | 2 gp/day | | Messenger | 2 cp/mile | | Road/gate toll | 1 cp | | Ship passage | 1 sp/mile | ### Food, Drink, Lodging | Item | Cost | | ---------------------------------------------------------- | --------------------------------------- | | Ale (gallon/mug) | 2 sp / 4 cp | | Inn (squalid/poor/modest/comfortable/wealthy/aristocratic) | 7 cp / 1 sp / 5 sp / 8 sp / 2 gp / 4 gp | | Meals | 3 cp - 8 sp | | Wine | 2 sp - 10 gp | --- ## Schema Design: `execute_action` Example ```typescript const executeActionSchema = z.object({ encounterId: z.string(), actorId: z.string(), action: z.enum([ "attack", "cast_spell", "dash", "disengage", "dodge", "help", "hide", "ready", "search", "use_object", "use_magic_item", "use_special_ability", "shove", "grapple", ]), // Attack-specific targetId: z.string().optional(), attackBonus: z.number().optional(), damage: z.string().optional(), // "2d6+4" damageType: DamageTypeSchema.optional(), advantage: z.boolean().optional(), disadvantage: z.boolean().optional(), // Spell-specific spellName: z.string().optional(), spellSlot: z.number().min(1).max(9).optional(), targetIds: z.array(z.string()).optional(), // For AoE targetPosition: PositionSchema.optional(), // Movement within action (shove/grapple result) forceMovement: z .object({ targetId: z.string(), direction: z.enum(["away", "toward", "left", "right"]), distance: z.number(), }) .optional(), // Ready action trigger: z.string().optional(), readiedAction: z.string().optional(), // Special ability abilityName: z.string().optional(), abilityDetails: z.record(z.any()).optional(), }); ``` --- ## Schema Design: `manage_condition` Example ```typescript const manageConditionSchema = z.object({ characterId: z.string(), operation: z.enum(["add", "remove", "query", "tick"]), // For add condition: ConditionSchema.optional(), source: z.string().optional(), // "Blindness/Deafness spell" duration: z .union([ z.number(), // Rounds z.literal("concentration"), z.literal("until_dispelled"), z.literal("until_rest"), ]) .optional(), // For exhaustion specifically exhaustionLevels: z.number().min(1).max(6).optional(), // For remove removeAll: z.boolean().optional(), // Remove all instances // For tick (end of turn processing) roundNumber: z.number().optional(), }); // Response includes all active conditions with metadata ``` --- ## Schema Design: `calculate_aoe` Example ```typescript const calculateAoeSchema = z.object({ encounterId: z.string(), shape: z.enum(["line", "cone", "cube", "sphere", "cylinder"]), origin: PositionSchema, // Point of origin // Shape-specific length: z.number().optional(), // Line, Cone width: z.number().optional(), // Line (default 5ft) radius: z.number().optional(), // Sphere, Cylinder, Cone angle sideLength: z.number().optional(), // Cube height: z.number().optional(), // Cylinder direction: z .object({ // For line/cone x: z.number(), y: z.number(), }) .optional(), // Options includeOrigin: z.boolean().default(false), ignoreIds: z.array(z.string()).optional(), // Don't count these }); // Returns: { affectedTiles: Position[], affectedCreatures: string[] } ``` --- ## Migration Path ### From rpg-mcp to rpg-mcp-lite | rpg-mcp Tool | Lite Equivalent | Notes | | --------------------------------------------------------------- | --------------------- | ------------------ | | `create_encounter` | `create_encounter` | Simplified terrain | | `execute_combat_action` | `execute_action` | Unified actions | | `update_character` + `add_condition` | `manage_condition` | Consolidated | | `apply_custom_effect` | `manage_effect` | Renamed | | `calculate_aoe` | `calculate_aoe` | Same | | `measure_distance` | `measure_distance` | Same | | `cast_spell` (via execute) | `cast_spell` | Dedicated tool | | `roll_skill_check` + `roll_ability_check` + `roll_saving_throw` | `roll_check` | Unified | | `take_long_rest` + `take_short_rest` | `take_rest` | Unified | | `give_item` + `remove_item` + `equip_item` | `manage_inventory` | Consolidated | | `create_party` + `add_party_member` | `manage_party` | Consolidated | | `add_narrative_note` | `add_session_note` | Renamed | | `get_narrative_context` | `get_session_context` | Renamed | ### Removed (Handled Narratively by DM) - All worldgen tools (Perlin, biomes, rivers) - All grand strategy tools (nations, diplomacy) - Corpse/loot table system - Theft provenance - Event inbox - POI discovery system - Workflow orchestration --- ## Implementation Priority ### Phase 1: Combat Core (MVP) 1. `create_encounter` 2. `execute_action` 3. `advance_turn` 4. `apply_damage` 5. `manage_condition` 6. `roll_check` 7. `render_battlefield` ### Phase 2: Spatial 8. `calculate_aoe` 9. `measure_distance` 10. `check_line_of_sight` 11. `check_cover` 12. `move_combatant` ### Phase 3: Magic 13. `cast_spell` 14. `check_concentration` 15. `manage_spell_slots` 16. `create_aura` ### Phase 4: Data Layer 17. `create_character` 18. `manage_inventory` 19. `manage_party` 20. `add_session_note` 21. `get_session_context` ### Phase 5: Polish - Remaining tools - Reference table integration - Schema refinement --- ## File Structure ``` rpg-mcp-lite/ ├── src/ │ ├── index.ts # Server entry │ ├── modules/ │ │ ├── combat/ │ │ │ ├── tools.ts # Combat tool definitions │ │ │ ├── engine.ts # Combat state machine │ │ │ └── conditions.ts # Condition effects │ │ ├── spatial/ │ │ │ ├── tools.ts │ │ │ ├── geometry.ts # AoE shapes, LoS │ │ │ └── grid.ts # Grid utilities │ │ └── magic/ │ │ ├── tools.ts │ │ ├── spells.ts # Spell database │ │ └── concentration.ts │ ├── data/ │ │ ├── tools.ts # Character, inventory, party tools │ │ ├── session.ts # Session notes │ │ └── reference.ts # D&D 5e tables │ ├── schema/ │ │ ├── combat.ts │ │ ├── spatial.ts │ │ ├── magic.ts │ │ ├── character.ts │ │ └── session.ts │ └── storage/ │ ├── db.ts # SQLite setup │ └── repos/ # Repository pattern ├── tests/ ├── package.json └── tsconfig.json ``` --- ## Phase 1 Completion Report (2025-12-17) ### ✅ Completed Systems **6 Core Tools Operational (112/112 tests passing):** 1. `roll_dice` - Full dice notation support + batch rolling (up to 20) 2. `create_character` - D&D 5e character creation with ASCII art output 3. `get_character` - Character sheets with **condition integration** 4. `update_character` - Batch updates + relative HP ("+10", "-15") 5. `manage_condition` - Full D&D 5e condition system with mechanical effects 6. `measure_distance` - Spatial calculations ### 🎯 Key Architectural Decisions Made **1. Effective Stats Pattern (CRITICAL)** Established the "base → effective" calculation pattern for ALL stat modifications: ```typescript interface EffectiveStatCalculation { base: number; // Original from character sheet effective: number; // After modifiers modified: boolean; // Was it changed? modifiers: string[]; // Human-readable explanations } ``` **Why This Matters:** This pattern must be replicated for: - Equipment bonuses (armor, weapons, magic items) - Custom effects (boons, curses) - Spell effects (Mage Armor, Shield, Haste) - Environmental effects (altitude, underwater) **2. Condition System = Blueprint for All Modifiers** `manage_condition` established: - Generic `ConditionEffect` interface (extensible to custom effects) - Mechanical effects: HP/speed/AC modifiers, advantage/disadvantage - Character integration: `getActiveConditions()`, `calculateEffectiveStats()` - Display integration: `get_character` shows base vs effective stats **Implications:** - `manage_effect` (boons/curses) should use SAME interface - Equipment bonuses should use SAME calculation - ALL systems that modify stats should export similar functions **3. Batch Operations = First-Class Citizens** Pattern: `single_input OR { batch: single_input[] }` Implemented in: - `roll_dice`: Roll multiple expressions in one call - `update_character`: Update multiple characters (e.g., AoE damage) - `manage_condition`: Batch add/remove/query conditions **To Extend To:** - `execute_action` (multi-target attacks) - `apply_damage` (AoE spells) - `manage_inventory` (loot distribution) - `manage_spell_slots` (rest affects whole party) **4. Character Names > IDs** All tools now accept `characterName` OR `characterId` for better UX. **Status:** - ✅ manage_condition - ✅ update_character - ✅ get_character - ⬜ Roll out to ALL character-referencing tools **5. Persistence Strategy: JSON First** **Decided:** Use JSON files in AppData, defer SQLite to Phase 2 **Current:** - ✅ Characters: JSON per character - ❌ Conditions: In-memory (BUG - lost on restart) - ⬜ Encounters: Not implemented - ⬜ Equipment: Not implemented - ⬜ Session notes: Not implemented **Critical Fix Required:** Persist condition store to `conditions.json` --- ## Critical Intersections Identified **See: [SYSTEM-INTERSECTIONS.md](./SYSTEM-INTERSECTIONS.md)** Key findings: 1. **Damage → Concentration**: apply_damage must call check_concentration 2. **0 HP → Unconscious**: apply_damage must add condition 3. **Incapacitated → Break Concentration**: condition system needs magic system hooks 4. **Rest → Multi-System**: take_rest orchestrates 5+ different systems 5. **Equipment → Stats**: Must use same effective stats pattern as conditions --- ## Open Questions 1. **Creature presets**: Keep inline in tool descriptions or separate lookup? 2. **Spell database**: Full 5e SRD or just structure + lookup tool? 3. **Session persistence**: Confirmed JSON, but when to migrate to SQLite? 4. **Meta-tools**: Keep `search_tools` / `load_tool_schema` pattern? 5. **Condition Persistence**: Save on every change or batch at intervals? --- _Version: 0.2.0-design (Post-Condition System)_ _Author: Mnehmos + Claude_ _Date: 2025-12-17_

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Mnehmos/ChatRPG'

If you have feedback or need assistance with the MCP directory API, please join our Discord server