Featured

Deploy OpenClaw in 60 seconds — 20% off logoDeploy OpenClaw in 60 seconds — 20% off

Launch OpenClaw on Hostinger in about 60 seconds and keep your agent live 24/7. Our referral link gives you 20% off, no coupon code needed.

Launch on Hostinger
Run your Hermes agent on Hostinger, fully managed logoRun your Hermes agent on Hostinger, fully managed

Launch Hermes on Hostinger in one click, fully managed, no VPS knowledge needed. Use code ZACAARON10 for 10% off.

Launch on Hostinger
Crawl and scrape any site into clean data, 10% off logoCrawl and scrape any site into clean data, 10% off

Firecrawl crawls and scrapes any site into clean markdown for your agent. Get 1,000 free credits, and new users get 10% off their first purchase.

Try Firecrawl free
6,000+ web scrapers for your AI agent, start free logo6,000+ web scrapers for your AI agent, start free

Apify gives your agent live web data: 6,000+ prebuilt scrapers and actors, MCP-ready. Sign up free with $5 in usage credits.

Try Apify free
One API to scrape, enrich, and extract the internet. logoOne API to scrape, enrich, and extract the internet.

Context.dev gives your agents a single API to scrape, enrich, and extract live web data — no proxies, no parsers, no maintenance.

Start building free
SetupClaw: done-for-you OpenClaw for founders & exec teams logoSetupClaw: done-for-you OpenClaw for founders & exec teams

White-glove OpenClaw for founders and exec teams (4–50+ employees): we install, harden, integrate your tools, and maintain it — secured from day one.

Get it set up for you
SEO data APIs for your agent, $1 free credit logoSEO data APIs for your agent, $1 free credit

DataForSEO gives your agent live access to SERP results, keyword data, backlinks, and on-page SEO data through one API. New accounts get a $1 credit, good for up to 20,000 keyword or backlink lookups.

Try DataForSEO free
Reach 48,000+ AI builders

A flat monthly placement in front of developers actively installing AI tools. No lock-in, cancel anytime.

Advertise here

Works with

Claude CodeClaude DesktopCursorVS CodeClineCodex CLIOpenClaw+ any MCP client

Install to Claude Code

This server doesn't publish a one-line install command. Follow the setup in the source repository.

Summary

Enables AI assistants to read and edit live D&D 5e Foundry VTT worlds and manage Molten-hosted server lifecycle via the Model Context Protocol.

README.md

fvtt-mcp-molten5e

A D&D 5e–only, Molten Hosting–optimized Model Context Protocol server for Foundry VTT, driven by Claude Code. It lets an AI GM assistant read and edit a live Foundry world (actors, items, journals, scenes, compendia, roll tables, cards…) and manage a Molten-hosted server's static files.

Paired with its bundled skills, it goes well beyond CRUD: it can author a complete, table-ready adventure end to end — scene, monsters, NPCs, a pregen PC or party, treasure, linked journals, and roll tables — scaled to however much the DM provides. Hand it only a map image and Claude reads the map and builds the whole module; hand it your own finished module and it faithfully recreates every stat block, item, and handout in the VTT.

Two importers worth calling out:

  • D&D Beyond → a real PC. Point it at a player's publicly shared D&D Beyond sheet and it builds

a fully leveled Foundry character — class/subclass/species/background, ability scores, the level-1 choices, spells, and starting equipment — canonicalized to the premium 2024 books.

  • Adventure map packs → your world. Import a battlemap module (a distributed Foundry scene-pack

with its own compendiums) faithfully: every scene with its walls, lights, day/night mood, and navigation thumbnails, plus the journal of map keys — with all assets re-pointed into your world, and cross-version (older and newer Foundry formats) handled. Tom Cartos packs are the first supported format; more to come.

---

📐 Design north star — design.md. The mission, scope, the skills decide, tools do contract, and the NPC authoring doctrine all live there; it's the document every skill, tool, and refactor traces back to. 🚧 Still under construction — actively evolving alongside the project, so expect it (and the tool surface) to change.

Why this shape

Managed Foundry hosts (like Molten) don't expose a general control API and you can't run a process next to the game server. The only supported way in is Foundry's own authenticated client.

So the MCP server drives a headless Chromium client (via Playwright): it wakes the (sleeping) Molten box with the Magic URL, joins the world as a dedicated Foundry user, waits for game.ready, and injects a page-side library that exposes the world's own client APIs. Claude Code talks to the MCP server over stdio; the server turns each tool call into a call inside that live page.

Claude Code  ──stdio──>  MCP server  (dist/index.js, on your PC)
                              │  Playwright → headless Chromium (src/foundry.ts)
                              ▼
                    Headless Foundry client
                    (wakes the box, joins the live world as a dedicated GM user)
                              │  the world's own client APIs (window.__fvtt)
                              ▼
                    Foundry VTT world (Molten-hosted)

The headless client connects lazily: tools/list answers without touching Foundry, and the first actual tool call is what wakes the box and joins the world. The whole tool tree depends on one seam — foundry.call(name, args) — and only src/foundry.ts ever imports Playwright.

Two-plane model

  • Plane A — the live bridge. World documents (actors, items, journals, scenes, compendia, roll

tables, cards, ownership). Goes through the headless Foundry client while the server is awake — the only safe way to read/write live world data.

  • Plane B — Molten files. Talks to Molten's own file endpoints directly (no bridge):

upload/serve static assets over WebDAV and map Data/-relative paths to public URLs.

Safety rule baked in: a running world's database (LevelDB stores under Data/worlds/<world>/data/) must never be written over the file channel — that corrupts it. Plane-B file ops are restricted to static assets and refuse world-DB paths; bulk DB edits are an offline-only flow (stop → Create Backup → fvtt unpack → edit → fvtt pack → start, via foundryvtt-cli). The Molten management panel is never scripted (their ToU forbids it); only the Magic-URL wake, WebDAV, and the Foundry server are automated.

Scope

In scope: actors — both NPCs and full leveled PCs (including import from a publicly shared D&D Beyond character) — items, journals, scenes (the scene document _and_ its placeables — walls, lights, tokens, regions/teleporters, ambient sounds, tiles, drawings, map notes), playlists, roll tables, cards, macros, combat-tracker config, compendium manipulation — especially pulling content out ("make an actor from the MM owlbear") — and asset upload. With the bundled skills these compose into end-to-end adventures — from reading a provided map image to drive a scene and everything in it, to importing a distributed battlemap module (e.g. Tom Cartos scene-packs) faithfully into your world. Authoring prefers the 2024 dnd5e data model, sourced from PHB / DMG / MM; if the requested content isn't in those packs the tool says so rather than inventing it.

Out of scope (for now): non-5e game systems; live session assistance — monitoring a running game and interjecting during play (live chat, running the monsters' combat turns) is the next phase (see design.md §8), not built yet; AI map-image generation (Claude reads a provided map, it does not draw one); scripting the Molten management panel. (Scene placeables — walls, lights, tokens, regions — _are_ authored and edited as scene contents; what's out of scope is driving them live on the canvas during a running session.)

---

Repository layout

src/
  index.ts          MCP server entry (stdio) — serves the registry's tools over JSON-RPC
  registry.ts       single source of truth: tool name → handler (advertised list derived from it)
  foundry.ts        THE Playwright seam: launch headless Chromium → wake → join → inject → call()
  config.ts         env/config loader (reads .env from the repo root)
  tools/            MCP tool classes — Plane A world tools + molten/ (Plane B WebDAV file tools)
  page/             page-side domain library, bundled into dist/page.bundle.js and injected
scripts/            dev/maintenance scripts (verify-*.mjs live acceptance, spike-headless)
tests/              gated live integration suites (offline unit tests live beside the code in src/**)

Requirements

  • Node.js 22+ (developed/tested on Node 24; see .nvmrc; CI runs 22 + 24). On Windows, if Node

isn't on PATH, use the full path to node.exe (see wiring below).

  • A Chromium for Playwrightnpx playwright install chromium (Playwright is a devDependency;

the headless bridge drives this browser).

  • Foundry VTT 14.x with the D&D 5e system, hosted on Molten, plus a dedicated

passwordless Foundry user for the MCP to join as.

Build

npm install
npx playwright install chromium   # one-time: the headless browser the bridge drives
npm run build                     # tsc → dist/, then esbuild bundles the in-page library

npm run build runs tsc && node esbuild.page.mjs: TypeScript compiles src/ to dist/, then esbuild bundles the page-side library (src/page/) into dist/page.bundle.js for injection. Tests: npm test (offline unit suite on vitest). Live integration suites are gated — see vitest.integration.config.ts and npm run test:integration.

Dev watch: npm run dev rebuilds the page bundle once, then runs tsc --watch for src/. Because the page library is a separate esbuild artifact, editing anything under src/page/ while developing needs npm run dev:page (esbuild --watch) alongside it — otherwise the running server keeps injecting the stale dist/page.bundle.js.

Wire into Claude Code

Register the built MCP server in your Claude Code config. Copy .mcp.json.example to a .mcp.json Claude Code reads (project-scoped, or your ~/.claude.json mcpServers) and set absolute paths:

{
  "mcpServers": {
    "foundry-molten5e": {
      "command": "C:/Program Files/nodejs/node.exe",
      "args": ["C:/path/to/fvtt-mcp-molten5e/dist/index.js"]
    }
  }
}
  • Use an absolute path to the root dist/index.js (Claude Code may launch the server from any

directory).

  • On Windows, point command at the full node.exe path if Node isn't on PATH.
  • The server loads its .env from the repo root regardless of working directory.
  • The headless client connects lazily — the first tool call wakes the Molten box and joins the

world, so the initial call after a cold box can take a while.

Configuration

Copy .env.example to .env (gitignored) and fill in your instance:

  • Non-secret, per-instance: MOLTEN_SERVER_URL, MOLTEN_WORLD_ID, MOLTEN_WEBDAV_URL,

MOLTEN_FILEBROWSER_URL, FOUNDRY_USER (the dedicated passwordless user to join as; defaults to MCP-Claude). The committed defaults are neutral your-server/your-world placeholders.

  • Wake (optional but recommended): MOLTEN_MAGIC_URL — Molten's "Server Startup / Magic URL"

(…?s=token), GET to wake a sleeping box before joining.

  • Secrets (never commit — env only): MOLTEN_WEBDAV_PASSWORD (upload-asset / asset file ops),

MOLTEN_ADMIN_KEY. Read them from your Molten panel → Server Details. Each tool reports which variable to set if its secret is missing.

Tools

138 tools total: 128 over the headless bridge (Plane A) + 10 Molten WebDAV file tools (Plane B).

Plane A (bridge) covers world introspection and editing — actors, items, compendium search, journals & quests, scenes and their placeables (walls, lights, tokens, regions/teleporters, ambient sounds, tiles, drawings, notes), roll tables, cards, playlists, ownership, folders/organization, macros, combat-tracker config, and 5e-specific helpers (NPC creation, PC building & leveling, D&D Beyond import, feature/spell granting, structured inventory/loot authoring), plus the asset-composition + reference-integrity tools. Plane B (Molten WebDAV) is the asset file library.

Plane B — Molten file tools (WebDAV):

| Tool | What it does | | --------------------- | -------------------------------------------------------------------------------- | | list-assets | List a directory under Data/ (folders + files, with size/type/public URL) | | asset-info | Existence + size/type/mtime/public URL for one path under Data/ | | download-asset | Download a file from under Data/ to a local path | | upload-asset | Upload a local file under Data/ (auto-creates parents; refuses world-DB paths) | | upload-asset-tree | Recursively upload a local directory tree under Data/ (preserves layout) | | create-asset-folder | Create a folder (and missing parents) under Data/ (idempotent) | | delete-asset | Delete a file (reference-aware; refuses if still used unless force) | | move-asset | Move/rename a file (refuses or relinks references; relink/force) | | copy-asset | Copy a file under Data/ | | asset-url | Map a Data/-relative path to its public HTTPS URL (pure, no network) |

Plane A — asset composition + reference integrity (bridge):

| Tool | What it does | | ----------------------- | ---------------------------------------------------------------------------- | | find-asset-references | Find every scene/actor/journal/playlist/… that references an asset path | | relink-asset | Rewrite all references from one asset path to another (dryRun supported) | | create-playlist | Create a Playlist from sound paths (the flagship "upload → playlist" wiring) | | create-scene | Create a Scene from a background image path | | update-scene | Update a scene's fields, including swapping its background image | | set-actor-art | Set an actor's portrait (+ prototype token) from an image path | | add-journal-image | Append an image page to a journal entry |

The remaining Plane A tools cover world CRUD (create-actor-from-compendium/author-npc, add-feature (features / compendium features / spells), import-item (copy a real PHB/DMG item — art + stats — onto an actor or the sidebar), add-item (author structured weapons/armor/consumables/loot/containers), create-item, create-journal/create-quest-journal, create-rolltable, create-cards, …), listing/search (list-actors, search-compendium, list-journals, …), and organization (create-folder, move-documents, bulk-delete). See the handlers map in src/registry.ts for the full dispatch table.

Plane B file ops run over WebDAV (need MOLTEN_WEBDAV_PASSWORD, work whenever the VM is awake). Plane A tools run over the headless bridge (need the world joined). Write tools refuse live world-DB paths; destructive file ops consult find-asset-references first.

Security

  • Outbound-only, nothing public. The server and the headless browser run on your machine and make

only outbound connections (to Foundry on Molten, and to Anthropic); nothing listens for inbound traffic, and the headless client authenticates to Foundry exactly as a normal user would.

  • Secrets stay in .env (gitignored), with tight file perms — never commit MOLTEN_WEBDAV_PASSWORD,

MOLTEN_ADMIN_KEY, or your Claude token. Errors name the missing variable, never its value.

  • Treat all agent inputs as untrusted (chat, transcripts, web) — prompt-injection can ride in.

Plane-A writes are inherently safe because they go through Foundry's own client APIs; Plane-B destructive file ops are reference-aware, refuse live world-DB paths (canonicalized, ..-rejecting), and deletes resolve strictly (exact id/name, no fuzzy match).

  • Anything under Data/ is served publicly over HTTPS with no auth — don't upload anything

sensitive.

Contributing

The project is one package: a Node-side MCP server (src/) that drives a headless Foundry page through the foundry.call(name, args) seam, plus a page-side library (src/page/**, bundled into dist/page.bundle.js and injected as window.__fvtt). Adding a tool touches both halves:

  1. MCP tool class (src/tools/<category>.ts) — declare the input contract once as a hoisted

zod schema; getToolDefinitions() returns { name, description, inputSchema: toInputSchema(schema) } (the advertised JSON Schema is generated from that zod via src/utils/schema.ts — never hand-written), plus a handleX(args) that schema.parsees and calls foundry.call('<op>', data).

  1. Register it (src/registry.ts) — instantiate the class, add its getToolDefinitions() to the

collected definitions, and add a '<tool-name>': args => tool.handleX(args) entry to the handlers map. The advertised tool list is derived from handlers, so a handler with no matching definition fails loudly at startup (src/tools/registry.test.ts guards the surface).

  1. Page-side op (src/page/<domain>.ts) — implement <op>(args) and register it in

src/page/index.ts. This runs inside the live Foundry page (the actual Document.create / update / delete): import only browser + Foundry globals here, never Node/Playwright.

  1. Build + verifynpm run build, then npm test, npm run typecheck, npm run knip, and

biome (npm run check). For live changes, npm run test:integration against a real world.

---

Support

Issues: GitHub Issues

Acknowledgments

Used as a reference: adambdooley/foundry-vtt-mcp by Adam Dooley.

License

MIT License — see LICENSE for details.

See related servers & alternatives →

Related MCP servers

Browse all →

Related guides

Hand-picked reading to help you choose and use AI & ML servers.