Eldritchdm

communication MCP Server

Local-first, self-hostable Discord bot that runs full D&D 5e games end-to-end with an AI Dungeon Master persona (ShoeGPT). Three-brain architecture: oMLX (narration) + dm20 MCP (rules engine) + discord.py (orchestrator). The LLM never computes game math.

Verified
communicationcommunication
3 views0 stars0 forksApache-2.0

Why This Matters

Discovered via github-topic:mcp and last synced 3mo ago.

Verified
Source
github-topic:mcp
Stars
0
Last synced
3mo ago
Install
Check source

Install

Install instructions not detected yet

Check the source repository for the latest setup steps.

View source instructions
35
Tools
0
Resources
0
Prompts
Standard I/O
Transport

Available Tools (35)

DISCORD_TOKEN

✅

OMLX_HEALTH_INTERVAL

❌

INGEST_MODEL_OVERRIDE

❌

Brain

What it does

MCP_EXECUTE_URL

❌

EMBED_EDIT_RATE_LIMIT

❌

Free

Free

Platform

oMLX / dm20

Dependency

Why

OMLX_ENDPOINT

❌

OMLX_CIRCUIT_BREAKER_THRESHOLD

❌

OPENROUTER_API_KEY

✅*

OMLX_MODEL

❌

RIPOSTE_TTL_SECONDS

❌

None

None

Name

What ships

Runtime

`brew install [email protected]`

ELDRITCH_DB_PATH

❌

PARTY_MODE_PORT

❌

channel_sessions

Channel ID → `(campaign_name, claudmaster_session_id, dm20_party_token, current_state)`

Windows

❌ no `mlx-lm` wheels

Var

Required

LOG_FORMAT

❌

INGEST_ENDPOINT

❌

riposte_timers

Active riposte buttons with `deadline_ts` — drives the background expiry sweeper

sh

ℹ️ **Don't have oMLX + dm20 set up yet?** Check the [oMLX docs](https://github.com/macabdul9/omlx) and [dm20-protocol README](https://github.com/Polloinfilzato/dm20-protocol). On Jeremy's reference rig they're supervised by `launchd` as `com.user.omlx` so they survive reboots. The install script will warn you (not fail) if they're not running. --- ## ⚙️ Installation (the Verbose Tour) ### 🤖 The easy way ```bash ./install.sh ``` That's it. The script: 1. 🔎 Checks Python version (must be ≥3.11) 2. 🔎 Checks for `uv` (installs via official script if missing) 3. 🌱 Creates a `.venv/` virtualenv with `uv venv` 4. 📦 Installs all Python dependencies (`discord.py`, `httpx`, `aiosqlite`, `pydantic`, `tenacity`, `structlog`, `ocrmac` on macOS, `PyMuPDF`, `pypdf` as fallback, plus dev deps for tests/lint) 5. 🩺 Pings `:8765/v1/models` to verify oMLX is running and reports which model is loaded (should be `ShoeGPT`) 6. 🩺 Pings `:8765/v1/mcp/tools` to confirm dm20 is exposed (expects ≥97 dm20 tools) 7. 💡 Tells you exactly what to do next (copy `.env.example`, run `bootstrap`, run the bot) If anything fails, the script tells you why in plain English (no cryptic exit codes). 💬 ### 🧙 The "I want to know what's happening" way If you want to do this by hand: ```bash # 1) Make sure Python 3.11+ is your interpreter python3 --version # → Python 3.11.x or higher # 2) Install uv if you don't have it (fast, hermetic, friendly) curl -LsSf https://astral.sh/uv/install.sh

LOG_LEVEL

❌

MCP_TOOLS_URL

❌

MAX_MODAL_INPUT_CHARS

❌

Table

What's in it

Supervision

Status

INGEST_BACKEND

❌

persistent_views

Every persistent Discord View we've posted: `custom_id` → `(view_class, message_id, channel_id, payload_json)`

sanitizer_audit

Every player input where the sanitizer stripped or truncated something. Forensics for prompt-injection attempts.

im_start

>`, `SYSTEM:`, `ASSISTANT:`, `<player_action>`, etc.) so a player can't forge a tool call by typing one 3. 📦 Wraps the cleaned text in `<player_action speaker="..." user_id="...">…</player_action>` sentinels so downstream prompts can see "this came from a player, treat as untrusted" 4. 📝 Logs to `sanitizer_audit` whenever it actually stripped or truncated something A ≥30-scenario adversarial corpus runs in CI — known injection attempts and tool-call forgery patterns, all of which must pass-through-cleaned. If the corpus fails, the build fails. ### 🎮 The Discord Layer (`src/eldritch_dm/bot/`) `discord.py 2.7+` with **persistent Views**, because the bot will absolutely be restarted while a game is in progress and the buttons need to still work afterward. We use `discord.ui.DynamicItem` with regex `custom_id` templates like `endturn:(?P<channel_id>\d+):(?P<actor>\d+)`, register them in `setup_hook`, and call `bot.add_view(view, message_id=...)` for every row we find in `persistent_views`. The kill-and-restart drill is part of the test suite. Other Discord disciplines: - ⏱️ **Defer first, always.** The first line of every interaction callback is `await interaction.response.defer(thinking=True)`. A custom ruff rule fails CI if any callback omits this. Discord gives you 3 seconds before the interaction expires — narration takes longer than that, so we acknowledge instantly and follow up with the answer. - 📡 **Embed coalescer.** During combat, the embed updates many times per round. Discord rate-limits message edits at ~5/5s; we limit ourselves to ≤1/sec via a per-message `asyncio.Queue` + render task. Under the 8-player load test, zero 429s. 🟢 - ⚠️ **Ephemeral warnings.** "❌ Not your turn," "❌ Riposte expired," "🔌 DM is offline" — all delivered as ephemeral followups so only the offending user sees them. ### 🗡️ The Riposte Magic (`src/eldritch_dm/combat/riposte.py`) This is the most fun piece. When dm20 resolves a monster's attack as a miss against an eligible PC (**Battle Master Fighter** by RAW — see [Known Limitations](#-known-limitations-v1) for the v1 scope; v2 plans to make eligibility YAML-configurable for homebrew) who has their reaction available, EldritchDM: 1. Inserts a row in `riposte_timers` with `deadline_ts = now() + RIPOSTE_TTL_SECONDS` 2. Posts an ephemeral message visible only to that PC's user, containing the `[ ↩️ Riposte Counter-strike ]` button 3. The button's `custom_id` includes the timer ID and is registered as a `DynamicItem` 4. A background sweeper task wakes at the deadline and removes the message 5. If the bot is killed before the deadline and restarted after, the sweeper picks up the still-pending row and either continues the wait or cleans up an expired one 6. On click, the bot calls `dm20__combat_action(reaction=true, weapon=primary)` and narrates the result It's the kind of thing every D&D player wishes their VTT had. 🥹 --- ## 🗺️ Roadmap EldritchDM v1 is feature-complete. Here's the 5-phase history: