Model Context Protocol server for FoundryVTT integration enabling AI assistants to interact with FoundryVTT instances for RPG campaign management, character handling, and game automation
Static source inference · medium confidence · detected: Logging
Deprecated protocol patterns detected
Summary
The server provides 33 tools with basic structure but significant gaps in quality. Most tools have short, generic descriptions (averaging ~40-60 chars) that lack context for LLM selection. Descriptions rarely explain WHEN to use a tool or its consequences. Parameter schemas are present but minimally described, many params lack context about valid ranges, formats, or dependencies. Error handling guidance is absent. Composition issues: duplicate/near-duplicate tools (e.g., get_recent_logs, search_logs, get_system_health, diagnose_errors, get_health_status all operate on diagnostics). No tool annotations (readOnlyHint, destructiveHint). Response schemas are not documented. The server mirrors a FoundryVTT API structure directly without abstracting for agent usability.
Tools (33)
apply_status_effectwriteauth50/100
Apply a status effect to a token (requires write enabled)
create_actor_itemwriteauth50/100
Create an item on an actor (requires write enabled)
create_journal_entrywriteauth50/100
Create a new journal entry (requires write enabled)
delete_actor_itemdestructiveauth50/100
Delete an item from an actor (requires write enabled)
diagnose_errorsread onlyauth50/100
Diagnose system errors
end_combatwriteauth50/100
End the current combat encounter (requires write enabled)
Pervasive lack of output schema documentation across all 33 tools. LLMs cannot plan downstream operations or extract required fields (IDs, references) without knowing the response structure.
Document output schema for EVERY tool. Return type should specify all fields (names, types, descriptions), nested objects, and array structures. Example: 'Returns {actor_id: string, name: string, type: string, hp: number, stats: {...}}'. Reference: pattern:tool-description.
Expand tool descriptions to 100-200 chars. Format as: 'WHAT it does. WHEN to use it. PREREQUISITE (if any). Example: get_actor_details: Get all attributes of an actor (HP, AC, inventory, status effects). Use after search_actors() to retrieve full details. Returns nested stats and items.'
Replace opaque 'object' parameters with explicit JSON Schema. For 'patch' in update_actor_attributes, define allowed keys (e.g., {"type": "object", "properties": {"name": {"type": "string"}, "data.attributes.hp.value": {"type": "number"}}, "additionalProperties": false}). Document required vs optional keys.
Add enums to string/choice parameters. E.g., apply_status_effect.statusId should be enum ['blinded', 'frightened', 'poisoned', ...]. lookup_rule.system should be enum ['dnd5e', 'pathfinder2e', ...]. search_logs.level should be enum ['error', 'warn', 'info', 'debug'].
Set min/max bounds for numeric parameters. get_chat_messages.limit: 1-100 (default 20). move_token.x, .y: 0-<grid_width>, 0-<grid_height>. generate_npc.level: 1-20. set_initiative: 0-30. Document in parameter description.
Consolidate duplicate tools. Merge get_recent_logs + search_logs into single search_logs with optional filters. Merge get_system_health + diagnose_errors + get_health_status into single get_system_health or status_report. Delete redundant variants.
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on Logging (deprecated) - log to stderr or use OpenTelemetry
Score history
Overall score trend
↑ 20 points across a rubric change (v1 → v2)
48/100
Scored
Grade
Overall
Spec posture
Rubric
2026-09-22
F
48
<=2025-11-25
v2
2026-03-09
F
28
-
v1
get_actor_detailsread onlyauth50/100
Get detailed information about a specific actor
get_chat_messagesread onlyauth50/100
Get recent chat messages
get_combat_stateread onlyauth50/100
Get the current combat state
get_health_statusread onlyauth50/100
Get overall health status of the FoundryVTT instance
get_journalread onlyauth50/100
Get a specific journal entry
get_recent_logsread onlyauth50/100
Get recent system logs
get_scene_inforead onlyauth50/100
Get information about a scene
get_system_healthread onlyauth50/100
Get system health status
get_usersread onlyauth50/100
Get list of users in the world
get_world_summaryread onlyauth50/100
Get a summary of the world
lookup_ruleread onlyauth50/100
Look up a game rule
move_tokenwriteauth50/100
Move a token on the scene (requires write enabled)
next_turnwriteauth50/100
Advance to the next turn in combat (requires write enabled)
refresh_world_dataread onlyauth50/100
Refresh cached world data
roll_diceread onlyauth50/100
Roll dice using FoundryVTT's dice rolling system
search_actorsread onlyauth50/100
Search for actors in FoundryVTT
search_compendiumread onlyauth50/100
Search for items in FoundryVTT compendiums
search_itemsread onlyauth50/100
Search for items in FoundryVTT
search_journalsread onlyauth50/100
Search for journal entries
search_logsread onlyauth50/100
Search system logs
search_worldread onlyauth50/100
Search the world for entities
set_initiativewriteauth50/100
Set initiative for a combatant (requires write enabled)
start_combatwriteauth50/100
Start a new combat encounter (requires write enabled)
update_actor_attributeswriteauth50/100
Update actor attributes (requires write enabled)
update_actor_itemwriteauth50/100
Update an item on an actor (requires write enabled)
Multiple description deductions: most descriptions are 30-70 chars (below 100-200 char baseline). Many lack WHEN-to-call context or state/action consequences. E.g., 'Search for actors' tells LLM nothing about query syntax, result count, or use cases.
No confirmation/dry-run for destructive operations (delete_actor_item, end_combat). Agents can irreversibly delete items or end combat without warning. Missing: confirm_before_execute pattern or dry-run support.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). LLMs cannot distinguish safe reads from destructive writes at a glance. Tools risking side effects should carry explicit hints.
No pagination for list/search results. 'limit' params present but no 'offset', 'cursor', or 'next_token' support. Large result sets blow context windows.
Vague optional parameter semantics: many params optional with 'default to current scene/combat' or similar behavior NOT explicitly documented. LLMs may pass wrong values or omit needed params.
Add confirmation/dry-run support for destructive operations. delete_actor_item and end_combat should accept optional 'confirm=true' or support a separate preview_delete_actor_item tool that returns what would be deleted. Reference: pattern:confirmation-request.
Add tool annotations. Register each tool with hints: delete_actor_item with {destructiveHint: true}, roll_dice with {readOnlyHint: true}, refresh_world_data with {idempotentHint: true}. This helps LLMs understand safety implications without parsing descriptions.
Add pagination support. search_* tools should return {results: [...], total_count: N, limit: 20, offset: 0, next_offset: 20}. Document limit default (20) and max (100). Reference: pattern:paginated-result.
Clarify optional parameter defaults explicitly. For get_scene_info with optional sceneId, document: 'If omitted, uses the currently active scene in FoundryVTT. Returns error if no scene is active.' For start_combat with optional tokenIds: 'If omitted, includes all tokens on the scene.'
Add parameter type/format guidance. E.g., 'query' in search_actors: 'Free-text search across actor names and aliases. Supports partial matches. Regex not supported. Example: "orc" matches "Orc Warrior" and "Little Orc Chief".' This prevents LLM attempts to pass regex or complex syntax.
Document response chaining: after search_actors returns actor_id, LLMs need actor_id to call get_actor_details, update_actor_attributes, etc. Ensure search results always include the ID used by downstream tools. Same for tokens, combats, scenes.
Implement rate limiting. Tools like roll_dice or search_world could be called in loops. Add guidance: 'This tool is rate-limited to 100 calls/minute. Requests exceeding this will return HTTP 429 Retry-After header.'
Add human-readable identifiers. Instead of requiring opaque actor IDs, accept actor names and resolve them inside the tool. E.g., move_token could accept actor_name in addition to tokenId: 'move_token(actor_name="Orc Warrior") resolves to the token on the current scene.' Reference: pattern:chat-data-model.