FoundryMCP
A lightweight MCP (Model Context Protocol) server for FoundryVTT that communicates directly via WebSockets.
Why This Server?
Unlike other FoundryVTT MCP servers that require:
- Installing a custom module on your Foundry server
- Running a headless browser
This server natively authenticates with FoundryVTT and exchanges WebSocket messages directly using the same protocol as the official Foundry client. This makes it:
- Lightweight - No browser overhead, just direct WebSocket communication
- Zero server-side setup - No modules to install on your Foundry instance
- Secure - Uses the same authentication flow as the official client
Security Recommendation
Create a dedicated FoundryVTT user for each game world you want the MCP server to access. Grant that user only the permissions you want the MCP server to have. This provides:
- Fine-grained access control
- Clear audit trail of MCP actions
- Easy revocation if needed
- Isolation between different games/worlds
Installation
npm install
npm run build
Configuration
Credentials File
Create a file at config/foundry_credentials.json:
[
{
"_id": "my-campaign",
"hostname": "your-foundry-server.com",
"userid": "your-user-id",
"password": "your-password"
},
{
"_id": "test-world",
"hostname": "test.foundry-server.com",
"userid": "test-user-id",
"password": "test-password"
}
]
Fields:
_id- A user-defined identifier for this credential entry (used to switch between instances)hostname- The domain/IP of your FoundryVTT serveruserid- Your Foundry user document ID (find by inspecting Users in Foundry admin panel)password- Your Foundry user password
You can configure multiple Foundry instances and switch between them at runtime using the choose_foundry_instance tool.
Environment Variable
Override the default credentials path by setting:
export FOUNDRY_CREDENTIALS=/path/to/credentials.json
Usage with MCP Clients
Add to your MCP client configuration:
{
"mcpServers": {
"foundry": {
"command": "node",
"args": ["/path/to/FoundryMCP/build/server.js"]
}
}
}
Or if installed globally:
{
"mcpServers": {
"foundry": {
"command": "foundry-mcp"
}
}
}
Available Tools
Document Retrieval (List)
These tools retrieve all documents of a given type from the connected world.
| Tool | Description |
|---|---|
get_actors | Get all actors (characters, NPCs, etc.) |
get_items | Get all items |
get_folders | Get all folders |
get_users | Get all users |
get_scenes | Get all scenes |
get_journals | Get all journal entries |
get_macros | Get all macros |
get_cards | Get all cards |
get_playlists | Get all playlists |
get_tables | Get all roll tables |
get_combats | Get all combats |
get_messages | Get all chat messages |
get_settings | Get all settings |
Parameters:
max_length(integer, optional): Maximum response size in bytes. Documents are removed from the response until it fits within this limit.requested_fields(string[], optional): Specific fields to include. Always includes_idandname. If omitted, all fields are returned.where(object, optional): Filter documents by field values. See Filtering withwherebelow.
Document Retrieval (Single)
These tools retrieve a single document by ID or name.
| Tool | Description |
|---|---|
get_actor | Get a specific actor |
get_item | Get a specific item |
get_folder | Get a specific folder |
get_user | Get a specific user |
get_scene | Get a specific scene |
get_journal | Get a specific journal entry |
get_macro | Get a specific macro |
get_card | Get a specific card |
get_playlist | Get a specific playlist |
get_table | Get a specific roll table |
get_combat | Get a specific combat |
get_message | Get a specific chat message |
get_setting | Get a specific setting |
Parameters (at least one required):
id(string): Document ID_id(string): Document ID (alias)name(string): Document namerequested_fields(string[], optional): Specific fields to include.
World Metadata
get_world
Get world metadata from FoundryVTT (title, system, version, etc.), excluding document collections like actors or items. Use the get_* document tools for collection data.
Document Manipulation
modify_document
Modify an existing document in FoundryVTT.
Parameters:
type(string, required): Document type. Valid types:- Core:
Actor,Item,Scene,JournalEntry,Folder,User,Playlist,Macro,RollTable,Cards,ChatMessage - Scene objects:
Combat,Combatant,ActiveEffect,Drawing,MeasuredTemplate,Note,Tile,Token,Wall,AmbientLight,AmbientSound
- Core:
_id(string, required): The document's unique identifierupdates(object[], required): Array of update objects with fields to modify
Example - Update actor HP:
{
"type": "Actor",
"_id": "abc123",
"updates": [{ "system": { "attributes": { "hp": { "value": 25 } } } }]
}
create_document
Create new documents in FoundryVTT.
Parameters:
type(string, required): Document type to createdata(object[], required): Array of document data objects
Example - Create an item:
{
"type": "Item",
"data": [{ "name": "Healing Potion", "type": "consumable" }]
}
delete_document
Permanently delete documents from FoundryVTT. This cannot be undone.
Parameters:
type(string, required): Document type to deleteids(string[], required): Array of document_idvalues to delete
Example:
{
"type": "Item",
"ids": ["vlcf6AI5FaE9qjgJ", "abc123def456"]
}
Instance Management
show_credentials
Show all configured Foundry credentials without revealing passwords. Returns the _id, hostname, userid, item_order (zero-based index), and currently_active status for each credential entry.
Example response:
[
{
"_id": "my-campaign",
"hostname": "your-foundry-server.com",
"userid": "abc123",
"item_order": 0,
"currently_active": true
},
{
"_id": "test-world",
"hostname": "test.foundry-server.com",
"userid": "def456",
"item_order": 1,
"currently_active": false
}
]
choose_foundry_instance
Switch to a different Foundry instance. Disconnects from the current instance (if any) and connects to the specified one.
Parameters (at least one required):
item_order(integer): Zero-based index of the credential in the array_id(string): The user-defined identifier for the credential entry
Example - Switch by item_order:
{
"item_order": 1
}
Example - Switch by _id:
{
"_id": "test-world"
}
Tips
Understanding Document Structure
Document schemas vary significantly between game systems (D&D 5e, Pathfinder, etc.). Use the get_* tools to inspect existing documents before attempting to modify or create new ones.
Filtering with where
All collection retrieval tools (get_actors, get_items, etc.) support the where parameter for filtering results. The where parameter accepts an object with key-value pairs that documents must match.
How it works:
- Each key-value pair in
whereis a condition that must be satisfied - All conditions use AND logic - a document must match ALL conditions to be included
- Values are compared using strict equality
Example - Get actors in a specific folder:
{
"where": {
"folder": "abcd1234"
}
}
Example - Get NPC actors in a specific folder:
{
"where": {
"folder": "abcd1234",
"type": "npc"
}
}
This returns only actors where folder equals "abcd1234" AND type equals "npc".
Example - Get items of a specific type:
{
"where": {
"type": "weapon"
}
}
Example - Combine with other parameters:
{
"where": {
"folder": "abcd1234"
},
"requested_fields": ["name", "type", "system.quantity"],
"max_length": 5000
}
Common filter fields:
folder- Filter by folder IDtype- Filter by document subtype (e.g., "npc", "character" for actors; "weapon", "armor" for items)ownership- Filter by ownership settings- Any top-level field on the document can be used as a filter key
Response Size Management
When working with large worlds, use max_length and requested_fields to limit response sizes:
{
"max_length": 10000,
"requested_fields": ["name", "type", "system.attributes.hp"]
}
How It Works
- Authentication: The server authenticates with FoundryVTT using the same HTTP POST flow as the official client
- WebSocket Connection: Establishes a persistent WebSocket connection using Socket.IO protocol
- Message Exchange: Sends and receives JSON messages using Foundry's native protocol
- Automatic Reconnection: Handles connection drops and re-authenticates as needed
License
MIT