A complete D&D 5e reference and utility MCP server backed by live 5etools data.
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.
- Download
5eMCP.mcpbfrom the latest release - Open the file — Claude Desktop will prompt you to install it, or go to Settings → Extensions → Install Extension and select the file
- Enter your GitHub personal access token when prompted (required — create a free one at github.com/settings/tokens with
public_reposcope or read-only access to public repos) - Choose your default ruleset (
2024or2014) - Restart Claude Desktop
Your token is stored securely in the OS keychain (macOS Keychain / Windows Credential Manager) — never in plain text.
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 belowIn the configs below, replace /path/to/5eMCP with the output of pwd above (e.g. /Users/you/Projects/5eMCP).
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"
}
}
}
}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"
}
}
}
}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.
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.
| 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. |
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 |
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 |
| 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). |
| 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). |
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. |
| 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. |
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.
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:
- Claude Desktop (or claude.ai) → Settings → Connectors → Add custom connector
- Enter your server's URL, e.g.
https://5emcp.example.com/mcp - 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.
All tools accept ruleset: "2024" | "2014":
"2024"→5etools-mirror-3/5etools-src(current rules)"2014"→5etools-mirror-3/5etools-2014-src(legacy rules)
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 # ESLintThis 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.shflowchart 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
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.
D20 icon by Delapouite via game-icons.net, licensed CC BY 3.0.
