foundry-rest-api-mcp-server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@foundry-rest-api-mcp-server create a goblin boss creature"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
foundry-rest-api-mcp-server
An MCP (Model Context Protocol) server that wraps the ThreeHats Foundry VTT REST API relay, so an LLM agent (Claude Code / Claude Desktop) can author and manage Foundry VTT content — primarily creating D&D 5e creatures — through native MCP tools instead of raw HTTP calls.
Status: V1 implemented. The stdio MCP server lives under
src/with unit tests undertest/. See Install & configure below to run it. The original plan that drove the build is inIMPLEMENTATION_PLAN.md.
What this is
The relay (github.com/ThreeHats/foundryvtt-rest-api-relay, public host https://foundryrestapi.com) bridges a running Foundry world to a REST API over a WebSocket. A Foundry-side module connects out to the relay; external clients then call REST endpoints, authenticating with an x-api-key header and targeting a world via a clientId query param.
This MCP server is a thin, typed client of that relay. It does not talk to Foundry directly and requires no Foundry-side code of its own (the relay's module handles that). That is the key differentiator from existing Foundry MCP servers, which all ship a custom Foundry module + socket (see IMPLEMENTATION_PLAN.md § Prior Art).
Related MCP server: mcp-llm
v1 scope (locked)
v1 implements the relay's document-authoring surface — these five scopes only:
Scope | Endpoints | Capability |
|
| Discover connected worlds → pick |
|
| Find actors/items/etc. by name (world + compendiums) |
|
| Read any document (by UUID or current selection) |
|
| Create / update / delete documents; tweak actor inventory & attributes |
|
| Organize content into folders |
This delivers the headline use case end-to-end: build a dnd5e NPC/monster (abilities, HP, AC, CR, traits, embedded attacks) as a real Foundry actor, search/read existing creatures to clone-and-tweak, and file everything into folders.
Everything else in the relay (dice rolls, chat, encounters/combat, scenes, canvas/tokens, effects, files, users, macro execution, streaming events) is out of v1 scope and documented as clearly-marked Future Phases — each unlocks by adding one scope and one tool module.
Optional companion: adding
structure:read(GET /structure,GET /get-folder) would let us find existing folders, not just create them. Cheap and read-only; deferred for now.
Architecture decisions (the short list)
Language/runtime: TypeScript, Node ≥ 18 (target Node 20 LTS), ESM-only.
SDK:
@modelcontextprotocol/sdk@^1.29(the shipped 1.x line). The renamed V2 SDK (@modelcontextprotocol/server) is not stable until ~mid-2026; migration later is mechanical. Build on 1.x now.Transport: stdio.
HTTP: native
fetch(no axios).Validation:
zod(peer of the SDK).Build/package:
tsup→ singlenpx-runnable bin.Config: env vars —
FOUNDRY_API_KEY(thex-api-key),FOUNDRY_RELAY_URL(defaulthttps://foundryrestapi.com),FOUNDRY_CLIENT_ID(optional; auto-resolves if one world is online),FOUNDRY_USER_ID(optional; omit = GM-level).Tool surface: small set of mostly single-purpose tools (~9 in v1), façades only where operations are homogeneous. Per-endpoint-explosion is explicitly avoided — LLM tool-selection reliability degrades past ~30–40 tools and every tool is permanent context cost.
Install & configure
Build from source
npm install
npm run build # → dist/index.js (executable, #!/usr/bin/env node)
npm test # unit tests (mocked fetch)
npm run inspect # launch the MCP Inspector against dist/index.jsEnvironment variables
Var | Required | Default | Purpose |
| yes | — | Sent as the |
| no |
| Relay base URL. Set to |
| no | auto-resolves | Which connected world to target. Auto-resolves when exactly one world is online. |
| no | GM-level | Scope actions to a Foundry user's permissions. Omit for GM access. |
On startup the server logs the online world(s) to stderr and disables foundry_create_creature if the active world's system isn't dnd5e.
Tools (v1)
foundry_list_worlds · foundry_search · foundry_get_entity · foundry_create_entity · foundry_update_entity · foundry_delete_entity · foundry_modify_actor · foundry_create_creature · foundry_manage_folder
Claude Code (.mcp.json)
Add to .mcp.json in your project root (or via claude mcp add):
{
"mcpServers": {
"foundry": {
"command": "node",
"args": ["/absolute/path/to/foundry-rest-api-mcp-server/dist/index.js"],
"env": {
"FOUNDRY_API_KEY": "your-scoped-key",
"FOUNDRY_CLIENT_ID": "fvtt_8bfa06d76c0c1ac5"
}
}
}
}Claude Desktop (claude_desktop_config.json)
~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"foundry": {
"command": "node",
"args": ["/absolute/path/to/foundry-rest-api-mcp-server/dist/index.js"],
"env": {
"FOUNDRY_API_KEY": "your-scoped-key",
"FOUNDRY_CLIENT_ID": "fvtt_8bfa06d76c0c1ac5"
}
}
}
}Once published to npm, replace
"command": "node", "args": ["…/dist/index.js"]with"command": "npx", "args": ["-y", "foundry-rest-api-mcp-server"].
Live smoke test (optional)
A gated end-to-end test creates then deletes a throwaway JournalEntry against the real relay:
FOUNDRY_LIVE_TEST=1 FOUNDRY_API_KEY=... FOUNDRY_CLIENT_ID=... npm testHow to use this repo (for the implementing agent)
Read
IMPLEMENTATION_PLAN.mdtop to bottom. Work the phases in order; each step lists its goal, the files it touches, the exact work, and an acceptance check.Read
EXECUTION_STRATEGY.mdfor how to run the build — recommended model/effort per ticket, the sequential-foundation → parallel-fan-out → sequential-convergence order, and the branch-per-work-stream (trunk-based) strategy with worktrees + CI gates.Use
API_SPEC.mdas the authoritative endpoint reference (request/response shapes, scopes, quirks, the dnd5e NPC schema notes).Pull granular, ordered tasks from the V1 project board / issues (milestone
V1 — Content Authoring). Each issue carries goal, endpoint+scope, file paths, acceptance criteria, andDepends on #N.The
reference/folder holds the relay's own docs/examples, mirrored verbatim from the upstream MIT-licensed repo for offline ground-truth (attribution inreference/SOURCE.md; regenerate withscripts/fetch-reference.sh). Filenames mirror their repo paths (e.g.docs_md_api_entity.md,docs_examples_dnd5e-examples.json).
Decision records & specs
decisions/— architecture & management decisions as ADRs, numberedNNNN-*.md. Each captures one decision (status · context · decision · consequences) and is immutable once Accepted; a later ADR supersedes an earlier one by reference, so history is never edited in place. Index + convention:decisions/README.md.specs/— technical component specs, numberedNNNN-*.md— the internal contracts the code implements (relay client, tool surface, dnd5e NPC builder). Index:specs/README.md.
The top-level docs (IMPLEMENTATION_PLAN.md, EXECUTION_STRATEGY.md, API_SPEC.md) are the elaborated references; the ADRs are the atomic, supersede-able record of why.
Getting a properly-scoped API key (do this before any write works)
A read-only key returns 403 API key lacks required scope: entity:write. You cannot add scopes to an existing key value — mint a new one that includes all five v1 scopes:
Dashboard: log in at
https://foundryrestapi.com→ API Keys → Create Scoped Key → tickclients:read,search,entity:read,entity:write,structure:write→ copy the key (shown once).Programmatic (device flow):
POST /auth/key-requestwith{"appName":"foundry-mcp","scopes":["clients:read","search","entity:read","entity:write","structure:write"]}→ open the returnedapprovalUrl→ pollGET /auth/key-request/:code/statusuntilapproved(the response then includesapiKey).
The known target world for this project is "Wilds Beyond the Witchlight", clientId fvtt_8bfa06d76c0c1ac5 (dnd5e 5.2.2, Foundry v13.351).
Available Tools
9 toolsfoundry_create_creatureCreate dnd5e NPCA
Build a dnd5e 5th-edition NPC actor from a friendly schema and create it in Foundry. Returns the new actor UUID and document. Only available when the connected world is dnd5e. ⚠️ Attack schema targets dnd5e v5.2.2 activities model — verify against a live NPC if attacks look wrong.
Inputs: ac (required), cr (required), hp (required), name (required), +13 more.
foundry_create_entityCreate Foundry EntityA
Create a new Foundry entity (Actor, Item, JournalEntry, etc.) with a raw Foundry document. Returns the new entity UUID and document.
Inputs: data (required), entityType (required), folder, keepId, +3 more.
foundry_delete_entityDelete Foundry EntityADestructive
Permanently delete a Foundry entity by UUID or current selection. This action is irreversible.
Inputs: uuid, userId, clientId, selected.
foundry_get_entityGet Foundry EntityARead-only
Retrieve a Foundry entity by UUID, or the currently selected token/actor. Returns the full document including system data and embedded items.
Inputs: uuid, actor, userId, clientId, +1 more.
foundry_list_worldsList Foundry WorldsARead-only
List all Foundry VTT worlds/clients connected to the relay, including their online status, system, and version info.
Inputs: no named parameters.
foundry_manage_folderManage Foundry FolderADestructive
Create or delete a Foundry folder. After creating a folder, pass the returned uuid as the folder argument when creating entities. Limitation: finding existing folders requires structure:read (not in v1 scope) — only freshly-created folder UUIDs are known.
Inputs: action (required), name, userId, clientId, +4 more.
foundry_modify_actorModify Foundry ActorA
Give/remove items, increase/decrease numeric attributes, or kill (set HP to 0) an actor. Use action to select the operation.
Inputs: action (required), uuid, amount, toUuid, +9 more.
foundry_searchSearch Foundry EntitiesARead-only
Search for Foundry entities by name. Returns UUID, documentType, subType, and package. This is the primary way to turn a name into a UUID for use with other tools. Use filter to narrow results, e.g. "Actor" or "documentType:Item,subType:weapon".
Inputs: query (required), limit, filter, userId, +3 more.
foundry_update_entityUpdate Foundry EntityAIdempotent
Update an existing Foundry entity by UUID or current selection. Pass only the fields to change.
Inputs: data (required), uuid, actor, userId, +2 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 9 tools
Most tools have distinct purposes (search vs get vs delete vs create), but there is some overlap between generic update_entity and specialized modify_actor, and between create_entity and create_creature. Descriptions help clarify boundaries, though agents might occasionally misselect.
Tool names follow a consistent 'foundry_' prefix with snake_case, and most use verb_noun patterns (list_worlds, create_entity, update_entity). Minor deviations: 'foundry_search' lacks a noun, and 'foundry_manage_folder' uses the vaguer verb 'manage' instead of create/delete.
Nine tools is well-scoped for a Foundry REST API server, covering core entity operations, world listing, search, and specialized dnd5e helpers without unnecessary bloat.
The set provides full CRUD for entities, search, and world listing, plus useful specialized tools for actor modification and creature creation. Minor gaps exist like no generic list_entities operation, but agents can work around these.
Maintenance
Related MCP Connectors
MCP server for OpenAI API (chat completions, image generation, embeddings) via AceDataCloud
An MCP server that provides an API to LLMs to manage their JumpCloud resources.
MCP server for Argo RPG Platform — connects AI assistants to campaign data via OAuth2
MCP server for AI dialogue using various LLM models via AceDataCloud
Related MCP Servers
- MIT
- AlicenseBqualityDmaintenanceAn MCP server that provides LLMs access to other LLMs449 npm82MIT
- AlicenseNot gradedqualityBmaintenanceA Model Context Protocol server that integrates with FoundryVTT, allowing AI assistants to interact with tabletop gaming sessions through natural language to query actors, roll dice, generate content, and manage game worlds.33 npm35MIT
- FlicenseAqualityDmaintenanceMCP server for managing Foundry VTT journal content (entries, categories, pages) and listing actors, enabling AI-assisted world-building via natural language commands.11-