Grimoire

Grimoire Grimoire turns your TTRPG campaign into a structured, queryable database and knowledge graph and exposes it to any MCP-compatible AI client.

Community: Submitted by a user or imported; check the owner before granting accessOnlineNo sign-inGlobalFreeCan modify data

What it can do

  • Add Relationship: [DATABASE TOOL] Create a DATABASE relationship between two entities. Modifies actual FK fields on entity tables or creates rows in junction tables. ✅ AUTO-VISUALIZATION: DB relations
  • Add Thread Progression: Record a new progression point for a story thread at a specific session. Only available to GM-role connections. Creates a progression that tracks how a thread advanced, encount
  • Add To Entity Graph: [GRAPH VISUALIZATION TOOL] Control which entities appear in a graph (MEMBERSHIP only). This does NOT create relationships - it just adds an entity as a node in the graph. ⚠️ NOT F

What data it sees

Do you need an account

No: the server works without sign-in

Grimoire

Grimoire turns your TTRPG campaign into a structured, queryable database and knowledge graph and exposes it to any MCP-compatible AI client. Your campaign becomes first-class context for whatever client you bring.

What it does

This server connects an AI client to a live Grimoire campaign through 41 tools across six surfaces:

  • Entities — 14 typed schemas (NPCs, locations, factions, quests, items, creatures, lore, vehicles, and more) with full CRUD and batch creation
  • Knowledge graphs — Traverse and edit the relationship web: who allies with whom, which faction holds which ground, who knows what about whom
  • Wiki pages — Block-based rich content with embedded entries and hierarchical structure
  • Open threads — Track unresolved obligations, debts, and promises with session-anchored progressions
  • Campaign bible and constitution — Surface the immutable truths of your setting (gods, magic rules, history, canon) so the AI stops contradicting your world
  • Search and catalog — Full-text search across the campaign, plus discoverable field options and tag taxonomies for downstream tool calls

Who it's for

GMs and worldbuilders running multi-session campaigns who want their AI assistant to actually know their world, not invent generic fantasy that contradicts established canon. Works for any genre: Fantasy, Sci-Fi, Post-Apocalyptic, Horror, Modern/Urban, Superhero, or Historical, with stackable facets (Cyber, Mecha, Mystery, War, Survival) layered on top.

What you can ask your client

  • "Parse my session 12 notes into NPCs and link them to the right factions."

  • "How would Queen Mira react if her brother betrayed her?"

  • "Show every NPC connected to House Vale, sorted by faction loyalty."

  • "What does Queen Mira know about the missing prince?" (respects DM-only secrets)

  • "Add Eldric the innkeeper. Gambling debts to House Vale, met the party in session 4."

  • Visibility-aware. Three tiers (DM-only, player-knowledge, common-knowledge) wrap every read. DM secrets stay DM secrets even when players are the ones querying through their own client.

Setup

  1. Click connect — Smithery handles the OAuth flow with ttrpg.bot.
  2. Sign in to your Grimoire account and pick which campaign to grant access to.
  3. Start asking your client about your world.

A free tier covers one campaign with unlimited entities and the full MCP surface. Paid plans unlock unlimited campaigns, custom fields, and additional storage.

Links

Server tool list (49)

Raw names from tools/list. Only developers need these.

add_relationship[DATABASE TOOL] Create a DATABASE relationship between two entities. Modifies actual FK fields on entity tables or creates rows in junction tables. ✅ AUTO-VISUALIZATION: DB relationships automatically appear in get_knowledge_graph! - FK fields and junction tables are visualized as edges in political/timeline/geography graphs - NO need to also call add_to_entity_graph or create_entity_graph_edge for DB relationships - Those tools are ONLY for custom edges that don't exist in the database schema ⚠️ DON'T DUPLICATE: If you use add_relationship, the edge will show up in graphs automatically. AUTOMATICALLY ROUTES TO: 1. FK FIELD - If a direct field exists (faction_id, parent_location_id, etc.) 2. JUNCTION TABLE - If no FK exists but a junction table does FK FIELDS BY CATEGORY: - npcs: faction_id→factions, superior_npc_id→npcs, location_ids→locations[] - locations: parent_location_id→locations, connected_location_ids→locations[] - factions: leader_id→npcs, allied_faction_ids→factions[], rival_faction_ids→factions[] - quests: quest_giver_id→npcs, related_npc_ids→npcs[], related_location_ids→locations[] - items: owner_npc_id→npcs, owner_pc_id→player_characters, location_id→locations JUNCTION TABLES: Used when FK doesn't exist. relationship_type becomes edge label. EXAMPLE - Set NPC's primary faction (FK): {"source_category": "npcs", "source_entity_id": "...", "target_category": "factions", "target_entity_id": "...", "relationship_type": "primary_faction"} Returns: {type: "fk_field"|"junction", field/table, success}
add_thread_progressionRecord a new progression point for a story thread at a specific session. Only available to GM-role connections. Creates a progression that tracks how a thread advanced, encountered complications, or was resolved during a session. Progression types: - start: Thread begins (usually auto-created) - update: Thread advances or develops - complication: Thread encounters a setback or twist - resolution: Thread concludes Optionally link to a specific key event from the session by providing its stable ID (key_event_id) or legacy index (key_event_index, 0-based). Prefer key_event_id when available — it survives reordering of key events.
add_to_entity_graph[GRAPH VISUALIZATION TOOL] Control which entities appear in a graph (MEMBERSHIP only). This does NOT create relationships - it just adds an entity as a node in the graph. ⚠️ NOT FOR RELATIONSHIPS: - To connect entities, use add_relationship (DB relationships auto-visualize as edges) - This tool only controls which entities appear as NODES in a graph - DB relationships between members automatically show as edges USE CASES: - Add an NPC to the political graph so they appear in the visualization - Add a location to a custom graph for a specific adventure - Control which entities are visible in get_knowledge_graph results GRAPH SELECTION (provide ONE of these): - graph_id: UUID for custom entity graphs (use list_entity_graphs to find IDs) - graph_type: "political" for the political web graph WORKFLOW: 1. Use add_relationship to create the actual DB connection between entities 2. Use this tool ONLY if you want to add an entity to a graph for visibility SUPPORTED ENTITY TYPES: pc, npc, faction, location, item, creature, deity, quest, lore, session RETURNS: Success confirmation with entity details.
batch_create_entitiesCreate multiple entities at once (max 10 per call). All must be same category. CALL get_entity_schema(category) FIRST so each entity targets the category's real default fields. Default-field keys inside custom_fields land in native columns; relation arrays sync junction tables; unknown keys fail that entity with the list of valid fields. USE CASES: Populating factions with NPCs, creating related locations, bulk session prep. TAGS: Each entity can have tags. Use standard tags: political, personal, economic, religious, magical, historical, secret, prophetic, combat, social, environmental, technological. PARTIAL-SUCCESS SEMANTICS: Entities are inserted sequentially, NOT inside a single transaction. If entity #3 fails its INSERT, entities #1 and #2 are already committed and remain in the database. Validation errors before INSERT (e.g., missing name) also fail per-entity. Inspect the 'failed' array to see what didn't make it. To roll back partial creation, delete via delete_entity using the IDs from 'created'. RETURNS: {created: [...], failed: [...], total, success} - 'failed' is always present (as [] when everything succeeded) so callers don't need null-checks.
batch_create_wiki_blocksCreate multiple blocks on a wiki page in one call (max 50). Blocks are created in array order, each chained after the previous one, so the stored order matches your array - no verification or reorder pass is needed. IMPORTANT WORKFLOW FOR NESTED PAGES: Wiki pages can be infinitely nested. When building page hierarchies with content: 1. Create parent page with create_wiki_page (omit parent_id for root) 2. READ THE RETURNED page_id FROM THE RESPONSE 3. Create child pages with parent_id set to that ID 4. Use batch_create_wiki_blocks to add content to each page BLOCK CREATION ORDER: Blocks are created in array order. Each block is positioned after the previous one. The first block goes after any existing content (or at the start if page is empty). CONTENT FORMAT: Text is wrapped in a "content" array with text fragments. EXAMPLE - Creating a complete NPC wiki page: { "page_id": "npc-page-uuid", "blocks": [ {"type": "heading", "content": {"content": [{"text": "Theron Blackwood"}], "level": 1}}, {"type": "text", "content": {"content": [{"text": "A grizzled veteran of the Northern Wars..."}]}}, {"type": "heading", "content": {"content": [{"text": "Appearance"}], "level": 2}}, {"type": "bullet", "content": {"content": [{"text": "Tall and broad-shouldered"}]}}, {"type": "bullet", "content": {"content": [{"text": "Silver-streaked beard, weathered face"}]}}, {"type": "heading", "content": {"content": [{"text": "Personality"}], "level": 2}}, {"type": "text", "content": {"content": [{"text": "Stoic and reserved, but fiercely loyal."}]}}, {"type": "callout", "content": {"content": [{"text": "SECRET: Gambling debt to Thieves Guild"}], "type": "warning"}, "visibility": "dm-secret"}, {"type": "page", "content": {"pageId": "faction-uuid", "title": "The Iron Guard", "icon": "⚔️"}} ] } BLOCK TYPES: - text: {"content": [{"text": "paragraph"}]} - heading: {"content": [{"text": "title"}], "level": 1-6} - bullet: {"content": [{"text": "list item"}]} - numbered: {"content": [{"text": "numbered item"}]} - quote: {"content": [{"text": "quoted text"}]} - callout: {"content": [{"text": "message"}], "type": "info|warning|success|error"} - divider: {} - page: {"pageId": "uuid", "title": "name", "icon": "emoji"} - image: {"url": "https://...", "caption": "optional caption"} - table: {"markdown": "| a | b |\n| --- | --- |\n| 1 | 2 |"} or a canonical table doc (paragraph-only cells, no spans; not allowed on the Campaign Bible) VISIBILITY OPTIONS (per block): - inherit: Uses page's visibility (default) - common-knowledge: Visible to all - dm-secret: GM role only - player-knowledge: GM tracking level marking player-known content (players see it only once an allowed-players list exists, which no tool sets yet) - system: Rules and meta notes, visible to players like common-knowledge Returns: Array of created block IDs in order. Use these IDs for subsequent updates. Entity links: text may contain @[Label](entity://<category>/<uuid>) tokens; valid tokens become real entity mentions, and reads emit the same syntax. Page links: text may contain @[Title](page://<uuid>) tokens naming other wiki pages in this campaign (ids from get_wiki_tree); valid tokens become real page links, reads emit the same syntax, and a page-handle block reads as its page token.
batch_reorder_wiki_blocksReorder multiple blocks on a wiki page in one call. EFFICIENT REORDERING: Instead of calling move_wiki_block multiple times, pass the complete new order in one call. This is much more efficient for reorganizing page content. USAGE: 1. Get current block order from get_wiki_page 2. Reorder the block IDs as needed 3. Pass the complete new order EXAMPLE - Move block to top: Current order: [block-1, block-2, block-3, block-4] Move block-3 to top: [block-3, block-1, block-2, block-4] { "page_id": "page-uuid", "block_ids": ["block-3-uuid", "block-1-uuid", "block-2-uuid", "block-4-uuid"] } IMPORTANT: - All block_ids must belong to the specified page - The array must include ALL blocks on the page - Blocks not in the array will NOT be deleted, but their positions may become inconsistent Returns: Success confirmation with new block order.
create_entityCreate a new entity in any of the 14 campaign categories. CALL get_entity_schema(category) FIRST to see the exact default fields, their types, select options, and any campaign-defined custom fields. COMMON FIELDS (all categories, set at top level): - name (required): Entity name - description: Narrative description - status: active|draft|hidden|archived (default: active) - player_knowledge: common-knowledge|dm-secret|player-knowledge - tags: Array of tag strings - USE STANDARD TAGS: political, personal, economic, religious, magical, historical, secret, prophetic, combat, social, environmental, technological. Call get_tag_options first. - custom_fields: JSON object for the category's DEFAULT fields plus any campaign-defined custom fields DEFAULT FIELDS ARE REAL COLUMNS: keys you pass in custom_fields that match a category's default field (e.g. locations.location_type, locations.population, npcs.faction_id) are written to their native columns, not the generic custom_fields blob. Relation arrays (e.g. allied_faction_ids, related_npc_ids) take entity UUIDs and sync junction tables. Only keys that are neither default fields nor defined custom fields are rejected with the list of valid fields. CATEGORY-SPECIFIC DEFAULT FIELDS (examples; see get_entity_schema for the full list): - npcs: race, class [{name,level}], alignment, personality_traits, motivation, faction_id, location_ids | DM: dm_secrets - locations: location_type, parent_location_id, population, cultural_characteristics, notable_npc_ids | DM: dm_secrets - factions: faction_type, power_level, goals, leader_id, allied_faction_ids, rival_faction_ids | DM: dm_true_agenda - quests: status (not_started|in_progress|completed|failed), quest_giver_id, rewards, objectives | DM: dm_true_objective - items: item_type, rarity, properties, owner_npc_id, owner_pc_id | DM: dm_secret_properties - session_recaps: session_number, summary, key_events, pcs_present_ids | DM: dm_consequences - lore_entries: category, era_period, in_game_date_start, historical_accuracy | DM: dm_historical_impact CONTENT FIDELITY: - Use the user's EXACT WORDS for names, descriptions, and details - DO NOT fill in fields the user didn't specify - ASK before adding creative content the user didn't request - Only populate fields the user explicitly provides
create_entity_graph_edge[GRAPH VISUALIZATION TOOL] Create a CUSTOM edge that doesn't exist in the database schema. ⚠️ DON'T USE FOR DB RELATIONSHIPS: - If a relationship CAN be stored in the DB (faction_id, allied_faction_ids, etc.), use add_relationship - DB relationships automatically appear as edges in get_knowledge_graph - This tool is ONLY for narrative/thematic connections not in the DB schema USE CASES (edges that DON'T exist in DB): - "secretly_manipulating" between two NPCs (no DB field for this) - "foreshadows" between a lore entry and a quest - "thematically_mirrors" between two locations - Plot threads, callbacks, character arcs not captured by FK fields DON'T USE FOR: - NPC belongs to faction → use add_relationship (sets faction_id) - Location is child of location → use add_relationship (sets parent_location_id) - NPC is leader of faction → use add_relationship (sets leader_id) GRAPH SELECTION (provide ONE of these): - graph_id: UUID for custom entity graphs (use list_entity_graphs to find IDs) - graph_type: "political" for the political web graph EDGE CATEGORIES: - plot_thread: Narrative connections - callback: Story callbacks/references - character_arc: Character development links - thematic: Thematic/symbolic connections - custom: Any other non-DB relationship RETURNS: Created edge with ID and full details.
create_foundation_edgeConnect two Foundation Nodes with a labeled edge in the foundations graph. Both IDs must be foundation node UUIDs (create them first with create_foundation_node). Use a verb-like relationship_type, e.g. 'created', 'empowered', 'founded', 'is_building'.
create_foundation_nodeCreate a Foundation Node: a discrete, named world concept in the campaign's constitutional Foundations graph (Layer 1, always loaded). Foundation nodes are world-defining concepts (e.g. a cataclysm, a hidden power, a cosmological law), NOT database entities like NPCs or locations. Use create_entity for those. Group nodes with 'category' (the campaign's foundation sections, e.g. for post-apocalyptic: "The Collapse", "Technology & Salvage", "Hazards & Radiation", "Factions of the Wastes", "Fundamental Laws"). Set 'importance' 0-5 (5 = most defining). Use 'visibility' to hide GM secrets from players. Use 'ai_guidance' for instructions on how the AI should treat this concept.
create_open_threadCreate a new open thread (narrative obligation) for the campaign. Only available to GM-role connections. Creates a thread that tracks an unresolved narrative element that needs eventual resolution. Thread types: consequence, promise, mystery, foreshadowing, callback_opportunity Set is_major=true for story-critical threads that must eventually be addressed.
create_wiki_blockCreate a single content block within a wiki page. For multiple blocks prefer batch_create_wiki_blocks: it chains each block after the previous one deterministically, so stored order matches your array. Sequential single creates are ordered too; only CONCURRENT create calls can interleave. BLOCK TYPES AND CONTENT STRUCTURE: Text is wrapped in a "content" array with text fragments. 1. TEXT (paragraphs, prose) type: "text" content: {"content": [{"text": "Your paragraph content here."}]} 2. HEADING (section headers, levels 1-6) type: "heading" content: {"content": [{"text": "Section Title"}], "level": 2} 3. BULLET (unordered list item) type: "bullet" content: {"content": [{"text": "List item text"}]} Note: Create multiple bullet blocks for a list 4. NUMBERED (ordered list item) type: "numbered" content: {"content": [{"text": "Numbered item text"}]} 5. QUOTE (block quotation) type: "quote" content: {"content": [{"text": "Quoted text or dialogue"}]} 6. CALLOUT (highlighted information box) type: "callout" content: {"content": [{"text": "Important message"}], "type": "info"} Types: info (blue), warning (yellow), success (green), error (red) 7. DIVIDER (horizontal separator) type: "divider" content: {} 8. PAGE (link to another wiki page) type: "page" content: {"pageId": "uuid", "title": "Page Name", "icon": "📜"} 9. IMAGE type: "image" content: {"url": "https://...", "caption": "Optional caption"} 10. TABLE (simple grid: header row + body rows) type: "table" content: {"markdown": "| Name | Role |\n| --- | --- |\n| Varka | Chief |"} Or pass a canonical TipTap table doc directly. Cells are paragraph-only (no colspan/rowspan, no nested blocks); entity and page tokens work inside cells. Reads render the grid back as markdown in "text". Not allowed on the Campaign Bible. POSITIONING: - Use after_block_id to insert after a specific block - Omit after_block_id to append to end of page VISIBILITY: - inherit: Uses page's visibility (default) - common-knowledge: Visible to all - dm-secret: GM only (great for secret notes) - player-knowledge: GM tracking level marking player-known content; players see it only once an allowed-players list exists, which no tool sets yet - bookkeeping, not sharing EXAMPLE - Adding a DM secret note: { "page_id": "npc-page-uuid", "type": "callout", "content": {"content": [{"text": "This NPC is secretly the villain's spy"}], "type": "warning"}, "visibility": "dm-secret" } Entity links: text may contain @[Label](entity://<category>/<uuid>) tokens; valid tokens become real entity mentions, and reads emit the same syntax. Page links: text may contain @[Title](page://<uuid>) tokens naming other wiki pages in this campaign (ids from get_wiki_tree); valid tokens become real page links, reads emit the same syntax, and a page-handle block reads as its page token.
create_wiki_pageCreate a new wiki page in the campaign. IMPORTANT WORKFLOW FOR NESTED PAGES: Wiki pages support infinite nesting. To create a hierarchy: 1. Create parent page FIRST (omit parent_id for root level) 2. Read the returned page_id from the response 3. Create child pages using that ID as parent_id 4. Add content blocks to each page EXAMPLE - Creating a location hierarchy: Step 1: Create continent page {"title": "Eldoria", "icon": "🌍"} Returns: {"id": "continent-uuid", ...} Step 2: Create region as child {"title": "The Northern Reaches", "parent_id": "continent-uuid", "icon": "⛰️"} Returns: {"id": "region-uuid", ...} Step 3: Create city as grandchild {"title": "Frostholm", "parent_id": "region-uuid", "icon": "🏰"} VISIBILITY INHERITANCE: - inherit: Uses the linking page block's visibility, else the parent page's (default for child pages; not allowed on a root page) - common-knowledge: Visible to all - dm-secret: Only GM role can see - player-knowledge: a GM TRACKING level marking what players know (vs secrets) for your own bookkeeping. Actual player admission additionally requires an allowed-players list, which no MCP or UI control sets yet - so treat it as labeling, not sharing - system: Rules and meta notes, visible to players like common-knowledge Pages are created in the campaign wiki space; party and player spaces are not writable over MCP. SLUG GENERATION: The slug is auto-generated from the title (e.g., "The Northern Reaches" → "the-northern-reaches"). Slugs are unique within each parent context. IMPORTANT - CREATE NAVIGATION LINKS: After creating a new page, create a "page" block on the parent page (or home page) to make navigation intuitive. While pages appear in the sidebar, clickable page cards in the wiki content provide better user experience. RECOMMENDED WORKFLOW: 1. Create the new page with create_wiki_page 2. Add content blocks to the new page with batch_create_wiki_blocks 3. Create a "page" block on the parent/home page: {"type": "page", "content": {"pageId": "new-page-uuid", "title": "Page Title", "icon": "📜"}} Inline alternative: write @[Page Title](page://new-page-uuid) inside any text block's text to link the page mid-sentence. Returns: Created page with ID, slug, depth, and breadcrumb.
current_campaignReturns the campaign, user, and role bound to the current MCP session.
delete_entityPermanently delete an entity. Cannot be undone. Cascades to remove all junction table relationships.
delete_foundation_edgeDelete a single edge from the foundations graph by its edge ID (the edgeId returned by create_foundation_edge). Use this to remove a duplicate or incorrect connection without deleting the nodes themselves.
delete_foundation_nodeDelete a Foundation Node and any foundation-graph edges referencing it.
delete_relationship[DATABASE TOOL] Remove a DATABASE relationship between two entities. Clears actual FK fields or deletes junction table rows. ⚠️ NOT for visualization graphs - this modifies real database data. AUTOMATICALLY ROUTES TO: 1. FK FIELD - Clears single FK or removes from array field 2. JUNCTION TABLE - Deletes row from junction table REQUIRED: source_entity_id + target_entity_id + both categories + relationship_type The relationship_type determines which FK field or junction table to target. EXAMPLE - Remove NPC from faction (FK): {"source_category": "npcs", "source_entity_id": "...", "target_category": "factions", "target_entity_id": "...", "relationship_type": "primary_faction"} EXAMPLE - Remove junction relationship: {"source_category": "npcs", "source_entity_id": "...", "target_category": "factions", "target_entity_id": "...", "relationship_type": "member"}
delete_wiki_blockDelete a wiki block from a page. PERMANENT: block deletion is a HARD delete with no undo (only PAGES go to the wiki trash). Other blocks on the page automatically reposition. PAGE-HANDLE CASCADE: deleting a "page" block also moves its linked page and that page's sub-pages to the wiki trash, exactly like deleting the page card in the UI - the response message says when this happened. The Campaign Bible's title block cannot be deleted. USE CASES: - Removing outdated information - Cleaning up content before reorganizing - Deleting placeholder content RETURNS: { "success": true, "message": "Block deleted successfully", "blockId": "deleted-block-uuid" } TIP: To replace a block with different content of the same type, use update_wiki_block instead. To change a block's type, delete and recreate it - but never as a way to edit a "page" handle (see the cascade above).
get_campaign_bibleGet the Campaign Bible with all its content blocks. The Campaign Bible is part of Layer 1 (Constitutional) - the immutable facts about the campaign world. It contains core narrative guidelines, creative boundaries, and story rules. RETURNS: - id: The Bible page UUID - title: Page title (e.g., "Campaign Name Bible") - blocks: Array of content blocks (heading, text, etc.) - tokenEstimate: Estimated tokens for AI context Each block contains: id, type, content, position, visibility. The first block is always the title heading and cannot be modified. CONTENT SHAPES (important if you plan to round-trip blocks): Block content can be returned in two formats depending on how it was written: - Simple: {"content": [{"text": "..."}]} — written by MCP create paths. - Full TipTap doc: {"type":"doc","content":[{"type":"heading","attrs":{...}, "content":[{"type":"text","text":"..."}]}]} — written by the frontend collaborative editor for the Bible page. If you read a block and want to update or rewrite it, do NOT manually reformat — pass the simple shape to update_campaign_bible (it normalizes on write) and let the server handle conversion. USE CASES: - Read the Campaign Bible to understand narrative guidelines - Get block IDs for updating specific sections - Check current content before making updates NOTE: get_constitution also includes a summary of the Campaign Bible content. Use this tool for full block-level details.
get_campaign_contextGet this campaign's genre, ruleset, and setting context. Call this early. Tells you what kind of story this is (fantasy, sci-fi, horror, post-apocalyptic, ...), what game system the GM runs, which entity categories exist and what they are called in this campaign, which categories are not used here, and the setting's technology and magic levels. Use it to speak the campaign's vocabulary and respect its ruleset.
get_constitutionGet the complete campaign constitution and overview. This is Layer 1 - call this FIRST. RETURNS: Campaign Summary, Campaign Bible (text summary), Foundation Nodes === TIERED WORKFLOW === Layer 1 - Constitution (THIS TOOL): World truths, theme, tone Layer 2 - Discovery (get_entity_catalog): Names + IDs only Layer 3 - Session Context (get_knowledge_graph attention=true): GM-curated entities Layer 4 - Full Graphs (get_knowledge_graph attention=false): ALL entities Layer 5 - Deep Dive (get_entity): Full details for specific entities === TOOL CATEGORIES === DATABASE TOOLS: add_relationship, get_relationships, delete_relationship GRAPH VISUALIZATION TOOLS: add_to_entity_graph, create_entity_graph_edge ENTITY CRUD: create_entity, update_entity, get_entity, list_entities CAMPAIGN BIBLE: get_campaign_bible (full blocks), update_campaign_bible NEXT STEPS: Use get_entity_catalog (Layer 2) then get_knowledge_graph with attention=true (Layer 3). For detailed Campaign Bible editing, use get_campaign_bible.
get_entityRetrieve full details for a specific entity. This is Layer 5 (On-Demand). USE THIS AFTER discovering entities via get_entity_catalog, search_campaign, or following relationship references. RETURNS: Core fields (id, name, description, status, tags), customFields, categoryData, timestamps. VISIBILITY: Player tokens cannot access dm-secret entities.
get_entity_catalogComplete catalog of ALL active entities. Layer 2 discovery. RETURNS two views of the same data: - catalog.byType: { npcs:[{id,name}], locations:[...], factions:[...], quests:[...], items:[...], lore_entries:[...], creatures:[...], player_characters:[...], world_rules:[...], planar_forces:[...], custom_mechanics:[...], session_preps:[...], vehicles:[...], session_recaps:[{id,name,sessionNumber}] }. Every type is always present (empty array if the campaign has none of that type). - catalog.graphs: { political, geography, timeline, foundations } - compact nodes+edges per projection. Use get_knowledge_graph for full graphs with details. Also returns catalog.typeCounts (per-type totals) and catalog.totalEntities. WHEN TO USE: At session start, before creating entities to avoid duplicates. TOKEN EFFICIENT: id + name only. Use get_entity / list_entities for full details.
get_entity_graphGet a specific user-created entity graph projection by ID. RETURNS: Full graph projection with nodes (entities) and edges (relationships/custom connections). Each node includes: id, name, type, description, and custom fields. Each edge includes: source, target, relationship type, and whether it's a custom edge. ATTENTION FILTER: Set attention=true to only get entities marked for AI context (useful for focused analysis). USE WITH: list_entity_graphs to find graph IDs first.
get_entity_schemaDescribe the writable shape of a category before creating or updating entities. CALL THIS FIRST when creating or updating an entity so you target real DEFAULT FIELDS instead of dumping everything into custom_fields. RETURNS: - globalFields: name, description, status, player_knowledge, tags (set at the top level of create_entity/update_entity) - defaultFields: the category's native fields (key, type, isRelation, isDMOnly, selectFieldName). Pass these inside custom_fields; they are written to real columns. - selectOptions: for select-type default fields, the SUGGESTED option values (same source as get_field_options). These are hints, not a closed enum — select-type default fields also accept brand-new free-text values (the new value becomes a campaign option). Don't avoid a value just because it isn't listed. - customFields: this campaign's GM-defined custom fields (key, type, required). Only these extra keys are accepted in custom_fields beyond the default fields. IMPORTANT: Any key in custom_fields that is neither a default field nor a defined custom field is rejected. Relation fields (isRelation=true) take arrays of entity UUIDs and sync junction tables.
get_field_optionsGet available options for customizable select fields. Use before creating/updating entities to see valid values for fields like race, class, creature_type, item_type, rarity, faction_type, location_type, etc. RETURNS: Array of {value, label, is_default} for each option.
get_knowledge_graphGet a knowledge graph projection with full entity details. Supports full graphs (Layer 4) and attention-filtered session context (Layer 3). ✅ DB RELATIONSHIPS AUTO-VISUALIZE: FK fields and junction tables appear as edges automatically. No need to manually add edges after using add_relationship. ATTENTION FILTER (Layer 3): Set attention=true for GM-curated session-relevant entities. GRAPH TYPES: - 'political': Factions, NPCs, alliances, memberships - 'timeline': Sessions, events, chronological flow - 'geography': Locations, spatial hierarchy RETURNS: Nodes (entity data) + Edges (DB relationships automatically included).
get_narrative_stateGet the current narrative state of the campaign (Tier 1.5). This is the temporal context layer - use it after get_constitution to understand "where we are in the story". Returns a comprehensive snapshot including: - Recent sessions (last 3) with summaries and key events - Open threads grouped by major (story-critical) and minor (callback opportunities) - Canonical facts (immutable historical events marked across all sessions) - Active campaign arcs - Recent session observations Recommended AI workflow: 1. get_constitution → World truths 2. get_narrative_state → Story progression (THIS TOOL) 3. get_entity_catalog → What exists 4. get_knowledge_graph → Current session context
get_open_threadsGet unresolved narrative threads for the campaign. Open threads represent narrative obligations: unresolved consequences, promises, mysteries, foreshadowing, and callback opportunities. Use this to understand what story elements need attention. Returns threads grouped by major (story-critical) and minor (nice-to-resolve). Thread types: - consequence: Action that will have repercussions - promise: Commitment made to NPC/faction - mystery: Unanswered question - foreshadowing: Setup for future payoff - callback_opportunity: Minor thread worth revisiting Use this tool after get_constitution to understand "where we are in the story".
get_relationships[DATABASE TOOL] Get all DATABASE relationships for an entity: junction tables AND FK fields. Returns actual data connections, not custom graph visualization edges. JUNCTION RELATIONSHIPS: Rich metadata (role, rank, loyalty) in dedicated tables. FK RELATIONSHIPS: Direct field references on entity tables. OUTGOING FKs (from entity): faction_id, parent_location_id, leader_npc_id, giver_npc_id, owner_id, etc. INCOMING FKs (to entity): Other entities referencing this one via their FK fields. FILTERING: - target_category: Only show relationships to specific category - direction: "outgoing", "incoming", or "both" (default) RETURNS: { entityId, category, junctionRelationships: [ { kind: "junction", id, junctionTable, sourceEntityId, sourceCategory, targetEntityId, targetCategory, relationshipType, metadata, createdAt } ], fkRelationships: { outgoing: [ { kind: "fk", fkField: "table.column", sourceEntityId, ... } ], incoming: [ { kind: "fk", fkField: "table.column", sourceEntityId, ... } ] }, totalJunction, totalFKOutgoing, totalFKIncoming } NOTES: - Each row carries a 'kind' discriminator: "junction" or "fk". - Junction rows have a stable id + createdAt; FK rows do not (they're derived from an FK column on an entity row), so id/createdAt are omitted on FK rows. - 'junctionTable' is only set on junction rows; 'fkField' is only set on FK rows and contains the "table.column" path (e.g. "npcs.faction_id").
get_tag_optionsGet available tags for entities in this campaign. IMPORTANT: Always call this BEFORE creating or updating entities to use consistent tags. Returns standard_tags (core tags) and custom_tags (already used in campaign). BEST PRACTICE: Prefer standard_tags for consistency. RETURNS: {standard_tags: [{value, label, color}], custom_tags: [string], all_tags: [string]}
get_thread_progressionsGet the progression history of a specific story thread. Shows how a thread evolved across sessions, from creation through updates, complications, and (optionally) resolution. Each progression includes the session context and any linked key events. Use this to understand the narrative arc of a specific thread.
get_wiki_pageRetrieve a wiki page by ID with its content blocks. SCOPE: the campaign wiki space only. Party and player spaces are not reachable over MCP; their page ids answer "page not found". RETURNS: id, title, slug, icon, depth, visibility, blocks[], breadcrumb[], children[], tokenEstimate. Blocks contain: type, content, text, position, visibility. "text" is the block as flat prose. To EDIT a block, wrap new prose back into the content object update_wiki_block documents (update takes a content OBJECT, not this string). A table block's text is a markdown grid (| cell | cell |); a page-handle block's text is its page token. Use include_blocks=false for metadata only. VISIBILITY: player tokens see a page only when its EFFECTIVE visibility admits them: dm-secret is dropped, player-knowledge admits only listed players, and inherit resolves through the page's handle block first, then the parent chain. Denied and unknown pages both answer "page not found". Entity links: text may contain @[Label](entity://<category>/<uuid>) tokens; valid tokens become real entity mentions, and reads emit the same syntax. Page links: text may contain @[Title](page://<uuid>) tokens naming pages in the campaign wiki space (ids from get_wiki_tree); valid tokens become real page links, reads emit the same syntax, and a page-handle block reads as its page token.
get_wiki_treeRetrieve the hierarchical page tree of the CAMPAIGN wiki space. Use to understand wiki structure, find content locations, identify parent pages for nesting. SCOPE: the campaign space only - the party wiki and player notebooks are not listed and are not reachable over MCP. (get_campaign_context's wikiPageCount spans every space, so it can read higher than this tree's totalPages.) RETURNS: pages[] (nested tree), totalPages, tokenEstimate. Each node: id, title, slug, icon, depth, visibility, hasChildren, children[]. Use max_depth to limit traversal (default: 10, max: 20). VISIBILITY: player tokens see only pages whose EFFECTIVE visibility admits them (dm-secret dropped, player-knowledge only when listed, inherit resolved handle-first then up the parent chain).
list_entitiesList all entities in a specific category with pagination. RETURNS: entities array with id, name, description (truncated), status, tags; totalCount for pagination. STATUS FILTERING: active (default), draft, hidden, archived PAGINATION: Use offset + limit to page through results.
list_entity_graphsList all user-created entity graphs for this campaign. Entity graphs are custom relationship visualizations that can include any combination of entity types. Unlike the built-in graphs (political/timeline/geography), you can create multiple entity graphs with different entity type selections. RETURNS: Array of entity graphs with id, name, description, entityTypes, isActive, membershipMode. USE CASE: Before adding entities or edges to a graph, first list available graphs to find the right one.
move_wiki_blockMove a block to a new position within the same page or to a different page. SAME-PAGE REORDERING: Move a block to a different position on its current page. - Omit target_page_id - Set after_block_id to position after a specific block - Omit after_block_id to move to end of page EXAMPLE - Move to after another block: { "block_id": "block-to-move-uuid", "after_block_id": "target-position-uuid" } CROSS-PAGE MOVE: Move a block to a completely different wiki page. - Set target_page_id to the destination page - Optionally set after_block_id for position on new page EXAMPLE - Move to different page: { "block_id": "block-to-move-uuid", "target_page_id": "destination-page-uuid" } NOTE: Cross-page moves create a new block on the target page and delete the original. The returned block ID will be different from the original. NOTE: Page-handle blocks (type "page") cannot move cross-page (the handle governs its page's visibility). Blocks only move between pages of the campaign wiki space, and table blocks cannot move onto the Campaign Bible.
resolve_open_threadMark an open thread as resolved. Only available to GM-role connections. Links the resolution to the session where it was addressed.
search_campaignSearch across all campaign entities using full-text search. SEARCH TIPS: - Use specific names: a character or place's exact name finds that entity directly - Use keywords: a recurring concept finds every entity that mentions it - Searches name, description, and custom_fields content CATEGORY FILTERING: Narrow search to specific categories for faster results. RETURNS: Array of results with: id, category, name, description (truncated), status, tags, relevance score VISIBILITY: Player tokens do not see dm-secret entities.
search_wikiFull-text search across the campaign wiki's page titles and block content. Complements search_campaign, which searches ENTITIES only and never touches wiki rows. RETURNS: results[] of {pageId, pageTitle, blockId?, snippet, rank}, ordered by relevance. blockId is set when the match is inside a specific block; absent when the page TITLE matched. Follow up with get_wiki_page for full content. SCOPE: the campaign wiki space only. Player tokens see only pages and blocks their effective visibility admits.
toggle_graph_attentionToggle attention status for an entity in a graph, elevating it from Layer 4 (full graph) to Layer 3 (AI context) or vice versa. LAYER ARCHITECTURE: - Layer 3: Attention-filtered context (entities marked with attention=true) - Layer 4: Full graph (all entities regardless of attention) This tool allows AI to mark entities as important for session context, making them appear in Layer 3 filtered views. GRAPH SELECTION (provide ONE of these): - graph_id: UUID for custom entity graphs - graph_type: Built-in graph type: 'political', 'timeline', 'geography' USE CASES: - Mark NPCs as relevant for upcoming session prep - Highlight locations the party is traveling to - Flag factions involved in current plot threads - Elevate sessions containing important callbacks WORKFLOW: 1. get_knowledge_graph with attention=false (Layer 4) - See all entities 2. Identify entities that should be in session context 3. toggle_graph_attention with attention=true - Elevate to Layer 3 4. get_knowledge_graph with attention=true (Layer 3) - Verify filtered view RETURNS: Updated entity with new attention status.
unresolve_open_threadReopen a previously resolved thread. Only available to GM-role connections. Clears the resolution, returning the thread to an open/unresolved state.
update_campaign_bibleReplace the Campaign Bible content with new blocks. IMPORTANT: This replaces ALL content blocks EXCEPT the title heading. The title block (first block) is protected and will be preserved. WORKFLOW: 1. Call get_campaign_bible_wiki to see current content 2. Call this tool with the new blocks array 3. The title heading stays, all other blocks are replaced BLOCK FORMAT: Same format as batch_create_wiki_blocks: { "blocks": [ {"type": "heading", "content": {"content": [{"text": "Section Title"}], "level": 2}}, {"type": "text", "content": {"content": [{"text": "Paragraph content..."}]}}, {"type": "bullet", "content": {"content": [{"text": "List item"}]}}, {"type": "callout", "content": {"content": [{"text": "Important note"}], "type": "info"}} ] } BLOCK TYPES: - text: {"content": [{"text": "paragraph"}]} - heading: {"content": [{"text": "title"}], "level": 1-6} - bullet: {"content": [{"text": "list item"}]} - numbered: {"content": [{"text": "numbered item"}]} - quote: {"content": [{"text": "quoted text"}]} - callout: {"content": [{"text": "message"}], "type": "info|warning|success|error"} - divider: {} NOTE: Do NOT include the title heading in your blocks array - it will be preserved automatically. NOTE: allowed types here: text, heading, bullet, numbered, quote, callout, divider, image. "page" handles and "table" blocks are refused (tables cannot round-trip through the Bible). NOTE: replacement is create-then-delete: if creating the new blocks fails, the previous Bible content is left untouched. Returns: The updated Campaign Bible page with all blocks. Entity links: text may contain @[Label](entity://<category>/<uuid>) tokens; valid tokens become real entity mentions, and reads emit the same syntax. Page links: text may contain @[Title](page://<uuid>) tokens naming other wiki pages in this campaign (ids from get_wiki_tree); valid tokens become real page links, reads emit the same syntax, and a page-handle block reads as its page token.
update_entityUpdate an existing entity's fields. CALL get_entity_schema(category) to see the writable default fields for the category. PARTIAL UPDATES: Only provide fields you want to change. Default-field keys inside custom_fields are written to their native columns (e.g. location_type, population, faction_id). Relation arrays (e.g. allied_faction_ids) replace the entity's junction-table links for that relation. CUSTOM_FIELDS BEHAVIOR (three rules, one object — see get_entity_schema for which key is which): - DEFAULT fields write to native columns and are partial: omit a key to leave it unchanged. Passing null on a default field is REJECTED (it does not clear the column); set a new value to change it. - TRUE CUSTOM fields (campaign-defined) are MERGED into the existing blob, so a partial update keeps unrelated custom fields. Pass null on a custom key to delete just that key. - RELATION arrays REPLACE that relation's junction links; pass [] to clear them. Unknown keys are rejected with the list of valid fields. TAGS: Use standard tags (political, personal, combat, social, etc.) - call get_tag_options to see available options. RETURNS: Updated entity with all current fields.
update_foundation_nodeUpdate a Foundation Node. Only the fields you provide are changed; omit a field to leave it untouched.
update_open_threadUpdate an existing open thread's details. Only available to GM-role connections. Provide only the fields you want to change. At least one field must be provided. Thread types: consequence, promise, mystery, foreshadowing, callback_opportunity
update_wiki_blockUpdate an existing wiki block's content or visibility. PARTIAL UPDATES: You only need to provide fields you want to change. - To update text: {"content": {"content": [{"text": "new text"}]}} - To change visibility: {"visibility": "dm-secret"} - Both at once: {"content": {...}, "visibility": "..."} CONTENT STRUCTURE BY TYPE: - text/bullet/numbered/quote: {"content": [{"text": "new content"}]} - heading: {"content": [{"text": "New Title"}], "level": 2} - callout: {"content": [{"text": "message"}], "type": "warning"} - image: {"url": "...", "caption": "..."} - table: {"markdown": "| a | b |\n| --- | --- |\n| 1 | 2 |"} or a canonical table doc; the write replaces the WHOLE table and is validated (paragraph-only cells, no spans) TABLE CAUTION: a user clicking into a table in an open browser tab re-saves their copy about two seconds later, so an MCP table edit made while that table is on someone's screen can be overwritten (last writer wins). Prefer table edits between sessions. EXAMPLE - Making a block secret: { "block_id": "block-uuid", "visibility": "dm-secret" } NOTE: Block type cannot be changed. Delete and recreate if type change needed. NOTE: Page-handle blocks (type "page") accept only visibility here; their content is refused. Entity links: text may contain @[Label](entity://<category>/<uuid>) tokens; valid tokens become real entity mentions, and reads emit the same syntax. Page links: text may contain @[Title](page://<uuid>) tokens naming other wiki pages in this campaign (ids from get_wiki_tree); valid tokens become real page links, reads emit the same syntax, and a page-handle block reads as its page token.
update_world_foundationsSet the structured World Foundations document (Layer 1, always loaded): the mechanical and cosmological truths of the world. Only the sections you provide are changed; omit a section to leave it untouched. This is the structured counterpart to the prose Campaign Bible.