Improved 5etools MCP https://5e.dungeon.church
  • TypeScript 99.1%
  • JavaScript 0.9%
Find a file
Clawd 9a018f67ab
All checks were successful
Notify Cybersyn / notify (push) Successful in 3s
Test / test (push) Successful in 29s
Add DM prep tools (treasure, random encounters, scaling, magic items) (#6)
# Add DM Prep Tools

## Summary

Implements four essential DM preparation tools that dramatically reduce the number of queries needed during session prep. Based on Brad's request to streamline encounter planning, treasure generation, and magic item selection workflows.

## New Tools

### 1. `generate_treasure`
**Purpose**: Generate treasure following DMG Chapter 7 treasure tables

**Input**:
- `challenge_rating?: number` - CR of the encounter (0-30) for individual treasure
- `hoard_tier?: "tier1"|"tier2"|"tier3"|"tier4"` - Hoard tier for party level ranges
- `magic_item_preference?: "none"|"few"|"many"` - Adjust magic item frequency

**Output**:
- Copper/Silver/Electrum/Gold/Platinum coins
- Gems with values and descriptions
- Art objects with values and descriptions
- Magic items from Tables A-I
- Total gold piece value

**Features**:
- Full DMG treasure tables (individual + hoard)
- 10 gem value tiers with flavor descriptions
- Magic item tables A-I with proper distributions
- Configurable magic item frequency

**Example**:
```typescript
{
  hoard_tier: "tier2",
  magic_item_preference: "many"
  // Returns: 12,000 gp, 4 gems (500gp each), 2 art objects (750gp each),
  // 3 magic items (Tables A-D)
}
```

---

### 2. `random_encounter`
**Purpose**: Generate environment-appropriate random encounters

**Input**:
- `environment: string` - Terrain type (forest, underdark, mountain, desert, urban, coast, arctic, swamp, grassland)
- `party: number[]` - Character levels
- `difficulty: "easy"|"medium"|"hard"|"deadly"` - Desired difficulty
- `monster_count?: number` - Preferred number of monsters
- `ruleset?: "2014"|"2024"|"any"` - Ruleset filter

**Output**:
- Thematically appropriate monsters for environment
- Encounter difficulty rating
- Total XP (base and adjusted)
- Flavor text describing the encounter

**Features**:
- 9 environment types with curated monster type lists
- Forest: beasts, fey, plants
- Underdark: aberrations, oozes, drow
- Mountain: giants, dragons, orcs
- Desert: elementals, monstrosities
- Urban: humanoids, constructs, undead
- Coast/Arctic/Swamp/Grassland: appropriate creature types

**Example**:
```typescript
{
  environment: "underdark",
  party: [5, 5, 5, 5],
  difficulty: "hard"
  // Returns: 3× Mind Flayer (CR 7), adjusted XP 3600, Hard encounter
  // "Deep in the lightless depths, horror stirs..."
}
```

---

### 3. `scale_encounter`
**Purpose**: Adjust encounters to new difficulty or party composition

**Input**:
- `current_encounter: Array<{cr: number|string, count: number}>` - Current monsters
- `current_party: number[]` - Original party levels
- `target_party?: number[]` - New party levels (if party changed)
- `target_difficulty?: "easy"|"medium"|"hard"|"deadly"` - Desired difficulty
- `adjustment?: "easier"|"harder"` - Relative adjustment

**Output**:
- Original encounter summary (XP, difficulty)
- Scaled encounter with adjusted counts/CRs
- New difficulty rating
- Detailed rationale explaining what changed and why
- Scaling strategy used

**Features**:
- Three scaling strategies:
  - **Count scaling**: Increase/decrease monster numbers
  - **CR swapping**: Replace with higher/lower CR versions
  - **Mixed**: Combination approach
- Preserves encounter "feel" (same monster types)
- Supports party size/level changes

**Example**:
```typescript
{
  current_encounter: [{cr: 5, count: 2}],
  current_party: [7, 7, 7, 7],
  target_difficulty: "deadly"
  // Returns: 4× CR 5 (scaled from 2), Medium → Deadly
  // Rationale: "Increased monster count from 2 to 4 to reach deadly threshold"
}
```

---

### 4. `suggest_magic_items`
**Purpose**: Suggest tier-appropriate magic items for party level

**Input**:
- `party_level?: number` - Average party level (1-20)
- `tier?: "tier1"|"tier2"|"tier3"|"tier4"` - Alternative to party_level
- `item_type?: string` - Filter by type (weapon, armor, wondrous, potion, scroll, ring, rod, staff, wand)
- `rarity?: "common"|"uncommon"|"rare"|"very rare"|"legendary"|"artifact"` - Override tier-appropriate rarity
- `count?: number` - How many items to suggest (default: 5, max: 50)
- `source?: string` - Filter by source abbreviation
- `ruleset?: "2014"|"2024"|"any"` - Ruleset filter

**Output**:
- Array of magic items appropriate for tier
- Each item: name, rarity, type, source, brief description

**Features**:
- Tier-appropriate rarity distributions:
  - **Tier 1 (1-4)**: Common 30%, Uncommon 70%
  - **Tier 2 (5-10)**: Uncommon 50%, Rare 50%
  - **Tier 3 (11-16)**: Rare 40%, Very Rare 60%
  - **Tier 4 (17-20)**: Very Rare 60%, Legendary 40%
- Weighted selection within tier constraints
- Multiple filter options (type, rarity, source, ruleset)

**Example**:
```typescript
{
  party_level: 8,
  item_type: "weapon",
  count: 3
  // Returns: 3 tier-appropriate weapons (mix of Uncommon/Rare)
  // e.g., +1 Longsword, Flame Tongue, Oathbow
}
```

---

## Implementation

**Files Added**:
- `src/treasure.ts` (27KB) - Treasure generation with DMG tables
- `src/random-encounter.ts` - Environment-based encounter generation
- `src/scale-encounter.ts` - Encounter scaling logic
- `src/magic-items.ts` - Magic item suggestion with tier weighting
- `tests/treasure.test.ts` (44 tests)
- `tests/random-encounter.test.ts` (29 tests)
- `tests/scale-encounter.test.ts` (25 tests)
- `tests/magic-items.test.ts` (24 tests)

**Files Modified**:
- `src/server.ts` - 4 new tool registrations with comprehensive schemas

**Test Coverage**:
- 122 new tests covering all functionality
- All edge cases (CR 0-30, fractional CRs, party sizes, environments)
- Statistical validation for treasure generation
- DMG compliance verification

---

## Testing

All 234 tests pass:
```bash
npm test
# ✓ 234 tests passed (122 new)
```

---

## Usage Impact

**Before** (manual multi-query workflow):
1. "Search monsters in forest"
2. "What's CR 3 XP?"
3. "Calculate encounter difficulty for 4× 5th level"
4. "What magic items for tier 2?"
5. "Roll treasure for CR 5 hoard"
→ **5+ queries per encounter**

**After** (streamlined single queries):
- `random_encounter({environment: "forest", party: [5,5,5,5], difficulty: "medium"})` → Complete thematic encounter
- `generate_treasure({hoard_tier: "tier2"})` → Full treasure hoard
- `suggest_magic_items({party_level: 5, count: 3})` → Tier-appropriate loot
- `scale_encounter({...})` → Instant difficulty adjustment
→ **1 query per task**

---

## Reference

Based on **Dungeon Master's Guide (2014)**:
- Chapter 7: Treasure (individual/hoard tables, magic items)
- Chapter 13: Building Encounters (XP, multipliers, thresholds)
- Appendix A: Random Dungeons (environment encounter tables)

Full encounter design reference: `~/.openclaw/workspace/skills/5etools/references/encounter-design.md`

---

## Next Steps

Potential enhancements:
- NPC generator (stats + personality traits)
- Trap generator (CR-appropriate traps)
- Lair action generator for boss encounters
- Weather/environment hazard generator

Reviewed-on: #6
Co-authored-by: Clawd <agent@dungeon.church>
Co-committed-by: Clawd <agent@dungeon.church>
2026-02-15 00:06:21 -08:00
.cursor/rules extract(renderer): move renderer to src/renderer.ts; add {@creature} and {@recharge} handlers with tests\n\nchore(types): install @types/node; adjust MCP tool response shapes\nchore(test): add Vitest, config, and renderer tests; exclude upstream tests\nchore(tsconfig): exclude tests from build to satisfy rootDir\nrefactor(server): import renderer/utils and remove inlined helpers 2025-08-11 01:19:31 +02:00
.forgejo/workflows ci: make test and notify-cybersyn workflows independent 2026-02-15 06:40:07 +00:00
5etools-src@c0085e8bc4 Add Cursor rules: core guidance, TypeScript standards, and read-only dataset enforcement 2025-08-11 00:29:56 +02:00
prompts extract(renderer): move renderer to src/renderer.ts; add {@creature} and {@recharge} handlers with tests\n\nchore(types): install @types/node; adjust MCP tool response shapes\nchore(test): add Vitest, config, and renderer tests; exclude upstream tests\nchore(tsconfig): exclude tests from build to satisfy rootDir\nrefactor(server): import renderer/utils and remove inlined helpers 2025-08-11 01:19:31 +02:00
src Add DM prep tools (treasure, random encounters, scaling, magic items) (#6) 2026-02-15 00:06:21 -08:00
tests Add DM prep tools (treasure, random encounters, scaling, magic items) (#6) 2026-02-15 00:06:21 -08:00
.cursorignore extract(renderer): move renderer to src/renderer.ts; add {@creature} and {@recharge} handlers with tests\n\nchore(types): install @types/node; adjust MCP tool response shapes\nchore(test): add Vitest, config, and renderer tests; exclude upstream tests\nchore(tsconfig): exclude tests from build to satisfy rootDir\nrefactor(server): import renderer/utils and remove inlined helpers 2025-08-11 01:19:31 +02:00
.cursorrules Add Cursor rules for mcp-5etools 2025-08-11 00:27:56 +02:00
.env.example extract(renderer): move renderer to src/renderer.ts; add {@creature} and {@recharge} handlers with tests\n\nchore(types): install @types/node; adjust MCP tool response shapes\nchore(test): add Vitest, config, and renderer tests; exclude upstream tests\nchore(tsconfig): exclude tests from build to satisfy rootDir\nrefactor(server): import renderer/utils and remove inlined helpers 2025-08-11 01:19:31 +02:00
.gitignore extract(renderer): move renderer to src/renderer.ts; add {@creature} and {@recharge} handlers with tests\n\nchore(types): install @types/node; adjust MCP tool response shapes\nchore(test): add Vitest, config, and renderer tests; exclude upstream tests\nchore(tsconfig): exclude tests from build to satisfy rootDir\nrefactor(server): import renderer/utils and remove inlined helpers 2025-08-11 01:19:31 +02:00
.gitmodules Add Cursor rules: core guidance, TypeScript standards, and read-only dataset enforcement 2025-08-11 00:29:56 +02:00
ARCHITECTURE.md extract(renderer): move renderer to src/renderer.ts; add {@creature} and {@recharge} handlers with tests\n\nchore(types): install @types/node; adjust MCP tool response shapes\nchore(test): add Vitest, config, and renderer tests; exclude upstream tests\nchore(tsconfig): exclude tests from build to satisfy rootDir\nrefactor(server): import renderer/utils and remove inlined helpers 2025-08-11 01:19:31 +02:00
CONTRIBUTING.md extract(renderer): move renderer to src/renderer.ts; add {@creature} and {@recharge} handlers with tests\n\nchore(types): install @types/node; adjust MCP tool response shapes\nchore(test): add Vitest, config, and renderer tests; exclude upstream tests\nchore(tsconfig): exclude tests from build to satisfy rootDir\nrefactor(server): import renderer/utils and remove inlined helpers 2025-08-11 01:19:31 +02:00
LICENSE extract(renderer): move renderer to src/renderer.ts; add {@creature} and {@recharge} handlers with tests\n\nchore(types): install @types/node; adjust MCP tool response shapes\nchore(test): add Vitest, config, and renderer tests; exclude upstream tests\nchore(tsconfig): exclude tests from build to satisfy rootDir\nrefactor(server): import renderer/utils and remove inlined helpers 2025-08-11 01:19:31 +02:00
package-lock.json extract(renderer): move renderer to src/renderer.ts; add {@creature} and {@recharge} handlers with tests\n\nchore(types): install @types/node; adjust MCP tool response shapes\nchore(test): add Vitest, config, and renderer tests; exclude upstream tests\nchore(tsconfig): exclude tests from build to satisfy rootDir\nrefactor(server): import renderer/utils and remove inlined helpers 2025-08-11 01:19:31 +02:00
package.json extract(renderer): move renderer to src/renderer.ts; add {@creature} and {@recharge} handlers with tests\n\nchore(types): install @types/node; adjust MCP tool response shapes\nchore(test): add Vitest, config, and renderer tests; exclude upstream tests\nchore(tsconfig): exclude tests from build to satisfy rootDir\nrefactor(server): import renderer/utils and remove inlined helpers 2025-08-11 01:19:31 +02:00
PR_DM_TOOLS.md Add DM prep tools (treasure, random encounters, scaling, magic items) (#6) 2026-02-15 00:06:21 -08:00
README.md feat: add domain-specific search tools for spells, monsters, and items (#2) 2026-02-14 22:32:45 -08:00
tsconfig.json extract(renderer): move renderer to src/renderer.ts; add {@creature} and {@recharge} handlers with tests\n\nchore(types): install @types/node; adjust MCP tool response shapes\nchore(test): add Vitest, config, and renderer tests; exclude upstream tests\nchore(tsconfig): exclude tests from build to satisfy rootDir\nrefactor(server): import renderer/utils and remove inlined helpers 2025-08-11 01:19:31 +02:00
vitest.config.ts extract(renderer): move renderer to src/renderer.ts; add {@creature} and {@recharge} handlers with tests\n\nchore(types): install @types/node; adjust MCP tool response shapes\nchore(test): add Vitest, config, and renderer tests; exclude upstream tests\nchore(tsconfig): exclude tests from build to satisfy rootDir\nrefactor(server): import renderer/utils and remove inlined helpers 2025-08-11 01:19:31 +02:00

mcp-5etools — MCP Server for 5eTools Data

Senior Platform Engineer goal: Expose 5eTools-style data to LLMs via Model Context Protocol (MCP) so the model can

  • search rules/entities,
  • fetch structured records (monster/spell/item/etc.),
  • render 5eTools entries + {@tags} into Markdown/HTML,
  • cite stable URIs (so the model can reference content consistently).

Important layout assumption: This repository contains a checked-out copy of 5etools-src/ at the project root:

/ (project root)
├─ 5etools-src/        # the upstream 5eTools data repo (not included in this package)
├─ src/                # MCP server implementation
├─ README.md           # you are here
├─ .cursorrules        # Cursor AI project guidance
└─ ...

The server reads data from ./5etools-src by default. Do not modify upstream content; treat it as read-only data.


Why this server exists

LLMs dont need whole books — they need fast, reliable primitives:

  1. Search by name/aliases with minimal facets (e.g., CR/type for monsters; level/school for spells).
  2. Get entity in structured JSON or rendered Markdown/HTML.
  3. Render entries with {@tags} (e.g., {@spell fireball}) into linkable text.
  4. List sources and resolve rules sections across 2014 vs 2024 rulesets.
  5. Stable URIs to cite/compare entities.

This MCP server provides those primitives so downstream LLM agents stop guessing and start calling tools.


Cursor Rules: This repo uses Project Rules in .cursor/rules/*.mdc (MDC format). Legacy .cursorrules is removed. See: .cursor/rules/.

Quickstart

# 1) Ensure Node 18+
node -v

# 2) Place/clone the upstream 5eTools repository at project root:
git clone https://github.com/5etools-mirror-3/5etools-src ./5etools-src
# (Optionally pin to a specific tag for deterministic behavior.)

# 3) Install & build
npm install
npm run build

# 4) Run (stdio transport)
npm start
# or: node dist/server.js

If you prefer an explicit path, set FIVETOOLS_SRC_DIR:

FIVETOOLS_SRC_DIR=./5etools-src npm start

MCP Surfaces (Tools & Resources)

Tools

  • search_entities({ query, kinds?, sources?, ruleset?, limit? }) — generic fuzzy search across all entity types
  • search_spells({ name?, level?, school?, classes?, source?, ruleset?, limit? }) — domain-specific spell search
  • search_monsters({ name?, cr_min?, cr_max?, type?, source?, ruleset?, limit? }) — domain-specific monster search
  • search_items({ name?, rarity?, type?, attunement?, source?, ruleset?, limit? }) — domain-specific item search
  • get_entity({ uri? | key:{kind,name,source?,ruleset?}, format?, includeFluff? })
  • render_entries({ entries, format? })
  • list_sources({ ruleset?, kind? })
  • get_rules_section({ slugOrTitle, ruleset? })
  • resolve_tag({ tag })

Resources

  • fiveet://entity/{kind}/{source}/{slug} → entity JSON

Minimal tag rendering supports common tags ({@spell}, {@item}, {@condition}, {@dice}, {@damage}, {@dc}, {@hit}) and can be extended.

Domain-Specific Search Examples

Search for 3rd-level evocation spells:

{
  "tool": "search_spells",
  "parameters": {
    "level": 3,
    "school": "E"
  }
}

Search for wizards spells named "fireball":

{
  "tool": "search_spells",
  "parameters": {
    "name": "fireball",
    "classes": ["wizard"]
  }
}

Search for CR 5-10 dragons:

{
  "tool": "search_monsters",
  "parameters": {
    "cr_min": 5,
    "cr_max": 10,
    "type": "dragon"
  }
}

Search for legendary items that require attunement:

{
  "tool": "search_items",
  "parameters": {
    "rarity": "legendary",
    "attunement": true
  }
}

Notes:

  • school uses abbreviated codes: A (abjuration), C (conjuration), D (divination), E (evocation), I (illusion), N (necromancy), T (transmutation), V (enchantment)
  • cr_min/cr_max accept fractional values (e.g., 0.125 for CR 1/8, 0.25 for CR 1/4)
  • All domain-specific tools support ruleset filtering ("2014", "2024", or "any")
  • Use search_entities for cross-domain or exploratory searches

Repository scripts

  • npm run build — TypeScript → dist/
  • npm start — launch MCP server on stdio

Project constraints

  • Read-only: Treat 5etools-src/ as immutable input.
  • Determinism: For production, pin a 5eTools tag/commit.
  • Licensing: This project ships no 5eTools content. Review upstream licensing before redistribution.

Integration notes

  • MCP clients (e.g., Claude Desktop, OpenWebUI MCP, custom hosts) can execute this binary and communicate over stdio.
  • Prefer returning resource_links to fiveet://entity/... when possible; clients can fetch entity JSON as needed.
  • When disambiguation is required, prefer 2024 rules unless explicitly asked for 2014.

Roadmap (next steps)

  • Expand tag renderer to cover 20+ {@...} forms with unit tests.
  • Add fuzzy search (Minisearch/Lunr) with facets and source/ruleset filters.
  • Add get_rules_section, resolve_tag, and list_sources tools.
  • Provide Dockerfile + GitHub Actions CI for lint/test/build.
  • Optional: expose /schema/{kind} resources with JSON Schema snapshots.

Dev Tips

  • Use npm run build after changes; TypeScript config is strict.
  • The loader builds in-memory indices at startup; for large-scale use, consider persistent indices on disk.
  • Keep renderer pure/deterministic for reliable LLM outputs.

License

This MCP servers code is MIT-licensed (see LICENSE). Upstream 5eTools data is not included and is subject to its own licensing.

Prompts

Reusable LLM prompt templates live in ./prompts/:

  • 00-agent-system.md — system-level behavior (MCP-first)
  • 10-search-lookup.md — lookup flow
  • 20-compare-entities.md — comparison tables
  • 30-render-entries.md — render 5eTools entries blobs
  • 40-rules-qa.md — rules Q&A
  • 50-resolve-tag.md — inline tag resolver
  • 60-adventure-parsing.md — module parsing notes
  • 70-house-rules-overlay.md — official + house rules
  • 80-eval-checklist.md — preflight checklist