Skip to content

Repository files navigation

D20 5eMCP

Tests Version Install in Claude Desktop

A complete D&D 5e reference and utility MCP server backed by live 5etools data.

Quick Start

Claude Desktop — One-Click Install (recommended)

Prerequisite: Node.js ≥ 22 must be your system's default node. Claude Desktop uses the macOS launch environment PATH, not your shell session — your terminal's active nvm version doesn't apply. If you use nvm, run nvm alias default 22 (or nvm install 22 && nvm alias default 22 if you don't have it) and fully quit and relaunch Claude Desktop. If you don't use nvm, install Node.js from nodejs.org.

  1. Download 5eMCP.mcpb from the latest release
  2. Open the file — Claude Desktop will prompt you to install it, or go to Settings → Extensions → Install Extension and select the file
  3. Enter your GitHub personal access token when prompted (required — create a free one at github.com/settings/tokens with public_repo scope or read-only access to public repos)
  4. Choose your default ruleset (2024 or 2014)
  5. Restart Claude Desktop

Your token is stored securely in the OS keychain (macOS Keychain / Windows Credential Manager) — never in plain text.


Developers (Claude Code, Cursor, manual config)

Requirements: Node.js ≥ 22, optional GitHub personal access token (read-only, public repos)

git clone https://github.com/jazzsequence/5eMCP.git
cd 5eMCP
npm install
npm run build
pwd   # copy this — you'll use it as your path in the config below

In the configs below, replace /path/to/5eMCP with the output of pwd above (e.g. /Users/you/Projects/5eMCP).

Claude Code

Add to ~/.claude.json:

{
  "mcpServers": {
    "5etools": {
      "command": "node",
      "args": ["/path/to/5eMCP/dist/index.js"],
      "env": {
        "GITHUB_TOKEN": "ghp_your_token_here",
        "DEFAULT_RULESET": "2024"
      }
    }
  }
}

Cursor

Add to .cursor/mcp.json in your project (or ~/.cursor/mcp.json globally):

{
  "mcpServers": {
    "5etools": {
      "command": "node",
      "args": ["/path/to/5eMCP/dist/index.js"],
      "env": {
        "GITHUB_TOKEN": "ghp_your_token_here",
        "DEFAULT_RULESET": "2024"
      }
    }
  }
}

Claude Desktop (manual config) {#claude-desktop-manual-config}

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "5etools": {
      "command": "node",
      "args": ["/path/to/5eMCP/dist/index.js"],
      "env": {
        "GITHUB_TOKEN": "ghp_your_token_here",
        "DEFAULT_RULESET": "2024"
      }
    }
  }
}

DEFAULT_RULESET can be "2024" (default) or "2014" for legacy rules. GITHUB_TOKEN is optional but strongly recommended — unauthenticated requests are rate-limited to 60/hr.

How It Works

5e.tools is fully client-side. When spells.html loads, the browser fetches data/spells/spells-phb.json directly from GitHub and renders it in JavaScript. This server replicates that pattern server-side:

GitHub Contents API
  → manifest: { spells: [...], bestiary: [...], book: [...], ... }
  → SHA-keyed disk/Redis cache
  → raw.githubusercontent.com (fetch on miss)
  → translation layer (resolve {@tags}, merge fluff, normalize)
  → MCP tool response

The manifest is schema-agnostic and self-updating. When 5etools adds a new content type, the next manifest refresh picks it up automatically — no code change required. Unknown types run through the passthrough handler (tags resolved, internal fields stripped) and return clean JSON. Nothing is ever inaccessible.

Available Tools

Meta Tools

Tool Description
manifest_status Build time, file counts by type, unknown types discovered.
list_sources All source abbreviations with content types.
fetch_content Fetch and translate any file in the manifest by content type + file name. Universal fallback for any content type.

Search Tools (*_search)

All search tools accept query (name substring), ruleset ("2024" or "2014"), limit, fields (optional list of field names to include in each result — default is all fields, e.g. ["name","cr","source"]), and include_homebrew (boolean, default false — when true also searches TheGiddyLimit/homebrew alongside official results). Results match on name, source abbreviation, pantheon/setting, and any top-level array-of-strings field in the data (e.g. damageInflict, conditionInflict, environment, property tags like "Vst|EGW").

Selected tools support additional structured filter parameters:

Tool Extra Parameters
spell_search level (int 0–9), school (full name: evocation, necromancy, etc.)
monster_search type (beast, humanoid, undead…), cr_max (max CR inclusive: "1/4", "1/2", "5"…), environment (habitat substring: "underdark", "forest", "nine hells"…)
item_search rarity (common, uncommon, rare, very rare, legendary, artifact), type (weapon, armor, wondrous…)
Tool Content
spell_search Spells
monster_search Monsters and creatures
item_search Magic and mundane items
race_search Playable species / races
background_search Character backgrounds
feat_search Feats
condition_search Conditions and diseases
vehicle_search Vehicles and vessels
object_search Objects
trap_search Traps and hazards
psionic_search Psionic powers and disciplines
deck_search Decks (e.g. Deck of Many Things)
reward_search Supernatural gifts and boons
optfeature_search Optional class features and invocations
table_search Random tables
variantrule_search Variant rules
deity_search Deities and gods (searchable by pantheon/setting)
language_search Languages
skill_search Skills
sense_search Senses (darkvision, tremorsense, etc.)
book_search Sourcebooks (name, ID, source, publication date)
adventure_search Published adventures
class_search Character classes (official + homebrew)
subclass_search Subclasses and archetypes

Get Tools (*_get)

Exact lookup by name with full fluff/description merged in. Accept name, optional source, and ruleset.

Tool Content
spell_get Full spell entry with description
monster_get Full stat block with lore
item_get Full item entry with description
race_get Full race entry with traits and fluff
background_get Full background entry with fluff
feat_get Full feat entry
book_get Sourcebook metadata by name
adventure_get Adventure metadata by name
class_get Full class entry by name
subclass_get Full subclass entry by name

Sourcebook & Adventure Content

Tool Description
book_content_get Retrieve full prose from a sourcebook or adventure by source abbreviation (e.g. SCC, EGW, SCC-CK). Without section: returns a table of contents. With section: returns that section's text rendered as clean markdown. Supports deep nested section search (case-insensitive substring match).

Omnisearch

Tool Description
omnisearch Search all 24 content types at once. Returns results tagged with entityType. Accepts include_homebrew (default true — homebrew is included by default).

DM Calculator Tools

All calculators are purely local — no network calls, no API key needed.

Tool Description
cr_calculate Calculate a monster's Challenge Rating from its stats (HP, AC, DPR, attack bonus). Applies DMG Appendix B algorithm. Supports damage immunity (effective HP ×2), resistance (×1.5), and vulnerability (×0.5). Returns final CR, XP, and the defensive/offensive sub-CRs.
cr_scale Look up the expected stat ranges (HP, AC, attack bonus, DPR, save DC, proficiency bonus) for a given CR from the DMG reference table. Useful for designing or adjusting homebrew monsters.
encounter_build Evaluate encounter difficulty for a party vs a set of monsters. Supports both 2014 (easy/medium/hard/deadly, with monster-count XP multiplier) and 2024 (low/moderate/high, no multiplier) rulesets. Returns adjusted XP, difficulty label, and full threshold breakdown.
loot_generate Generate individual treasure loot for a monster by CR, using the DMG individual treasure tables. Returns all possible outcomes for the CR bracket with probability percentages and average coin amounts.

Environment Variables

Variable Default Description
GITHUB_TOKEN Read-only GitHub PAT. Strongly recommended.
DEFAULT_RULESET "2024" Which ruleset to use ("2024" or "2014").
MANIFEST_TTL_SECONDS 3600 How often to rebuild the manifest (seconds).
CACHE_DIR ~/.cache/5eMCP Disk cache location (local stdio mode).
REDIS_URL Redis connection URL (e.g. redis://localhost:6379). When set and reachable, Redis is used instead of disk cache. Falls back to disk on connection failure.
LOCAL_BASE_URL Base URL of a self-hosted 5etools static mirror (e.g. https://5e.example.com). When set, spell/monster/item/etc. content for the 2024 and 2014 ruleset repos is fetched from this mirror instead of raw.githubusercontent.com — faster, no GitHub rate limit for content fetches. Ignored if LOCAL_DATA_DIR is also set. Manifest indexing (file listing) still uses the GitHub Contents API, since a static mirror has no equivalent listing endpoint. Homebrew content is never redirected.
LOCAL_DATA_DIR Filesystem path to a local 5etools data/ directory (e.g. /opt/5etools/data) — typically used when the MCP server runs colocated with a self-hosted mirror. When set, both manifest indexing and content fetching read directly from disk, bypassing GitHub entirely for core ruleset content (no rate limit, no network round-trip at all). Homebrew still goes through the GitHub Contents API regardless, since self-hosted mirrors don't bundle it — that call degrades gracefully (logged, non-fatal) if it hits a rate limit. Assumes the directory matches the ruleset(s) you query; a single local mirror generally only reflects one ruleset.
PORT 3000 Port for the HTTP transport (npm start / dist/http.js).
MCP_HTTP_TOKEN Bearer token required on the HTTP transport's /mcp endpoint. If unset, the endpoint is unauthenticated — fine on a private network, not recommended for public exposure.

HTTP Transport

In addition to stdio (used by Claude Desktop/Code/Cursor above), the server supports the MCP Streamable HTTP transport, useful for running the server remotely (e.g. colocated with a self-hosted 5etools mirror) and connecting to it from clients that can't spawn a local process.

Colocated with a self-hosted mirror (reads the mirror's data/ directory straight off disk — fastest, no GitHub calls for core content):

LOCAL_DATA_DIR=/opt/5etools/data MCP_HTTP_TOKEN=your-secret npm start

Or pointing at a mirror over HTTP (e.g. the MCP server runs elsewhere than the mirror):

LOCAL_BASE_URL=https://5e.example.com MCP_HTTP_TOKEN=your-secret npm start

npm start runs the TypeScript source directly via tsx — no separate build step needed. If you do want a compiled build (e.g. for npm run build:mcpb), note that tsc is memory-hungry; on RAM-constrained hosts it can OOM, in which case npm start is the way to go anyway.

This starts a stateless HTTP server:

  • POST /mcp — MCP JSON-RPC endpoint (Streamable HTTP transport, one server instance per request)
  • GET /health — health check, returns {"status":"ok","service":"5eMCP"}

If MCP_HTTP_TOKEN is set, requests to /mcp must include Authorization: Bearer <token>; /health is always open.

Connecting Claude Desktop / claude.ai to a Remote Instance

Once the HTTP server is deployed and reachable, connect to it as a Custom Connector rather than editing claude_desktop_config.json — that file is for stdio servers that Claude spawns as a local process, which doesn't apply to a server running elsewhere:

  1. Claude Desktop (or claude.ai) → Settings → Connectors → Add custom connector
  2. Enter your server's URL, e.g. https://5emcp.example.com/mcp
  3. Click Add

If MCP_HTTP_TOKEN is unset, that's all — the connector works immediately. Note that the Custom Connector UI's "Advanced settings" are built for OAuth (Client ID/Secret), not a raw static bearer token, so MCP_HTTP_TOKEN isn't directly pluggable there. If you need auth on a Custom Connector, put a reverse proxy in front (e.g. Cloudflare Access, Caddy with basicauth) rather than relying on MCP_HTTP_TOKEN alone.

Ruleset Support

All tools accept ruleset: "2024" | "2014":

  • "2024"5etools-mirror-3/5etools-src (current rules)
  • "2014"5etools-mirror-3/5etools-2014-src (legacy rules)

Development

npm run dev          # Run without compile step (tsx)
npm run build        # Compile TypeScript
npm run typecheck    # Type-check without emitting
npm test             # Run tests (Vitest)
npm run lint         # ESLint

This project uses TDD. Tests are written before implementation. See AGENTS.md for the full workflow including mandatory reviewer agent approval before commits.

# First-time setup: install git hooks
./.githooks/install.sh

Architecture

flowchart TD
    Client["MCP Client\n(Claude Desktop / Claude Code / Cursor)"]
    Server["MCP Server (Node.js)"]
    Manifest["Manifest Layer\n1-hour TTL refresh"]
    Cache["Cache Layer\nSHA-keyed disk or Redis"]
    Translation["Translation Layer\ntag resolver · typed handlers · passthrough"]
    Calculators["Calculators\nCR · encounter · loot · scaling"]
    GH["GitHub Contents API"]
    Raw["raw.githubusercontent.com"]
    Redis[("Redis / Disk")]

    Client -->|stdio| Server
    Server --> Manifest
    Server --> Cache
    Server --> Translation
    Server --> Calculators
    Manifest -->|"index all files"| GH
    Cache -->|"fetch on miss"| Raw
    Cache <-->|"read / write"| Redis
Loading

Legal

5etools data is fetched live from public GitHub repositories. This server does not store or redistribute any content. The GitHub API rate limit applies. A GitHub token is required for sustained use.

Calculator logic is ported from 5etools' MIT-licensed JavaScript source.

Credits

D20 icon by Delapouite via game-icons.net, licensed CC BY 3.0.

About

No description, website, or topics provided.

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages