Foundry REST API MCP
Foundry REST API MCP
An MCP server that lets MCP clients work with a Foundry VTT world through the FoundryVTT REST API Relay. It is the client-facing component of the ThreeHats ecosystem:
Foundry VTT + REST API Module <-- WebSocket --> REST API Relay <-- HTTPS --> this MCP serverThe MCP server connects to the relay's HTTP(S) API. Do not use the module's ws:// or wss:// relay URL for FOUNDRY_REST_API_BASE_URL.
Ecosystem and compatibility
Component | Role |
Connects a Foundry world to the relay over WebSocket. | |
Exposes the authenticated HTTP API used by this server. | |
Foundry REST API MCP | Exposes supported relay operations as typed |
Use the upstream relay documentation for module pairing, relay deployment, API-key management, and the complete REST API reference.
This project supports the relay's optional clientId and userId request scoping. A scoped API key can bind either value so the MCP client does not need to provide it. A key scoped to one world therefore does not require FOUNDRY_CLIENT_ID.
Quick start
Install and pair the Foundry module with either the public relay or your self-hosted relay.
Create an API key in the relay with only the scopes needed for the tools you intend to use.
Add this server to Codex in
~/.codex/config.toml:
[mcp_servers.foundry]
command = "npx"
args = [
"--yes",
"github:zagushka/foundry-rest-api-mcp#v0.5.0"
]
[mcp_servers.foundry.env]
# Public relay:
FOUNDRY_REST_API_BASE_URL = "https://foundryrestapi.com"
FOUNDRY_REST_API_KEY = "replace-with-a-scoped-secret"
# Optional: omit when the key is already scoped to exactly one world.
# FOUNDRY_CLIENT_ID = "fvtt_..."Restart Codex after changing the configuration. Codex starts this stdio server automatically; it does not expose its own HTTP port.
Self-hosted relay
Use the HTTP API address of your relay instead of its WebSocket address. The standard local relay API listens on port 3011:
[mcp_servers.foundry.env]
FOUNDRY_REST_API_BASE_URL = "http://localhost:3011"
FOUNDRY_REST_API_KEY = "replace-with-a-scoped-secret"
# FOUNDRY_CLIENT_ID = "fvtt_..."If Codex should inherit variables already available in its environment, use env_vars instead:
[mcp_servers.foundry]
command = "npx"
args = [
"--yes",
"github:zagushka/foundry-rest-api-mcp#v0.5.0"
]
env_vars = [
"FOUNDRY_REST_API_BASE_URL",
"FOUNDRY_REST_API_KEY",
"FOUNDRY_CLIENT_ID"
]The Git tag pins the installed release. Change it deliberately when upgrading.
Supported tools and permissions
All exposed tools begin with foundry_ and publish typed MCP parameters. Request the smallest set of relay scopes needed for the tools you enable:
Tool group | Capabilities | Relay scopes |
World content and folders | Inspect connected worlds; inspect, search, create, update, and delete entities and folders |
|
Users | List users, create an isolated bot/service user |
|
Actor inventory and effects | Add, update, and delete embedded |
|
Files | Browse file sources, download files, and upload base64-encoded files |
|
Scenes and canvas | Manage scenes, canvas documents, token movement, selection, and distance measurement |
|
Encounters and effects | Read and manage combats, combatants, turns, and active effects |
|
Table play | Roll dice and read, send, or delete chat messages |
|
Read-only tools advertise readOnlyHint: true. Tools that change world state advertise readOnlyHint: false; deletion tools and chat clearing also advertise destructiveHint: true. Treat a key that grants write scopes as a privileged credential and keep it outside Git.
Actor embedded documents
Use foundry_create_actor_embedded_documents, foundry_update_actor_embedded_documents, and foundry_delete_actor_embedded_documents to manage one actor's embedded Item or ActiveEffect documents. Pass the actor UUID (for example, Actor.abc123) and an array of document data or IDs. Updates require each document's _id or id.
The relay exposes no dedicated Actor.createEmbeddedDocuments route. For items, the create tool uses its supported actor items upsert; for effects, it uses the relay's effect endpoint. Updating and deleting target the embedded document UUIDs directly.
External bot users and private replies
Use foundry_list_users to find the Foundry user ID for FOUNDRY_BOT_USER_ID; the relay resolves clientId automatically when the API key is locked to one world. foundry_create_user is available only to a GM key with user:write; it accepts no password and returns only a safe subset of user fields.
Use foundry_get_current_client (or foundry_list_clients for more than one connected world) to diagnose the resolved clientId, world ID/title, Foundry version, and connection status without setting FOUNDRY_CLIENT_ID manually.
For every bot reply use foundry_send_chat_as_user, not the generic chat tool. It sends the requested userId to the relay and rejects a response whose ChatMessage.author.id differs. The relay is the authorization boundary: a scoped API key forcibly replaces userId, so callers cannot impersonate another user; an unscoped GM key may choose an author.
For a private reply, pass chatType: 3 and whisper: [originatingPlayerUserId]. The optional live test verifies the complete flow, including invisibility to an unrelated player:
FOUNDRY_REST_API_BASE_URL=https://relay.example \
FOUNDRY_BOT_API_KEY=... FOUNDRY_PLAYER_API_KEY=... FOUNDRY_OTHER_PLAYER_API_KEY=... \
FOUNDRY_BOT_USER_ID=... FOUNDRY_PLAYER_USER_ID=... \
npm run test:private-bot-replyIt intentionally creates two Whisper messages and does not remove them. Use test-world scoped keys with chat:write for the bot/player and chat:read for the unrelated-player visibility check.
The server deliberately does not expose D&D5e-specific operations, sessions, macros, playlists, arbitrary JavaScript, relay authentication management, or SSE/WebSocket subscriptions. Use the upstream API directly when one of those capabilities is required.
Local development
git clone https://github.com/zagushka/foundry-rest-api-mcp.git
cd foundry-rest-api-mcp
npm ci
npm testFor a manual local run, copy .env.example to .env, fill in the relay address and API key, then run:
npm run build
npm run start:envLicense
MIT © Peter Pshenichny
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/zagushka/foundry-rest-api-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server