{"serverInfo":{"name":"Archivist AI","version":"3.0.0"},"authentication":{"required":true,"schemes":["oauth2"]},"tools":[{"name":"list-campaigns-tool","title":"List Campaigns Tool","description":"List your MyArchivist campaigns. Returns a paginated list of campaigns.","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]}},"type":"object"},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of campaigns records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-campaign-tool","title":"Get Campaign Tool","description":"Get a specific MyArchivist campaign by its ID.","inputSchema":{"properties":{"campaign_id":{"type":"string"}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"system":{"type":["string","null"]},"image":{"type":["string","null"]},"public":{"type":"boolean"},"mature":{"type":"boolean"},"owner_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]},"archived":{"type":["boolean","null"]},"archived_at":{"type":["string","null"]},"summary":{"type":["string","null"]},"language":{"type":["string","null"]}},"type":"object","required":["id","title","public","mature","created_at"]}},{"name":"get-campaign-stats-tool","title":"Get Campaign Stats Tool","description":"Get statistics for a specific campaign: character count, session count, and more.","inputSchema":{"properties":{"campaign_id":{"type":"string"}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"campaign_id":{"type":"string"},"title":{"type":"string"},"characters":{"type":"integer"},"sessions":{"type":"integer"},"moments":{"type":"integer"},"public":{"type":"boolean"},"created_at":{"type":"string"}},"type":"object","required":["campaign_id","title","characters","sessions","moments","public","created_at"]}},{"name":"ask-campaign-tool","title":"Ask Campaign Tool","description":"RAG ask endpoint for campaign questions.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"question":{"type":"string"}},"type":"object","required":["campaign_id","question"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"answer":{"type":"string"},"citations":{"type":["array","null"]},"citations.*":{"type":"object"},"citations.*.source_type":{"enum":["beat","location","item","character","session","faction","quest"],"type":"string"},"citations.*.source_id":{"type":"string"},"citations.*.excerpt":{"type":"string"},"citations.*.mcp_tool":{"type":["object","null"]},"citations.*.mcp_tool.name":{"type":"string"},"citations.*.mcp_tool.arguments":{"type":"object"},"monthlyTokensRemaining":{"type":"integer"},"hourlyTokensRemaining":{"type":"integer"}},"type":"object","required":["answer","monthlyTokensRemaining","hourlyTokensRemaining"]}},{"name":"create-campaign-tool","title":"Create Campaign Tool","description":"Create a new MyArchivist campaign. Title is required; description, system (e.g. \"D&D 5e\"), summary, language, and tone fields are optional. Campaign creation is limited by the account's subscription tier; if the tier limit is exceeded the API returns a 403 with the tier name and cap.","inputSchema":{"properties":{"title":{"type":"string"},"description":{"type":["string","null"]},"system":{"type":["string","null"]},"summary":{"type":["string","null"]},"language":{"type":["string","null"]},"chat_tone":{"type":["string","null"]},"campaign_tone":{"type":["string","null"]},"entities_tone":{"type":["string","null"]},"ai_image_gen":{"type":["boolean","null"]},"public":{"type":["boolean","null"]},"mature":{"type":["boolean","null"]}},"type":"object","required":["title"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":true},"outputSchema":{"properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"system":{"type":["string","null"]},"image":{"type":["string","null"]},"public":{"type":"boolean"},"mature":{"type":"boolean"},"owner_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]},"archived":{"type":["boolean","null"]},"archived_at":{"type":["string","null"]},"summary":{"type":["string","null"]},"language":{"type":["string","null"]}},"type":"object","required":["id","title","public","mature","created_at"]}},{"name":"update-campaign-tool","title":"Update Campaign Tool","description":"Partially update a MyArchivist campaign. Only the campaign owner can update; only fields included in the request are changed. Cannot be used on archived campaigns.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"system":{"type":["string","null"]},"summary":{"type":["string","null"]},"language":{"type":["string","null"]},"chat_tone":{"type":["string","null"]},"campaign_tone":{"type":["string","null"]},"entities_tone":{"type":["string","null"]},"ai_image_gen":{"type":["boolean","null"]},"public":{"type":["boolean","null"]},"mature":{"type":["boolean","null"]}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":true},"outputSchema":{"properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"system":{"type":["string","null"]},"image":{"type":["string","null"]},"public":{"type":"boolean"},"mature":{"type":"boolean"},"owner_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]},"archived":{"type":["boolean","null"]},"archived_at":{"type":["string","null"]},"summary":{"type":["string","null"]},"language":{"type":["string","null"]}},"type":"object","required":["id","title","public","mature","created_at"]}},{"name":"list-characters-tool","title":"List Characters Tool","description":"List characters in a campaign. Optionally filter by name search, character type, and approval status.","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]},"campaign_id":{"type":"string"},"search":{"type":["string","null"]},"character_type":{"type":["string","null"]},"approved_only":{"type":["boolean","null"]},"with_links":{"type":["boolean","null"]}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of characters records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-character-tool","title":"Get Character Tool","description":"Get a specific character by ID including aliases, backstory, and speaker linkage.","inputSchema":{"properties":{"character_id":{"type":"string"},"with_links":{"type":["boolean","null"]}},"type":"object","required":["character_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"character_name":{"type":"string"},"character_alias":{"type":["string","null"]},"player_name":{"type":["string","null"]},"player":{"type":["object","null"]},"description":{"type":["string","null"]},"image":{"type":["string","null"]},"type":{"enum":["PC","NPC"],"type":["string","null"]},"character_aliases":{"type":["array","null"]},"player_handle":{"type":["string","null"]},"backstory":{"type":["string","null"]},"tcg_image":{"type":["string","null"]},"merge":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","character_name","merge","created_at"]}},{"name":"create-character-tool","title":"Create Character Tool","description":"Create a new character (PC or NPC) in a campaign. After drafting description (and backstory for characters), before calling create: for each entity name referenced in the text, run list_characters\/list_factions\/list_locations\/list_items with search=<candidate name>, read only character_name or name plus aliases from matches, wrap confirmed records per the markup rules below, then include the linked text in the create payload. Compendium writes auto-create Link rows. Wikilink markup rules: `[[Target Name|Alias]]` uses the left side only to resolve the entity; the right side becomes Link.alias (if omitted, both sides are the same string). The app renders links by matching bracket text to Link.alias \u2014 not by guessing from prose typography. Default to `[[Exact Name From API]]` with no pipe, copying character_name or name byte-for-byte from list_* results. Use `[[Target Name|Alias]]` only when the prose uses a shorter or different label than the entity name (e.g. [[Queen Whatsherface|the queen]]). Never write `[[Name|Name]]`, never put the canonical name on the left and a prose variant on the right when both refer to the same entity, and never mix straight\/curly apostrophes or other look-alike characters between sides. Re-wrapped aliases from list_links must match the stored alias string exactly inside the brackets.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"character_name":{"type":"string"},"character_alias":{"type":["string","null"]},"character_aliases":{"type":["array","null"]},"player_name":{"type":["string","null"]},"player_handle":{"type":["string","null"]},"description":{"type":["string","null"]},"backstory":{"type":["string","null"]},"type":{"enum":["PC","NPC"],"type":["string","null"]},"image":{"type":["string","null"]},"speaker_id":{"type":["string","null"]}},"type":"object","required":["campaign_id","character_name"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"character_name":{"type":"string"},"character_alias":{"type":["string","null"]},"player_name":{"type":["string","null"]},"player":{"type":["object","null"]},"description":{"type":["string","null"]},"image":{"type":["string","null"]},"type":{"enum":["PC","NPC"],"type":["string","null"]},"character_aliases":{"type":["array","null"]},"player_handle":{"type":["string","null"]},"backstory":{"type":["string","null"]},"tcg_image":{"type":["string","null"]},"merge":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","character_name","merge","created_at"]}},{"name":"update-character-tool","title":"Update Character Tool","description":"Partially update a character. Only the fields you include are changed. When editing description or backstory, follow this order: (1) fetch the entity with with_links: true; (2) list_links with from_id set to this entity's id and from_type matching its compendium type \u2014 store every returned alias in memory (writes delete Link rows whose alias no longer appears wrapped in the text); (3) draft the new prose; (4) re-wrap each stored alias as [[alias]] wherever that alias still appears (use [[Target|alias]] only if that link originally used a distinct display alias); (5) for other entity names in the draft, run list_characters\/list_factions\/list_locations\/list_items with search=<candidate name> and read only character_name or name plus aliases from matches \u2014 ignore long description fields; (6) wrap confirmed campaign entities using the markup rules below; compendium writes auto-create Link rows. Wikilink markup rules: `[[Target Name|Alias]]` uses the left side only to resolve the entity; the right side becomes Link.alias (if omitted, both sides are the same string). The app renders links by matching bracket text to Link.alias \u2014 not by guessing from prose typography. Default to `[[Exact Name From API]]` with no pipe, copying character_name or name byte-for-byte from list_* results. Use `[[Target Name|Alias]]` only when the prose uses a shorter or different label than the entity name (e.g. [[Queen Whatsherface|the queen]]). Never write `[[Name|Name]]`, never put the canonical name on the left and a prose variant on the right when both refer to the same entity, and never mix straight\/curly apostrophes or other look-alike characters between sides. Re-wrapped aliases from list_links must match the stored alias string exactly inside the brackets. Then call this update tool.","inputSchema":{"properties":{"character_id":{"type":"string"},"character_name":{"type":["string","null"]},"character_alias":{"type":["string","null"]},"character_aliases":{"type":["array","null"]},"player_name":{"type":["string","null"]},"player_handle":{"type":["string","null"]},"description":{"type":["string","null"]},"backstory":{"type":["string","null"]},"type":{"enum":["PC","NPC"],"type":["string","null"]},"image":{"type":["string","null"]},"speaker_id":{"type":["string","null"]}},"type":"object","required":["character_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"character_name":{"type":"string"},"character_alias":{"type":["string","null"]},"player_name":{"type":["string","null"]},"player":{"type":["object","null"]},"description":{"type":["string","null"]},"image":{"type":["string","null"]},"type":{"enum":["PC","NPC"],"type":["string","null"]},"character_aliases":{"type":["array","null"]},"player_handle":{"type":["string","null"]},"backstory":{"type":["string","null"]},"tcg_image":{"type":["string","null"]},"merge":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","character_name","merge","created_at"]}},{"name":"delete-character-tool","title":"Delete Character Tool","description":"Delete a character. The API cleans up all outgoing and inbound Link rows and unbrackets [[alias]] markup in every referring text field (Character descriptions, session summaries, beat descriptions, moment content, journal entries) so no dangling wikilinks remain.","inputSchema":{"properties":{"character_id":{"type":"string"}},"type":"object","required":["character_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"list-sessions-tool","title":"List Sessions Tool","description":"List game sessions in a campaign. Optionally filter by session type or public-only.","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]},"campaign_id":{"type":"string"},"session_type":{"enum":["audioUpload","playByPost","discordVoice","txtUpload","rawNotes","other"],"type":["string","null"]},"public_only":{"type":["boolean","null"]},"with_links":{"type":["boolean","null"]}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of sessions records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-session-tool","title":"Get Session Tool","description":"Get a specific game session by ID. Optionally include related beats and moments.","inputSchema":{"properties":{"session_id":{"type":"string"},"include_beats":{"type":["boolean","null"]},"include_moments":{"type":["boolean","null"]},"with_links":{"type":["boolean","null"]}},"type":"object","required":["session_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"type":{"enum":["audioUpload","playByPost","discordVoice","txtUpload","rawNotes","other"],"type":["string","null"]},"title":{"type":["string","null"]},"summary":{"type":["string","null"]},"session_date":{"type":["string","null"]},"public":{"type":"boolean"},"notes":{"type":["string","null"]},"image":{"type":["string","null"]},"index":{"type":["integer","null"]},"pbp_start_msg_url":{"type":["string","null"]},"pbp_end_msg_url":{"type":["string","null"]},"ai_session_review":{"type":["object","null"]},"ai_session_review.stage":{"type":["string","null"]},"ai_session_review.review_started_at":{"type":["string","null"]},"ai_session_review.save_started_at":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]},"beats":{"type":["array","null"]},"moments":{"type":["array","null"]}},"type":"object","required":["id","campaign_id","public","created_at"]}},{"name":"get-session-cast-analysis-tool","title":"Get Session Cast Analysis Tool","description":"Get the cast analysis for a game session, including talk-share breakdown and core session metrics.","inputSchema":{"properties":{"session_id":{"type":"string"}},"type":"object","required":["session_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"session_id":{"type":"string"},"analysis":{"type":"object"},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","session_id","analysis","created_at"]}},{"name":"get-session-handout-tool","title":"Get Session Handout Tool","description":"Get the generated session handout for a game session, including summary, outlines, spotlights, and notable moments.","inputSchema":{"properties":{"session_id":{"type":"string"}},"type":"object","required":["session_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"summary":{"type":"string"},"sessionOutline":{"type":["string","null"]},"encounters":{"type":["array","null"]},"characterSpotlight":{"type":["array","null"]},"otherEntitySpotlight":{"type":["array","null"]},"items":{"type":["array","null"]},"valuableInformation":{"type":["array","null"]},"partyStatusAndNextSteps":{"properties":{"partyStatus":{"properties":{"summary":{"type":"string"},"bullets":{"type":"array"}},"type":"object"},"nextSteps":{"properties":{"summary":{"type":"string"}},"type":"object"}},"type":["object","null"]},"moments":{"type":["array","null"]}},"type":"object","required":["summary"]}},{"name":"get-session-transcript-tool","title":"Get Session Transcript Tool","description":"Get the cleaned transcript for a game session, including utterances, full text, and aggregate stats.","inputSchema":{"properties":{"session_id":{"type":"string"}},"type":"object","required":["session_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"version":{"type":"integer"},"metadata":{"type":"object"},"text":{"type":"string"},"utterances":{"type":"array"},"stats":{"type":"object"},"created_at":{"type":"string"}},"type":"object","required":["version","metadata","text","utterances","stats","created_at"]}},{"name":"patch-session-tool","title":"Patch Session Tool","description":"Partially update a game session (limited fields: title, session_date, summary, notes, type, public, image). Omitted fields are left unchanged. notes holds the user-supplied content of rawNotes sessions. IMPORTANT: Sessions use the explicit-link contract, not the auto-resolve contract used by Character\/Faction\/Location\/Item. On write, the API strips any [[alias]] markup whose alias does NOT already have a Link row for this session; new wikilinks in summary are silently dropped. To reference an entity, call create_link first with from_type=\"GameSession\", then include [[alias]] in the summary. When editing summary, first fetch the session with get_session(with_links: true) to see current [[wikilinks]] and avoid losing them.","inputSchema":{"properties":{"session_id":{"type":"string"},"title":{"maxLength":255,"type":["string","null"]},"session_date":{"type":["string","null"]},"summary":{"type":["string","null"]},"notes":{"type":["string","null"]},"type":{"enum":["audioUpload","playByPost","discordVoice","txtUpload","rawNotes","other"],"type":["string","null"]},"public":{"type":["boolean","null"]},"image":{"type":["string","null"]}},"type":"object","required":["session_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"type":{"enum":["audioUpload","playByPost","discordVoice","txtUpload","rawNotes","other"],"type":["string","null"]},"title":{"type":["string","null"]},"summary":{"type":["string","null"]},"session_date":{"type":["string","null"]},"public":{"type":"boolean"},"notes":{"type":["string","null"]},"image":{"type":["string","null"]},"index":{"type":["integer","null"]},"pbp_start_msg_url":{"type":["string","null"]},"pbp_end_msg_url":{"type":["string","null"]},"ai_session_review":{"type":["object","null"]},"ai_session_review.stage":{"type":["string","null"]},"ai_session_review.review_started_at":{"type":["string","null"]},"ai_session_review.save_started_at":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]},"beats":{"type":["array","null"]},"moments":{"type":["array","null"]}},"type":"object","required":["id","campaign_id","public","created_at"]}},{"name":"list-beats-tool","title":"List Beats Tool","description":"List beats in a campaign, ordered by index. Beats represent story moments (major, minor, step).","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]},"campaign_id":{"type":"string"},"with_links":{"type":["boolean","null"]}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of beats records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-beat-tool","title":"Get Beat Tool","description":"Get a specific beat by ID.","inputSchema":{"properties":{"beat_id":{"type":"string"},"with_links":{"type":["boolean","null"]}},"type":"object","required":["beat_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"game_session_id":{"type":["string","null"]},"game_session_ids":{"type":["array","null"]},"label":{"type":"string"},"type":{"enum":["major","minor","step"],"type":"string"},"index":{"type":"integer"},"parent_id":{"type":["string","null"]},"description":{"type":["string","null"]},"metadata":{"type":["object","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","label","type","index","created_at"]}},{"name":"create-beat-tool","title":"Create Beat Tool","description":"Create a new story beat in a campaign. Beats organize the campaign timeline (major\/minor\/step) and can be attached to one or more sessions or nested under a parent beat. IMPORTANT: Like sessions, beat descriptions use the explicit-link contract \u2014 new [[wikilinks]] in description are silently dropped unless a matching Link already exists for this beat. To reference an entity, create the beat first, then call create_link with from_type=\"Beat\", then update_beat to include [[alias]] in the description.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"label":{"maxLength":255,"type":"string"},"description":{"maxLength":5000,"type":["string","null"]},"type":{"enum":["major","minor","step"],"type":["string","null"]},"index":{"type":["integer","null"]},"parent_id":{"type":["string","null"]},"game_session_id":{"type":["string","null"]},"game_session_ids":{"type":["array","null"]},"metadata":{"type":["object","null"]}},"type":"object","required":["campaign_id","label"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"game_session_id":{"type":["string","null"]},"game_session_ids":{"type":["array","null"]},"label":{"type":"string"},"type":{"enum":["major","minor","step"],"type":"string"},"index":{"type":"integer"},"parent_id":{"type":["string","null"]},"description":{"type":["string","null"]},"metadata":{"type":["object","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","label","type","index","created_at"]}},{"name":"update-beat-tool","title":"Update Beat Tool","description":"Partially update a story beat. IMPORTANT: Beats use the explicit-link contract. On write, [[alias]] markup in description is only preserved if a Link row already exists for this beat with that alias; new wikilinks are silently dropped. To add a wikilink, call create_link with from_type=\"Beat\" first, then include [[alias]] in description. When editing existing description, first fetch the beat with get_beat(with_links: true) to see the current [[wikilinks]] and avoid losing them.","inputSchema":{"properties":{"beat_id":{"type":"string"},"label":{"maxLength":255,"type":["string","null"]},"description":{"maxLength":5000,"type":["string","null"]},"type":{"enum":["major","minor","step"],"type":["string","null"]},"index":{"type":["integer","null"]},"parent_id":{"type":["string","null"]},"game_session_id":{"type":["string","null"]},"game_session_ids":{"type":["array","null"]},"metadata":{"type":["object","null"]}},"type":"object","required":["beat_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"game_session_id":{"type":["string","null"]},"game_session_ids":{"type":["array","null"]},"label":{"type":"string"},"type":{"enum":["major","minor","step"],"type":"string"},"index":{"type":"integer"},"parent_id":{"type":["string","null"]},"description":{"type":["string","null"]},"metadata":{"type":["object","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","label","type","index","created_at"]}},{"name":"delete-beat-tool","title":"Delete Beat Tool","description":"Delete a story beat. Child beats have their parent_id cleared. Any Link rows sourced from this beat are removed.","inputSchema":{"properties":{"beat_id":{"type":"string"}},"type":"object","required":["beat_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"list-moments-tool","title":"List Moments Tool","description":"List Key Moments (Moments) in a campaign or session. These are the same Moment records; the product now calls them Key Moments and they can carry an image plus presentation metadata (style, customTheme, variant). Filter by label search, comma-separated categories (Key Moments typically use \"key-moment\"), or kind. Pass with_links=true before editing content.","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]},"campaign_id":{"type":["string","null"]},"session_id":{"type":["string","null"]},"search":{"type":["string","null"]},"categories":{"type":["string","null"]},"kind":{"type":["string","null"]},"with_links":{"type":["boolean","null"]}},"type":"object"},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of moments records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-moment-tool","title":"Get Moment Tool","description":"Get a Key Moment (Moment) by ID, including image URL, categories, kind, and presentation metadata. Pass with_links=true before editing content. Attach or replace the card image with init_image_upload (entity_type=moment) then complete_image_upload.","inputSchema":{"properties":{"moment_id":{"type":"string"},"with_links":{"type":["boolean","null"]}},"type":"object","required":["moment_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"session_id":{"type":["string","null"]},"label":{"type":["string","null"]},"index":{"type":["integer","null"]},"content":{"type":["string","null"]},"image":{"type":["string","null"]},"categories":{"type":["array","null"]},"kind":{"type":["string","null"]},"metadata":{"type":["object","null"]},"pending":{"type":["boolean","null"]},"approved":{"type":["boolean","null"]},"discovered":{"type":["boolean","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","created_at"]}},{"name":"create-moment-tool","title":"Create Moment Tool","description":"Create a Key Moment (Moment) attached to a session. For a Key Moment card, set categories=[\"key-moment\"] and approved=true, pending=false. Optional image is a URL; to upload a file, create first then use init_image_upload with entity_type=moment. metadata holds presentation fields such as style, customTheme, and variant. IMPORTANT: Unlike Characters\/Factions\/Locations\/Items, moment content does NOT auto-resolve new [[wikilinks]]. Only aliases that already have Link rows (created via create_link or authored during transcript upload) are wrapped in the stored content. To add a wikilink referring to an entity, first call create_link with from_type=\"Moment\" and from_id set to the moment id, then update_moment to include [[alias]] in content.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"session_id":{"type":"string"},"label":{"maxLength":255,"type":["string","null"]},"content":{"maxLength":20000,"type":["string","null"]},"image":{"type":["string","null"]},"index":{"type":["integer","null"]},"categories":{"type":["array","null"]},"pending":{"type":["boolean","null"]},"approved":{"type":["boolean","null"]},"discovered":{"type":["boolean","null"]},"kind":{"maxLength":64,"type":["string","null"]},"metadata":{"type":["object","null"]}},"type":"object","required":["campaign_id","session_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"session_id":{"type":["string","null"]},"label":{"type":["string","null"]},"index":{"type":["integer","null"]},"content":{"type":["string","null"]},"image":{"type":["string","null"]},"categories":{"type":["array","null"]},"kind":{"type":["string","null"]},"metadata":{"type":["object","null"]},"pending":{"type":["boolean","null"]},"approved":{"type":["boolean","null"]},"discovered":{"type":["boolean","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","created_at"]}},{"name":"update-moment-tool","title":"Update Moment Tool","description":"Partially update a Key Moment (Moment), including image, categories, kind, and presentation metadata (merged into existing metadata so provenance keys are kept). IMPORTANT: Moments use the explicit-link contract, not the auto-resolve contract used by Character\/Faction\/Location\/Item. On write, the API strips any [[alias]] markup whose alias does NOT already have a Link row for this moment; new wikilinks in content are silently dropped. To reference an entity, call create_link first with from_type=\"Moment\", then include [[alias]] in the content on this update. When editing existing content, fetch the moment with get_moment(with_links: true) first to see the current [[wikilinks]] and avoid inadvertently losing them.","inputSchema":{"properties":{"moment_id":{"type":"string"},"label":{"maxLength":255,"type":["string","null"]},"content":{"maxLength":20000,"type":["string","null"]},"image":{"type":["string","null"]},"index":{"type":["integer","null"]},"categories":{"type":["array","null"]},"pending":{"type":["boolean","null"]},"approved":{"type":["boolean","null"]},"discovered":{"type":["boolean","null"]},"kind":{"maxLength":64,"type":["string","null"]},"metadata":{"type":["object","null"]}},"type":"object","required":["moment_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"session_id":{"type":["string","null"]},"label":{"type":["string","null"]},"index":{"type":["integer","null"]},"content":{"type":["string","null"]},"image":{"type":["string","null"]},"categories":{"type":["array","null"]},"kind":{"type":["string","null"]},"metadata":{"type":["object","null"]},"pending":{"type":["boolean","null"]},"approved":{"type":["boolean","null"]},"discovered":{"type":["boolean","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","created_at"]}},{"name":"delete-moment-tool","title":"Delete Moment Tool","description":"Delete a Key Moment (Moment). Any inbound\/outbound Link rows for this moment are removed. Note: as a source of wikilinks, moments only appear as [[\u2026]] in their own content (not in other entities' text), so no cross-record text rewriting is required.","inputSchema":{"properties":{"moment_id":{"type":"string"}},"type":"object","required":["moment_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"list-hero-awards-tool","title":"List Hero Awards Tool","description":"List hero awards in a campaign or session. Hero awards are player achievement cards (title, description, character, optional player name, card style). Filter by title\/description\/character search.","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]},"campaign_id":{"type":["string","null"]},"session_id":{"type":["string","null"]},"search":{"type":["string","null"]}},"type":"object"},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of hero awards records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-hero-award-tool","title":"Get Hero Award Tool","description":"Get a hero award by ID, including title, description, character\/player names, card style, variant, and custom theme.","inputSchema":{"properties":{"hero_award_id":{"type":"string"}},"type":"object","required":["hero_award_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"session_id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"character_name":{"type":["string","null"]},"player_name":{"type":["string","null"]},"tone_mode":{"type":["string","null"]},"award_mode":{"type":["string","null"]},"style":{"type":["string","null"]},"variant":{"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","session_id","title","description","created_at"]}},{"name":"create-hero-award-tool","title":"Create Hero Award Tool","description":"Create a hero award attached to a session. Requires title and description. Optional character_name, player_name, style (default verdant), variant (default square-v2), tone_mode (default), award_mode (moment or theme), and custom_theme. Hero awards do not use wikilinks. Card images are rendered by the app, not uploaded via init_image_upload.","inputSchema":{"properties":{"session_id":{"type":"string"},"title":{"maxLength":200,"type":"string"},"description":{"maxLength":4000,"type":"string"},"character_name":{"maxLength":120,"type":["string","null"]},"player_name":{"maxLength":120,"type":["string","null"]},"tone_mode":{"maxLength":40,"type":["string","null"]},"award_mode":{"enum":["moment","theme"],"type":["string","null"]},"style":{"maxLength":40,"type":["string","null"]},"variant":{"maxLength":40,"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]}},"type":"object","required":["session_id","title","description"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"session_id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"character_name":{"type":["string","null"]},"player_name":{"type":["string","null"]},"tone_mode":{"type":["string","null"]},"award_mode":{"type":["string","null"]},"style":{"type":["string","null"]},"variant":{"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","session_id","title","description","created_at"]}},{"name":"update-hero-award-tool","title":"Update Hero Award Tool","description":"Partially update a hero award (title, description, character\/player names, style, variant, tone_mode, award_mode, custom_theme, order_index).","inputSchema":{"properties":{"hero_award_id":{"type":"string"},"title":{"maxLength":200,"type":["string","null"]},"description":{"maxLength":4000,"type":["string","null"]},"character_name":{"maxLength":120,"type":["string","null"]},"player_name":{"maxLength":120,"type":["string","null"]},"tone_mode":{"maxLength":40,"type":["string","null"]},"award_mode":{"enum":["moment","theme"],"type":["string","null"]},"style":{"maxLength":40,"type":["string","null"]},"variant":{"maxLength":40,"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]}},"type":"object","required":["hero_award_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"session_id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"character_name":{"type":["string","null"]},"player_name":{"type":["string","null"]},"tone_mode":{"type":["string","null"]},"award_mode":{"type":["string","null"]},"style":{"type":["string","null"]},"variant":{"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","session_id","title","description","created_at"]}},{"name":"delete-hero-award-tool","title":"Delete Hero Award Tool","description":"Delete a hero award.","inputSchema":{"properties":{"hero_award_id":{"type":"string"}},"type":"object","required":["hero_award_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"list-quotes-tool","title":"List Quotes Tool","description":"List memorable session quotes in a campaign or session. Quotes are recap cards (speaker, text, context, style). Filter by text\/speaker\/context search.","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]},"campaign_id":{"type":["string","null"]},"session_id":{"type":["string","null"]},"search":{"type":["string","null"]}},"type":"object"},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of quotes records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-quote-tool","title":"Get Quote Tool","description":"Get a session quote by ID, including speaker, text, context, character name, and card style.","inputSchema":{"properties":{"quote_id":{"type":"string"}},"type":"object","required":["quote_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"session_id":{"type":"string"},"text":{"type":"string"},"speaker":{"type":["string","null"]},"character_name":{"type":["string","null"]},"context":{"type":["string","null"]},"style":{"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]},"pipeline_id":{"type":["string","null"]},"recap_set_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","session_id","text","created_at"]}},{"name":"create-quote-tool","title":"Create Quote Tool","description":"Create a memorable quote attached to a session. Requires text. Optional speaker, character_name, context, style (default verdant), and custom_theme. A recap pipeline is created for the session if one does not exist. Quotes do not use wikilinks.","inputSchema":{"properties":{"session_id":{"type":"string"},"text":{"maxLength":8000,"type":"string"},"speaker":{"maxLength":200,"type":["string","null"]},"character_name":{"maxLength":120,"type":["string","null"]},"context":{"maxLength":2000,"type":["string","null"]},"style":{"maxLength":40,"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]}},"type":"object","required":["session_id","text"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"session_id":{"type":"string"},"text":{"type":"string"},"speaker":{"type":["string","null"]},"character_name":{"type":["string","null"]},"context":{"type":["string","null"]},"style":{"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]},"pipeline_id":{"type":["string","null"]},"recap_set_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","session_id","text","created_at"]}},{"name":"update-quote-tool","title":"Update Quote Tool","description":"Partially update a session quote (text, speaker, character_name, context, style, custom_theme, order_index).","inputSchema":{"properties":{"quote_id":{"type":"string"},"text":{"maxLength":8000,"type":["string","null"]},"speaker":{"maxLength":200,"type":["string","null"]},"character_name":{"maxLength":120,"type":["string","null"]},"context":{"maxLength":2000,"type":["string","null"]},"style":{"maxLength":40,"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]}},"type":"object","required":["quote_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"session_id":{"type":"string"},"text":{"type":"string"},"speaker":{"type":["string","null"]},"character_name":{"type":["string","null"]},"context":{"type":["string","null"]},"style":{"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]},"pipeline_id":{"type":["string","null"]},"recap_set_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","session_id","text","created_at"]}},{"name":"delete-quote-tool","title":"Delete Quote Tool","description":"Delete a session quote.","inputSchema":{"properties":{"quote_id":{"type":"string"}},"type":"object","required":["quote_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"list-spotlights-tool","title":"List Spotlights Tool","description":"List recap spotlights in a campaign or session. These are GEMS spotlight cards (title, description, character\/player), not session-handout spotlights. Filter by title\/description\/character search.","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]},"campaign_id":{"type":["string","null"]},"session_id":{"type":["string","null"]},"search":{"type":["string","null"]}},"type":"object"},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of spotlights records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-spotlight-tool","title":"Get Spotlight Tool","description":"Get a recap spotlight by ID, including title, description, character\/player names, and card style. This is a GEMS spotlight card, not a session-handout spotlight.","inputSchema":{"properties":{"spotlight_id":{"type":"string"}},"type":"object","required":["spotlight_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"session_id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"character_name":{"type":["string","null"]},"player_name":{"type":["string","null"]},"style":{"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]},"entry_type":{"type":["string","null"]},"source_moment_id":{"type":["string","null"]},"pipeline_id":{"type":["string","null"]},"recap_set_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","session_id","title","created_at"]}},{"name":"create-spotlight-tool","title":"Create Spotlight Tool","description":"Create a recap spotlight attached to a session. Requires title. Optional description, character_name, player_name, style (default verdant), custom_theme, and source_moment_id. A recap pipeline is created for the session if one does not exist. Spotlights do not use wikilinks. This is a GEMS card, not a session-handout spotlight.","inputSchema":{"properties":{"session_id":{"type":"string"},"title":{"maxLength":200,"type":"string"},"description":{"maxLength":4000,"type":["string","null"]},"character_name":{"maxLength":120,"type":["string","null"]},"player_name":{"maxLength":120,"type":["string","null"]},"style":{"maxLength":40,"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]},"source_moment_id":{"type":["string","null"]}},"type":"object","required":["session_id","title"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"session_id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"character_name":{"type":["string","null"]},"player_name":{"type":["string","null"]},"style":{"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]},"entry_type":{"type":["string","null"]},"source_moment_id":{"type":["string","null"]},"pipeline_id":{"type":["string","null"]},"recap_set_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","session_id","title","created_at"]}},{"name":"update-spotlight-tool","title":"Update Spotlight Tool","description":"Partially update a recap spotlight (title, description, character\/player names, style, custom_theme, order_index, source_moment_id).","inputSchema":{"properties":{"spotlight_id":{"type":"string"},"title":{"maxLength":200,"type":["string","null"]},"description":{"maxLength":4000,"type":["string","null"]},"character_name":{"maxLength":120,"type":["string","null"]},"player_name":{"maxLength":120,"type":["string","null"]},"style":{"maxLength":40,"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]},"source_moment_id":{"type":["string","null"]}},"type":"object","required":["spotlight_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"session_id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"character_name":{"type":["string","null"]},"player_name":{"type":["string","null"]},"style":{"type":["string","null"]},"custom_theme":{"type":["object","null"]},"order_index":{"type":["integer","null"]},"entry_type":{"type":["string","null"]},"source_moment_id":{"type":["string","null"]},"pipeline_id":{"type":["string","null"]},"recap_set_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","session_id","title","created_at"]}},{"name":"delete-spotlight-tool","title":"Delete Spotlight Tool","description":"Delete a recap spotlight.","inputSchema":{"properties":{"spotlight_id":{"type":"string"}},"type":"object","required":["spotlight_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"list-factions-tool","title":"List Factions Tool","description":"List factions in a campaign. Optionally filter by name search. Factions represent guilds, organisations, or other groups.","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]},"campaign_id":{"type":"string"},"search":{"type":["string","null"]},"with_links":{"type":["boolean","null"]}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of factions records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-faction-tool","title":"Get Faction Tool","description":"Get a specific faction by ID.","inputSchema":{"properties":{"faction_id":{"type":"string"},"with_links":{"type":["boolean","null"]}},"type":"object","required":["faction_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"type":{"type":["string","null"]},"image":{"type":["string","null"]},"aliases":{"type":["array","null"]},"tcg_image":{"type":["string","null"]},"merge":{"type":["boolean","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","name","created_at"]}},{"name":"create-faction-tool","title":"Create Faction Tool","description":"Create a new faction in a campaign. After drafting description (and backstory for characters), before calling create: for each entity name referenced in the text, run list_characters\/list_factions\/list_locations\/list_items with search=<candidate name>, read only character_name or name plus aliases from matches, wrap confirmed records per the markup rules below, then include the linked text in the create payload. Compendium writes auto-create Link rows. Wikilink markup rules: `[[Target Name|Alias]]` uses the left side only to resolve the entity; the right side becomes Link.alias (if omitted, both sides are the same string). The app renders links by matching bracket text to Link.alias \u2014 not by guessing from prose typography. Default to `[[Exact Name From API]]` with no pipe, copying character_name or name byte-for-byte from list_* results. Use `[[Target Name|Alias]]` only when the prose uses a shorter or different label than the entity name (e.g. [[Queen Whatsherface|the queen]]). Never write `[[Name|Name]]`, never put the canonical name on the left and a prose variant on the right when both refer to the same entity, and never mix straight\/curly apostrophes or other look-alike characters between sides. Re-wrapped aliases from list_links must match the stored alias string exactly inside the brackets.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"name":{"type":"string"},"aliases":{"type":["array","null"]},"type":{"type":["string","null"]},"description":{"type":["string","null"]},"image":{"type":["string","null"]}},"type":"object","required":["campaign_id","name"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"type":{"type":["string","null"]},"image":{"type":["string","null"]},"aliases":{"type":["array","null"]},"tcg_image":{"type":["string","null"]},"merge":{"type":["boolean","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","name","created_at"]}},{"name":"update-faction-tool","title":"Update Faction Tool","description":"Partially update a faction. When editing description or backstory, follow this order: (1) fetch the entity with with_links: true; (2) list_links with from_id set to this entity's id and from_type matching its compendium type \u2014 store every returned alias in memory (writes delete Link rows whose alias no longer appears wrapped in the text); (3) draft the new prose; (4) re-wrap each stored alias as [[alias]] wherever that alias still appears (use [[Target|alias]] only if that link originally used a distinct display alias); (5) for other entity names in the draft, run list_characters\/list_factions\/list_locations\/list_items with search=<candidate name> and read only character_name or name plus aliases from matches \u2014 ignore long description fields; (6) wrap confirmed campaign entities using the markup rules below; compendium writes auto-create Link rows. Wikilink markup rules: `[[Target Name|Alias]]` uses the left side only to resolve the entity; the right side becomes Link.alias (if omitted, both sides are the same string). The app renders links by matching bracket text to Link.alias \u2014 not by guessing from prose typography. Default to `[[Exact Name From API]]` with no pipe, copying character_name or name byte-for-byte from list_* results. Use `[[Target Name|Alias]]` only when the prose uses a shorter or different label than the entity name (e.g. [[Queen Whatsherface|the queen]]). Never write `[[Name|Name]]`, never put the canonical name on the left and a prose variant on the right when both refer to the same entity, and never mix straight\/curly apostrophes or other look-alike characters between sides. Re-wrapped aliases from list_links must match the stored alias string exactly inside the brackets. Then call this update tool.","inputSchema":{"properties":{"faction_id":{"type":"string"},"name":{"type":["string","null"]},"aliases":{"type":["array","null"]},"type":{"type":["string","null"]},"description":{"type":["string","null"]},"image":{"type":["string","null"]}},"type":"object","required":["faction_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"type":{"type":["string","null"]},"image":{"type":["string","null"]},"aliases":{"type":["array","null"]},"tcg_image":{"type":["string","null"]},"merge":{"type":["boolean","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","name","created_at"]}},{"name":"delete-faction-tool","title":"Delete Faction Tool","description":"Delete a faction. The API cleans up all outgoing and inbound Link rows and unbrackets [[alias]] markup for this faction in every referring text field.","inputSchema":{"properties":{"faction_id":{"type":"string"}},"type":"object","required":["faction_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"list-locations-tool","title":"List Locations Tool","description":"List locations in a campaign. Optionally filter by name search. Locations can be nested (cities, taverns, dungeons, etc.).","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]},"campaign_id":{"type":"string"},"search":{"type":["string","null"]},"with_links":{"type":["boolean","null"]}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of locations records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-location-tool","title":"Get Location Tool","description":"Get a specific location by ID.","inputSchema":{"properties":{"location_id":{"type":"string"},"with_links":{"type":["boolean","null"]}},"type":"object","required":["location_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"type":{"type":["string","null"]},"parent_id":{"type":["string","null"]},"image":{"type":["string","null"]},"aliases":{"type":["array","null"]},"tcg_image":{"type":["string","null"]},"merge":{"type":["boolean","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","name","created_at"]}},{"name":"create-location-tool","title":"Create Location Tool","description":"Create a new location in a campaign. Locations can nest (parent_id references another Location in the same campaign). After drafting description (and backstory for characters), before calling create: for each entity name referenced in the text, run list_characters\/list_factions\/list_locations\/list_items with search=<candidate name>, read only character_name or name plus aliases from matches, wrap confirmed records per the markup rules below, then include the linked text in the create payload. Compendium writes auto-create Link rows. Wikilink markup rules: `[[Target Name|Alias]]` uses the left side only to resolve the entity; the right side becomes Link.alias (if omitted, both sides are the same string). The app renders links by matching bracket text to Link.alias \u2014 not by guessing from prose typography. Default to `[[Exact Name From API]]` with no pipe, copying character_name or name byte-for-byte from list_* results. Use `[[Target Name|Alias]]` only when the prose uses a shorter or different label than the entity name (e.g. [[Queen Whatsherface|the queen]]). Never write `[[Name|Name]]`, never put the canonical name on the left and a prose variant on the right when both refer to the same entity, and never mix straight\/curly apostrophes or other look-alike characters between sides. Re-wrapped aliases from list_links must match the stored alias string exactly inside the brackets.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"name":{"type":"string"},"aliases":{"type":["array","null"]},"type":{"type":["string","null"]},"description":{"type":["string","null"]},"image":{"type":["string","null"]},"parent_id":{"type":["string","null"]}},"type":"object","required":["campaign_id","name"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"type":{"type":["string","null"]},"parent_id":{"type":["string","null"]},"image":{"type":["string","null"]},"aliases":{"type":["array","null"]},"tcg_image":{"type":["string","null"]},"merge":{"type":["boolean","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","name","created_at"]}},{"name":"update-location-tool","title":"Update Location Tool","description":"Partially update a location. When editing description or backstory, follow this order: (1) fetch the entity with with_links: true; (2) list_links with from_id set to this entity's id and from_type matching its compendium type \u2014 store every returned alias in memory (writes delete Link rows whose alias no longer appears wrapped in the text); (3) draft the new prose; (4) re-wrap each stored alias as [[alias]] wherever that alias still appears (use [[Target|alias]] only if that link originally used a distinct display alias); (5) for other entity names in the draft, run list_characters\/list_factions\/list_locations\/list_items with search=<candidate name> and read only character_name or name plus aliases from matches \u2014 ignore long description fields; (6) wrap confirmed campaign entities using the markup rules below; compendium writes auto-create Link rows. Wikilink markup rules: `[[Target Name|Alias]]` uses the left side only to resolve the entity; the right side becomes Link.alias (if omitted, both sides are the same string). The app renders links by matching bracket text to Link.alias \u2014 not by guessing from prose typography. Default to `[[Exact Name From API]]` with no pipe, copying character_name or name byte-for-byte from list_* results. Use `[[Target Name|Alias]]` only when the prose uses a shorter or different label than the entity name (e.g. [[Queen Whatsherface|the queen]]). Never write `[[Name|Name]]`, never put the canonical name on the left and a prose variant on the right when both refer to the same entity, and never mix straight\/curly apostrophes or other look-alike characters between sides. Re-wrapped aliases from list_links must match the stored alias string exactly inside the brackets. Then call this update tool.","inputSchema":{"properties":{"location_id":{"type":"string"},"name":{"type":["string","null"]},"aliases":{"type":["array","null"]},"type":{"type":["string","null"]},"description":{"type":["string","null"]},"image":{"type":["string","null"]},"parent_id":{"type":["string","null"]}},"type":"object","required":["location_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"type":{"type":["string","null"]},"parent_id":{"type":["string","null"]},"image":{"type":["string","null"]},"aliases":{"type":["array","null"]},"tcg_image":{"type":["string","null"]},"merge":{"type":["boolean","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","name","created_at"]}},{"name":"delete-location-tool","title":"Delete Location Tool","description":"Delete a location. Child locations are unlinked (their parent_id is cleared). The API cleans up all outgoing and inbound Link rows and unbrackets [[alias]] markup for this location in every referring text field.","inputSchema":{"properties":{"location_id":{"type":"string"}},"type":"object","required":["location_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"list-items-tool","title":"List Items Tool","description":"List items in a campaign. Optionally filter by name search. Items include weapons, armour, artefacts, and other notable objects.","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]},"campaign_id":{"type":"string"},"search":{"type":["string","null"]},"with_links":{"type":["boolean","null"]}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of items records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-item-tool","title":"Get Item Tool","description":"Get a specific item by ID.","inputSchema":{"properties":{"item_id":{"type":"string"},"with_links":{"type":["boolean","null"]}},"type":"object","required":["item_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"type":{"type":["string","null"]},"image":{"type":["string","null"]},"aliases":{"type":["array","null"]},"tcg_image":{"type":["string","null"]},"merge":{"type":["boolean","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","name","created_at"]}},{"name":"create-item-tool","title":"Create Item Tool","description":"Create a new item in a campaign. After drafting description (and backstory for characters), before calling create: for each entity name referenced in the text, run list_characters\/list_factions\/list_locations\/list_items with search=<candidate name>, read only character_name or name plus aliases from matches, wrap confirmed records per the markup rules below, then include the linked text in the create payload. Compendium writes auto-create Link rows. Wikilink markup rules: `[[Target Name|Alias]]` uses the left side only to resolve the entity; the right side becomes Link.alias (if omitted, both sides are the same string). The app renders links by matching bracket text to Link.alias \u2014 not by guessing from prose typography. Default to `[[Exact Name From API]]` with no pipe, copying character_name or name byte-for-byte from list_* results. Use `[[Target Name|Alias]]` only when the prose uses a shorter or different label than the entity name (e.g. [[Queen Whatsherface|the queen]]). Never write `[[Name|Name]]`, never put the canonical name on the left and a prose variant on the right when both refer to the same entity, and never mix straight\/curly apostrophes or other look-alike characters between sides. Re-wrapped aliases from list_links must match the stored alias string exactly inside the brackets.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"name":{"type":"string"},"aliases":{"type":["array","null"]},"type":{"type":["string","null"]},"description":{"type":["string","null"]},"image":{"type":["string","null"]}},"type":"object","required":["campaign_id","name"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"type":{"type":["string","null"]},"image":{"type":["string","null"]},"aliases":{"type":["array","null"]},"tcg_image":{"type":["string","null"]},"merge":{"type":["boolean","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","name","created_at"]}},{"name":"update-item-tool","title":"Update Item Tool","description":"Partially update an item. When editing description or backstory, follow this order: (1) fetch the entity with with_links: true; (2) list_links with from_id set to this entity's id and from_type matching its compendium type \u2014 store every returned alias in memory (writes delete Link rows whose alias no longer appears wrapped in the text); (3) draft the new prose; (4) re-wrap each stored alias as [[alias]] wherever that alias still appears (use [[Target|alias]] only if that link originally used a distinct display alias); (5) for other entity names in the draft, run list_characters\/list_factions\/list_locations\/list_items with search=<candidate name> and read only character_name or name plus aliases from matches \u2014 ignore long description fields; (6) wrap confirmed campaign entities using the markup rules below; compendium writes auto-create Link rows. Wikilink markup rules: `[[Target Name|Alias]]` uses the left side only to resolve the entity; the right side becomes Link.alias (if omitted, both sides are the same string). The app renders links by matching bracket text to Link.alias \u2014 not by guessing from prose typography. Default to `[[Exact Name From API]]` with no pipe, copying character_name or name byte-for-byte from list_* results. Use `[[Target Name|Alias]]` only when the prose uses a shorter or different label than the entity name (e.g. [[Queen Whatsherface|the queen]]). Never write `[[Name|Name]]`, never put the canonical name on the left and a prose variant on the right when both refer to the same entity, and never mix straight\/curly apostrophes or other look-alike characters between sides. Re-wrapped aliases from list_links must match the stored alias string exactly inside the brackets. Then call this update tool.","inputSchema":{"properties":{"item_id":{"type":"string"},"name":{"type":["string","null"]},"aliases":{"type":["array","null"]},"type":{"type":["string","null"]},"description":{"type":["string","null"]},"image":{"type":["string","null"]}},"type":"object","required":["item_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"type":{"type":["string","null"]},"image":{"type":["string","null"]},"aliases":{"type":["array","null"]},"tcg_image":{"type":["string","null"]},"merge":{"type":["boolean","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","name","created_at"]}},{"name":"delete-item-tool","title":"Delete Item Tool","description":"Delete an item. The API cleans up all outgoing and inbound Link rows and unbrackets [[alias]] markup for this item in every referring text field.","inputSchema":{"properties":{"item_id":{"type":"string"}},"type":"object","required":["item_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"list-quests-tool","title":"List Quests Tool","description":"List quests in a campaign with pagination. Filter by status (planned, in-progress, blocked, failed, done, n\/a) or category (main, side, faction, personal, n\/a).","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]},"campaign_id":{"type":"string"},"search":{"type":["string","null"]},"status":{"enum":["planned","in-progress","blocked","failed","done","n\/a"],"type":["string","null"]},"quest_category":{"enum":["main","side","faction","personal","n\/a"],"type":["string","null"]}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of quests records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-quest-tool","title":"Get Quest Tool","description":"Get a fully expanded quest by ID, including objectives, progress log, related entity refs, and session provenance.","inputSchema":{"properties":{"quest_id":{"type":"string"}},"type":"object","required":["quest_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"order_index":{"type":"integer"},"quest_name":{"type":"string"},"quest_category":{"enum":["main","side","faction","personal","n\/a"],"type":["string","null"]},"status":{"enum":["planned","in-progress","blocked","failed","done","n\/a"],"type":["string","null"]},"quest_giver":{"type":["string","null"]},"quest_giver_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]},"next_action":{"type":["string","null"]},"resolution":{"type":["string","null"]},"objective_count":{"type":["integer","null"]},"completed_objective_count":{"type":["integer","null"]},"progress_entry_count":{"type":["integer","null"]},"related_entity_count":{"type":["integer","null"]},"first_session":{"type":["object","null"]},"last_session":{"type":["object","null"]},"success_definition":{"type":["string","null"]},"failure_conditions":{"type":["string","null"]},"objectives":{"type":["array","null"]},"progress_log":{"type":["array","null"]},"progress_log_entries":{"type":["array","null"]},"related_characters":{"type":["array","null"]},"related_factions":{"type":["array","null"]},"related_locations":{"type":["array","null"]},"related_items":{"type":["array","null"]},"related_entity_refs":{"type":["array","null"]}},"type":"object","required":["id","campaign_id","order_index","quest_name","created_at"]}},{"name":"create-quest-tool","title":"Create Quest Tool","description":"Create a new quest entry in a campaign's quest log. Objectives is a list of objects with {text, status} where status is pending\/in-progress\/completed\/failed\/blocked. related_characters\/factions\/locations\/items are lists of entity ids or names. Quests use snake_case field names in their body. Quests do NOT participate in the wikilinks system: text fields (success_definition, failure_conditions, next_action, resolution) are stored verbatim without link syncing.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"quest_name":{"maxLength":255,"type":"string"},"quest_giver":{"maxLength":255,"type":["string","null"]},"quest_category":{"enum":["main","side","faction","personal","n\/a"],"type":["string","null"]},"status":{"enum":["planned","in-progress","blocked","failed","done","n\/a"],"type":["string","null"]},"success_definition":{"maxLength":2000,"type":["string","null"]},"failure_conditions":{"maxLength":2000,"type":["string","null"]},"next_action":{"maxLength":2000,"type":["string","null"]},"resolution":{"maxLength":2000,"type":["string","null"]},"objectives":{"type":["array","null"]},"progress_log":{"type":["array","null"]},"related_characters":{"type":["array","null"]},"related_factions":{"type":["array","null"]},"related_locations":{"type":["array","null"]},"related_items":{"type":["array","null"]},"related_entity_refs":{"type":["array","null"]}},"type":"object","required":["campaign_id","quest_name"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"order_index":{"type":"integer"},"quest_name":{"type":"string"},"quest_category":{"enum":["main","side","faction","personal","n\/a"],"type":["string","null"]},"status":{"enum":["planned","in-progress","blocked","failed","done","n\/a"],"type":["string","null"]},"quest_giver":{"type":["string","null"]},"quest_giver_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]},"next_action":{"type":["string","null"]},"resolution":{"type":["string","null"]},"objective_count":{"type":["integer","null"]},"completed_objective_count":{"type":["integer","null"]},"progress_entry_count":{"type":["integer","null"]},"related_entity_count":{"type":["integer","null"]},"first_session":{"type":["object","null"]},"last_session":{"type":["object","null"]},"success_definition":{"type":["string","null"]},"failure_conditions":{"type":["string","null"]},"objectives":{"type":["array","null"]},"progress_log":{"type":["array","null"]},"progress_log_entries":{"type":["array","null"]},"related_characters":{"type":["array","null"]},"related_factions":{"type":["array","null"]},"related_locations":{"type":["array","null"]},"related_items":{"type":["array","null"]},"related_entity_refs":{"type":["array","null"]}},"type":"object","required":["id","campaign_id","order_index","quest_name","created_at"]}},{"name":"update-quest-tool","title":"Update Quest Tool","description":"Partially update a quest. Any list you send replaces the corresponding list on the record (objectives, progress_log, related_characters, etc). Quests do NOT participate in the wikilinks system, so text fields are stored verbatim.","inputSchema":{"properties":{"quest_id":{"type":"string"},"quest_name":{"maxLength":255,"type":["string","null"]},"quest_giver":{"maxLength":255,"type":["string","null"]},"quest_category":{"enum":["main","side","faction","personal","n\/a"],"type":["string","null"]},"status":{"enum":["planned","in-progress","blocked","failed","done","n\/a"],"type":["string","null"]},"success_definition":{"maxLength":2000,"type":["string","null"]},"failure_conditions":{"maxLength":2000,"type":["string","null"]},"next_action":{"maxLength":2000,"type":["string","null"]},"resolution":{"maxLength":2000,"type":["string","null"]},"objectives":{"type":["array","null"]},"progress_log":{"type":["array","null"]},"related_characters":{"type":["array","null"]},"related_factions":{"type":["array","null"]},"related_locations":{"type":["array","null"]},"related_items":{"type":["array","null"]},"related_entity_refs":{"type":["array","null"]}},"type":"object","required":["quest_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"order_index":{"type":"integer"},"quest_name":{"type":"string"},"quest_category":{"enum":["main","side","faction","personal","n\/a"],"type":["string","null"]},"status":{"enum":["planned","in-progress","blocked","failed","done","n\/a"],"type":["string","null"]},"quest_giver":{"type":["string","null"]},"quest_giver_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]},"next_action":{"type":["string","null"]},"resolution":{"type":["string","null"]},"objective_count":{"type":["integer","null"]},"completed_objective_count":{"type":["integer","null"]},"progress_entry_count":{"type":["integer","null"]},"related_entity_count":{"type":["integer","null"]},"first_session":{"type":["object","null"]},"last_session":{"type":["object","null"]},"success_definition":{"type":["string","null"]},"failure_conditions":{"type":["string","null"]},"objectives":{"type":["array","null"]},"progress_log":{"type":["array","null"]},"progress_log_entries":{"type":["array","null"]},"related_characters":{"type":["array","null"]},"related_factions":{"type":["array","null"]},"related_locations":{"type":["array","null"]},"related_items":{"type":["array","null"]},"related_entity_refs":{"type":["array","null"]}},"type":"object","required":["id","campaign_id","order_index","quest_name","created_at"]}},{"name":"delete-quest-tool","title":"Delete Quest Tool","description":"Delete a quest and its objectives \/ progress entries \/ related refs.","inputSchema":{"properties":{"quest_id":{"type":"string"}},"type":"object","required":["quest_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"list-journals-tool","title":"List Journals Tool","description":"List journal entries in a campaign. Results are filtered to entries the caller can see. Content is omitted from the list; use get_journal to fetch full content.","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]},"campaign_id":{"type":"string"},"folder_id":{"type":["string","null"]},"with_links":{"type":["boolean","null"]}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of journals records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-journal-tool","title":"Get Journal Tool","description":"Get a specific journal entry by ID including full content and the caller's effective permission level.","inputSchema":{"properties":{"entry_id":{"type":"string"},"with_links":{"type":["boolean","null"]}},"type":"object","required":["entry_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"title":{"type":"string"},"summary":{"type":["string","null"]},"status":{"enum":["draft","published","archived"],"type":["string","null"]},"folder_id":{"type":["string","null"]},"is_public":{"type":"boolean"},"is_pinned":{"type":["boolean","null"]},"tags":{"type":["array","null"]},"content":{"type":["string","null"]},"author_id":{"type":["string","null"]},"last_edited_by_id":{"type":["string","null"]},"token_count":{"type":["integer","null"]},"cover_image":{"type":["string","null"]},"published_at":{"type":["string","null"]},"archived_at":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]},"content_rich":{"type":["object","null"]},"content_metadata":{"type":["object","null"]},"permission_level":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","title","is_public","created_at"]}},{"name":"create-journal-tool","title":"Create Journal Tool","description":"Create a new journal entry in a campaign. Returns {success, id} on success. content is plain text; content_rich accepts a ProseMirror-style JSON document. Journals participate in the wikilinks system on serialization only: [[wikilinks]] in stored content are rendered when you fetch with with_links=true, but on write the API does not create Link rows from the text automatically. Create Link rows explicitly with create_link (from_type=\"Journal\", from_id=journal_id) if you want persistent link tracking. Setting is_public and status=\"published\" can make the entry publicly visible.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"title":{"maxLength":255,"type":"string"},"summary":{"type":["string","null"]},"content":{"type":["string","null"]},"content_rich":{"type":["object","null"]},"content_metadata":{"type":["object","null"]},"tags":{"type":["array","null"]},"cover_image":{"type":["string","null"]},"is_pinned":{"type":["boolean","null"]},"is_public":{"type":["boolean","null"]},"status":{"enum":["draft","published","archived"],"type":["string","null"]},"published_at":{"type":["string","null"]},"archived_at":{"type":["string","null"]},"folder_id":{"type":["string","null"]}},"type":"object","required":["campaign_id","title"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":true},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"update-journal-tool","title":"Update Journal Tool","description":"Update an existing journal entry (PUT). Returns {success, id}. When editing content, first fetch the entry with get_journal(with_links: true) so you can see and preserve existing [[wikilinks]] \u2014 links are not auto-created from text, but existing [[\u2026]] markup should be kept if you want them rendered as links on read. Changing is_public or status can publish or unpublish the entry.","inputSchema":{"properties":{"entry_id":{"type":"string"},"title":{"maxLength":255,"type":["string","null"]},"summary":{"type":["string","null"]},"content":{"type":["string","null"]},"content_rich":{"type":["object","null"]},"content_metadata":{"type":["object","null"]},"tags":{"type":["array","null"]},"cover_image":{"type":["string","null"]},"is_pinned":{"type":["boolean","null"]},"is_public":{"type":["boolean","null"]},"status":{"enum":["draft","published","archived"],"type":["string","null"]},"published_at":{"type":["string","null"]},"archived_at":{"type":["string","null"]},"folder_id":{"type":["string","null"]}},"type":"object","required":["entry_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"delete-journal-tool","title":"Delete Journal Tool","description":"Delete a journal entry. Returns {success: true}. Vector embeddings for the entry are best-effort deleted alongside the row. Deleting a published public entry removes its publicly visible content.","inputSchema":{"properties":{"entry_id":{"type":"string"}},"type":"object","required":["entry_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"list-journal-folders-tool","title":"List Journal Folders Tool","description":"List journal folders for a campaign. Folders are ordered by path and position for tree rendering.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"parent_id":{"type":["string","null"]}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of journal folders records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"get-journal-folder-tool","title":"Get Journal Folder Tool","description":"Get a specific journal folder by ID.","inputSchema":{"properties":{"folder_id":{"type":"string"}},"type":"object","required":["folder_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"parent_id":{"type":["string","null"]},"name":{"type":"string"},"path":{"type":"string"},"position":{"type":"integer"},"description":{"type":["string","null"]},"metadata":{"type":["array","null"]},"created_at":{"type":"string"},"updated_at":{"type":["string","null"]}},"type":"object","required":["id","campaign_id","name","path","position","created_at"]}},{"name":"create-journal-folder-tool","title":"Create Journal Folder Tool","description":"Create a new journal folder in a campaign. Folders organize journal entries hierarchically; path is a \"\/\"-separated string that must be unique within the campaign. Only campaign owners\/admins can create folders.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"name":{"maxLength":255,"type":"string"},"path":{"maxLength":1024,"type":"string"},"parent_id":{"type":["string","null"]},"description":{"type":["string","null"]},"position":{"type":["integer","null"]},"metadata":{"type":["object","null"]}},"type":"object","required":["campaign_id","name","path"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"update-journal-folder-tool","title":"Update Journal Folder Tool","description":"Update a journal folder (PUT semantics). Only owners\/admins may write. path must stay unique within the campaign; setting parent_id to the folder's own id is rejected.","inputSchema":{"properties":{"folder_id":{"type":"string"},"name":{"maxLength":255,"type":["string","null"]},"path":{"maxLength":1024,"type":["string","null"]},"parent_id":{"type":["string","null"]},"description":{"type":["string","null"]},"position":{"type":["integer","null"]},"metadata":{"type":["object","null"]}},"type":"object","required":["folder_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"delete-journal-folder-tool","title":"Delete Journal Folder Tool","description":"Delete a journal folder. Journal entries in the folder are NOT deleted; their folder_id is set to null (they move to the campaign root).","inputSchema":{"properties":{"folder_id":{"type":"string"}},"type":"object","required":["folder_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"list-links-tool","title":"List Links Tool","description":"List links between entities in a campaign. Supports filtering by source\/target entity and relationship alias.","inputSchema":{"properties":{"page":{"minimum":1,"type":["integer","null"]},"size":{"minimum":1,"maximum":100,"type":["integer","null"]},"campaign_id":{"type":"string"},"from_id":{"type":["string","null"]},"from_type":{"type":["string","null"]},"to_id":{"type":["string","null"]},"to_type":{"type":["string","null"]},"alias":{"type":["string","null"]}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"data":{"description":"List of links records.","type":"array"},"total":{"description":"Total number of matching records.","type":"integer"},"page":{"description":"Current page number.","type":"integer"},"size":{"description":"Page size.","maximum":100,"type":"integer"},"pages":{"description":"Total number of pages.","type":"integer"}},"type":"object","required":["data"]}},{"name":"create-link-tool","title":"Create Link Tool","description":"Create a link (wikilink) between two entities in a campaign. Links represent relationships like a Character belonging to a Faction, a Location contained in another Location, or a Session referencing an Item. from_type may be Character\/Faction\/Location\/Item\/Moment\/GameSession\/Beat\/Backstory\/Journal\/World; to_type must be Character\/Faction\/Location\/Item\/Moment. The alias is the display text that gets wrapped as [[alias]] in the source record's text. If a link with the same (from_type, from_id, aliasNorm) already exists it will be updated (upsert).","inputSchema":{"properties":{"campaign_id":{"type":"string"},"from_id":{"type":"string"},"from_type":{"enum":["Character","Faction","Location","Item","Moment","GameSession","Beat","Backstory","Journal","World"],"type":"string"},"to_id":{"type":"string"},"to_type":{"enum":["Character","Faction","Location","Item","Moment"],"type":"string"},"alias":{"type":"string"}},"type":"object","required":["campaign_id","from_id","from_type","to_id","to_type","alias"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"from_id":{"type":"string"},"from_type":{"type":"string"},"to_id":{"type":"string"},"to_type":{"type":"string"},"alias":{"type":["string","null"]},"created_at":{"type":"string"}},"type":"object","required":["id","campaign_id","from_id","from_type","to_id","to_type","created_at"]}},{"name":"update-link-tool","title":"Update Link Tool","description":"Update an existing link's alias. Only the alias field can be changed via this tool; to change the source or target of a link, delete it and create a new one, or use bulk_link_maintenance to rename an alias campaign-wide.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"link_id":{"type":"string"},"alias":{"type":"string"}},"type":"object","required":["campaign_id","link_id","alias"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"id":{"type":"string"},"campaign_id":{"type":"string"},"from_id":{"type":"string"},"from_type":{"type":"string"},"to_id":{"type":"string"},"to_type":{"type":"string"},"alias":{"type":["string","null"]},"created_at":{"type":"string"}},"type":"object","required":["id","campaign_id","from_id","from_type","to_id","to_type","created_at"]}},{"name":"delete-link-tool","title":"Delete Link Tool","description":"Delete a single link between entities. This removes the Link record but does NOT rewrite the source record's text; any [[alias]] markup in the source description will remain until the source is next edited. Use bulk_link_maintenance with operation=remove if you also want the wikilink brackets stripped from all references to the target across the campaign.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"link_id":{"type":"string"}},"type":"object","required":["campaign_id","link_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"bulk-link-maintenance-tool","title":"Bulk Link Maintenance Tool","description":"Trigger campaign-wide wikilink maintenance for a target entity (Character\/Faction\/Location\/Item\/Moment). Operations: (1) add \u2014 introduce a new [[alias]] pointing at target_id in every text field currently containing that alias in plain form; (2) remove \u2014 unbracket every [[alias]] that resolves to target_id; (3) update \u2014 repoint every existing link to target_id to new_target_id, and\/or rename its alias to new_alias. The request is accepted (202) and forwarded to a background webhook; the response contains a task_id you can use to correlate downstream logs. Only the campaign owner can trigger this and the account must have an active subscription tier.","inputSchema":{"properties":{"operation":{"enum":["add","remove","update"],"type":"string"},"campaign_id":{"type":"string"},"target_id":{"type":"string"},"target_type":{"enum":["Character","Faction","Location","Item","Moment"],"type":"string"},"alias":{"maxLength":255,"type":["string","null"]},"new_alias":{"maxLength":255,"type":["string","null"]},"new_target_id":{"type":["string","null"]}},"type":"object","required":["operation","campaign_id","target_id","target_type"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"success":{"type":"boolean"},"task_id":{"type":["string","null"]}},"type":"object","required":["success"]}},{"name":"get-image-usage-tool","title":"Get Image Usage Tool","description":"Return the calling account's image feature quota for a campaign: `used`\/`limit` counts for the current billing cycle, `tier` name, `can_access` flag, and cycle window. Call this when you want to reason about headroom before an image operation that could 403 on a depleted or tier-locked quota.","inputSchema":{"properties":{"campaign_id":{"type":"string"}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"outputSchema":{"properties":{"used":{"type":"integer"},"limit":{"type":"integer"},"can_access":{"type":"boolean"},"feature_type":{"type":["string","null"]},"tier":{"type":"string"},"billing_cycle_start":{"type":["string","null"]},"billing_cycle_end":{"type":["string","null"]},"message":{"type":["string","null"]}},"type":"object","required":["used","limit","can_access","tier"]}},{"name":"init-image-upload-tool","title":"Init Image Upload Tool","description":"STEP 1 of the direct-upload flow. Ask the API to reserve an object key for the entity and presign an S3 PUT URL. `content_type` must be image\/* (jpeg, png, gif, webp, avif, heic, heif). Returns `{object_key, upload_url, public_url, expires_in_seconds}`. AFTER calling this, the client MUST issue an HTTP `PUT` to `upload_url` with the raw image bytes and the same `Content-Type` header before it expires (typically ~5 minutes). Once the PUT is complete, call `complete_image_upload` to finalize (moderate and optionally attach). Agents that cannot perform arbitrary HTTP PUTs should ask a human collaborator to do the PUT step.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"entity_type":{"enum":["campaign","world","character","faction","location","item","moment","session","gamesession"],"type":"string"},"entity_id":{"type":"string"},"file_name":{"minLength":1,"maxLength":255,"type":"string"},"content_type":{"minLength":1,"maxLength":100,"type":"string"}},"type":"object","required":["campaign_id","entity_type","entity_id","file_name","content_type"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"outputSchema":{"properties":{"object_key":{"type":"string"},"upload_url":{"type":"string"},"public_url":{"type":"string"},"expires_in_seconds":{"type":"integer"}},"type":"object","required":["object_key","upload_url","public_url","expires_in_seconds"]}},{"name":"complete-image-upload-tool","title":"Complete Image Upload Tool","description":"STEP 2 of the direct-upload flow. Call after successfully PUTting bytes to the presigned `upload_url` returned by `init_image_upload`. The API validates the object (size cap, image signature) and runs the same NSFW moderation pipeline used by the product UI \u2014 flagged uploads are deleted and the tool returns an error. When `attach` is true (default), the entity's image field is set to the resulting `public_url`. Returns `{url, attached}`.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"object_key":{"minLength":1,"maxLength":2048,"type":"string"},"entity_type":{"enum":["campaign","world","character","faction","location","item","moment","session","gamesession"],"type":"string"},"entity_id":{"type":"string"},"attach":{"type":["boolean","null"]}},"type":"object","required":["campaign_id","object_key","entity_type","entity_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true},"outputSchema":{"properties":{"url":{"type":"string"},"attached":{"type":"boolean"}},"type":"object","required":["url","attached"]}},{"name":"delete-entity-image-tool","title":"Delete Entity Image Tool","description":"Remove an image within a campaign. Provide EITHER `entity_type` + `entity_id` (detaches the image from that record AND deletes the underlying object) OR a managed `image_url` (deletes just that object). Valid entity types: campaign, world, character, faction, location, item, moment, session, gamesession. Returns `{removed: bool}`.","inputSchema":{"properties":{"campaign_id":{"type":"string"},"entity_type":{"enum":["campaign","world","character","faction","location","item","moment","session","gamesession"],"type":["string","null"]},"entity_id":{"type":["string","null"]},"image_url":{"maxLength":2048,"type":["string","null"]}},"type":"object","required":["campaign_id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true},"outputSchema":{"properties":{"removed":{"type":"boolean"}},"type":"object","required":["removed"]}}],"resources":[],"prompts":[]}