5eMCP is a Model Context Protocol server providing comprehensive access to D&D 5e content — spells, monsters, items, classes, full sourcebook prose, adventure text, homebrew, and callable DM utility tools — backed by live 5etools GitHub data. No API key required; files are the API.
Core design principle: Manifest-driven, pointer-based resolution. A lightweight dynamic index of everything in the 5etools repos is built from the GitHub Contents API. Content is never stored — when a tool is called, the server locates the file in the manifest, fetches only what is needed, runs it through the translation layer, and returns clean structured output.
- Runtime: Node.js 24 (native fetch, ESM)
- Language: TypeScript 5.x, strict mode, ESM (
"type": "module") - Module resolution: Node16 (requires
.jsextensions in imports) - MCP SDK:
@modelcontextprotocol/sdk—McpServer+StdioServerTransport - Validation: Zod
- Testing: Vitest
- Linting: ESLint +
@typescript-eslint - Cache: Disk (local stdio mode) / Redis (Pantheon HTTP mode)
- Data sources:
raw.githubusercontent.com, GitHub Contents API
npm run build # Compile TypeScript → dist/
npm run typecheck # Type-check without emitting
npm run dev # Run directly with tsx (no compile step)
npm test # Run Vitest tests (all)
npm run test:watch # Vitest in watch mode
npm run lint # ESLintsrc/
├── index.ts # Entry — stdio mode (HTTP in Phase 5)
├── server.ts # McpServer, tool registration
├── github.ts # GitHub Contents API + raw fetch
├── types.ts # Shared types (Ruleset, GitHubContentsItem, repos)
├── manifest/
│ ├── schema.ts # ManifestFile, Manifest interfaces
│ ├── builder.ts # GitHub Contents API → Manifest (schema-agnostic)
│ └── refresh.ts # 1-hour TTL refresh loop + in-memory cache
├── cache/
│ ├── index.ts # Disk cache (local) — SHA-keyed JSON files
│ └── keys.ts # contentKey(sha), manifestKey(ruleset)
├── translation/
│ ├── index.ts # Handler dispatch: typed handler or passthrough
│ ├── tags.ts # {@tag} recursive resolver
│ ├── strip.ts # Internal 5etools field stripper
│ ├── passthrough.ts # Generic unknown-type handler
│ └── handlers/ # One typed handler per known content type (Phase 2+)
├── tools/
│ ├── meta.ts # manifest_status, list_sources (Phase 1)
│ └── passthrough.ts # fetch_content (Phase 1)
└── calculators/ # Ported 5etools DM tools (Phase 4)
- Phase 1 (done): Manifest core + universal passthrough. Every content type accessible via
fetch_content. - Phase 2 (done): Typed search/get tools for all 22 content types, multi-field search, structured filters (level, school, cr_max, type, rarity, environment), fields projection, omnisearch.
- Phase 3 (done): Books/adventures index tools, homebrew search (include_homebrew flag), Redis cache (gated on REDIS_URL, falls back to disk).
- Phase 4 (done): Callable DM tools —
cr_calculate,cr_scale,encounter_build,loot_generate. Completes the 1.0 featureset. - Phase 5 (post-1.0): Express HTTP transport + Pantheon deploy.
- Manifest is schema-agnostic.
content: Record<string, ManifestFile[]>— new 5etools content types appear automatically on next refresh. No code change required. - SHA-keyed cache. Cache keys are GitHub blob SHAs, not filenames. Content that hasn't changed is never re-fetched.
- Passthrough guarantee. Unknown content types always run through the passthrough handler (resolve
{@tags}, strip internal fields, return clean JSON). Nothing is ever inaccessible. - Translation is stateless. The translation layer has no awareness of manifest or cache. Pure functions only.
- Tools are thin wrappers. Parameter validation and response formatting only. All data logic lives in manifest/cache/translation layers.
.jsextensions required in all TypeScript ESM imports (e.g.,import { foo } from "./bar.js").
GITHUB_TOKEN # Read-only PAT (5000 req/hr vs 60 unauth) — strongly recommended
DEFAULT_RULESET # "2024" (default) or "2014"
MANIFEST_TTL_SECONDS # 3600 (default — 1 hour)
CACHE_DIR # ~/.cache/5eMCP (default)| Repo | Ruleset | Contents |
|---|---|---|
5etools-mirror-3/5etools-src |
2024 | Full mechanical data, fluff, books, adventures |
5etools-mirror-3/5etools-2014-src |
2014 | Full mechanical data, fluff, books, adventures |
TheGiddyLimit/homebrew |
Both | Community homebrew by content type |
This project uses Test-Driven Development (TDD) and mandatory reviewer agent approval before every commit of AI-generated code.
- Write tests BEFORE implementation. No implementation code without a failing test first.
- Tests live in
tests/(mirroringsrc/structure). - Test files are named
*.test.ts. - All tests must pass before committing.
Before ANY commit of AI-generated code:
npm run typecheck— zero type errorsnpm run lint— zero lint errorsnpm run build— compiles successfullynpm test— all tests pass- Spawn reviewer agent → get APPROVE
- Commit within 5 minutes of approval
USER_COMMIT=1 git commit -m "Your message"./.githooks/install.shAdd to ~/.claude.json (or project .claude.json):
{
"mcpServers": {
"5etools": {
"command": "node",
"args": ["/path/to/5eMCP/dist/index.js"],
"env": {
"GITHUB_TOKEN": "ghp_your_token_here",
"DEFAULT_RULESET": "2024"
}
}
}
}