Skip to content
RECAP RAVEN
The Recap Raven MCP server is available now on plans with memory.

For custom AI workflows

Connect ChatGPT or Claude to your campaign memory.

Want to ask questions of your campaign from ChatGPT, Claude, Gemini or your own agent? Recap Raven’s MCP server exposes your campaign memory and AI answers as tools any MCP client can call — so the recap engine is reachable from wherever your agent lives.

What is MCP?

MCP lets apps like ChatGPT, Claude, Gemini, or your own agent call Recap Raven tools directly. Instead of copying recaps into another AI, your AI can ask Recap Raven for sessions, transcript windows, hooks, entities, quotes, and campaign answers.

Get started

Connect your MCP client to https://mcp.recapraven.com/mcp using a personal API key from your Recap Raven account area. Create or rotate keys from API Keys. You need a plan with memory. Choose your client to see the setup steps:

Most users only need this

  1. Create an API key.
  2. Add https://mcp.recapraven.com/mcp to your MCP client.
  3. Use Authorization: Bearer <your key>.
  4. Ask: “List my Recap Raven campaigns”.

MCP endpoint
https://mcp.recapraven.com/mcp
Authorization header
Authorization: Bearer raven_sk_...

ChatGPT Desktop setup

  1. In your Recap Raven account area, open API Keys → Create key. You need a plan with memory, and the key is shown once.
  2. Open ChatGPT Desktop → Settings → Connectors → Add a new connector.
  3. Set the URL to https://mcp.recapraven.com/mcp
  4. Set the Authorization header to: Bearer raven_sk_... (the key from step 1).
  5. Save, then start a chat — Recap Raven’s tools become available to ChatGPT.
  6. Test it by asking ChatGPT: “List my Recap Raven campaigns.”
ChatGPT settings summary
URL: https://mcp.recapraven.com/mcp
Authorization: Bearer <YOUR_RECAP_RAVEN_API_KEY>

Available on plans with memory

MCP is unavailable on Free and Recap Only. Most deterministic tool calls run on every memory plan (Premium, Studio, Pro) at no extra cost. Semantic search and AI answers spend your existing Ask credits.

MCP availability by plan
Free tierUnavailable
Recap OnlyUnavailable
Plans with memoryDeterministic tools at no extra cost; search_corpus uses low chat credits per search, and cited ask tools spend Ask credits.
API keyCreate one personal API key from API Keys. Revoke any time; keys are disabled if the account leaves a plan with memory.

Fair use & rate limits

The MCP server is a shared, metered surface. To keep it sustainable (and stop a runaway agent loop from burning a whole licence in minutes), every API key is rate-limited in addition to your Ask allowance.

MCP rate limits
Server fair-usePer-API-key request ceiling on the MCP server itself (all tool calls combined) — prevents a single key from flooding the endpoint. Responses over the limit return 429 with Retry-After.
Premium15 requests/minute and 150 requests/hour.
Studio30 requests/minute and 450 requests/hour.
Pro60 requests/minute and 1200 requests/hour.
Free toolsRate-limited per API key. Deterministic reads and keyword searches (search_transcript, search_facts) cost no credits. Semantic search_corpus is not included here; it uses low chat credits per completed search.
Chat-credit toolssearch_corpus (low chat credits) and cited ask tools are bounded by both your Ask allowance and a per-key rate limit. The usage gate stops spend when the allowance is exhausted; the rate limit stops a burst from draining it instantly. No separate MCP quota — your agent spends the same per-licence chat credits it uses in the app.

Included at no extra cost

Deterministic read tools — sessions, entities and the ledger, hooks, mechanics, engagement, transcript and beats search, recaps, lore and lexicon. They return stored campaign data with no AI inference, so they cost no credits on any memory plan. Semantic search_corpus is not included in this list; it uses low chat credits. Expand any tool for example input, example output and field reference.

list_campaignsIncluded with your memory plan

Discovery tool: list the campaigns available to your MCP key so other tools can use the right campaign_id.

Example input

{}

Example output

{
  "campaigns": [
    {
      "campaign_id": "a1b2c3d4-…",
      "name": "The White Moose",
      "module": "Dolmenwood"
    }
  ]
}
Field descriptions
FieldTypeDescription
campaignsarrayCampaigns owned by your account.
campaigns[].campaign_idstring (uuid)Use this id with campaign-scoped MCP tools.
campaigns[].namestringCampaign name.
campaigns[].modulestring | nullOptional module/system label.
list_sessionsIncluded with your memory plan

Discovery tool: list ready sessions with their session_number and title, so an agent can map "session 12" to the right recap_id.

Example input

{
  "campaign_id": "a1b2c3d4-…"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid) | omittedOptional campaign filter.

Example output

{
  "recaps": [
    {
      "recap_id": "r1e2c3a4-…",
      "campaign_id": "a1b2c3d4-…",
      "session_number": 12,
      "title": "The Choosing",
      "status": "ready"
    }
  ]
}
Field descriptions
FieldTypeDescription
recapsarrayReady sessions visible to your account.
recaps[].recap_idstring (uuid)Use this id with get_recap, get_transcript_window and get_mechanics_events.
recaps[].campaign_idstring (uuid) | nullCampaign that owns the session.
recaps[].session_numberinteger | nullThe GM’s own 1-based session numbering (DM-editable), when set.
recaps[].titlestring | nullSession title.
recaps[].statusstringOnly ready sessions are listed.
get_engagementIncluded with your memory plan

The campaign engagement dashboard: per-speaker participation trend and the cached cross-session synthesis (summary + key-events timeline).

Example input

{
  "campaign_id": "a1b2c3d4-…"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to read. Must be owned by your account.

Example output

{
  "sessions": [
    {
      "recap_id": "…",
      "session_ref": "S01AB",
      "session_at": "2026-06-20T19:00:00Z"
    }
  ],
  "players": [
    {
      "speaker": "Mira",
      "points": [
        {
          "session_ref": "S01AB",
          "participation_pct": 28.4,
          "turn_count": 42,
          "talk_time_seconds": 612,
          "word_count": 1840
        }
      ]
    }
  ]
}
Field descriptions
FieldTypeDescription
sessionsarrayOne entry per ready session in the campaign.
sessions[].recap_idstring (uuid)The recap/session id.
sessions[].session_refstringShort human reference, e.g. S01AB.
sessions[].session_atstring (ISO 8601)When the session started (UTC).
playersarrayOne entry per recognised speaker.
players[].speakerstringSpeaker display name.
players[].pointsarrayPer-session metrics for this speaker.
players[].points[].participation_pctnumberShare of conversation, 0–100.
players[].points[].turn_countintegerNumber of speaking turns taken.
players[].points[].talk_time_secondsintegerTotal seconds speaking.
players[].points[].word_countintegerTotal words spoken.
get_credit_balanceIncluded with your memory plan

Your Ask allowance as percentage used, plus a recent-activity feed. Raw allowance counts are not exposed to MCP clients.

Example input

{}

Example output

{
  "usage": {
    "percent_used": 29
  },
  "recent_activity": [
    {
      "type": "recap_ready",
      "label": "Session S01AB recap is ready",
      "date": "2026-06-21T08:02:00Z",
      "recap_id": "…"
    },
    {
      "type": "credit",
      "label": "Asked your campaign",
      "date": "2026-06-21T08:05:00Z"
    }
  ]
}
Field descriptions
FieldTypeDescription
usage.percent_usedintegerWhole-number Ask usage from 0 to 100.
recent_activityarrayNewest-first feed (session-recorded, recap-ready, credit-ledger events).
recent_activity[].typestringEvent kind.values: recap_ready | session_recorded | credit
recent_activity[].labelstringHuman-readable summary.
recent_activity[].datestring (ISO 8601)When the event occurred.
recent_activity[].recap_idstring (uuid) | nullPresent for recap/session-related events.
get_memory_overviewIncluded with your memory plan

Richest GM situational-awareness blob: distribution, engagement trend + overall score, per-session participation, pillars of play.

Example input

{
  "campaign_id": "a1b2c3d4-…"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to read.

Example output

{
  "distribution": [
    {
      "label": "Roleplay",
      "pct": 58
    }
  ],
  "engagement": {
    "overall": {
      "score": 74,
      "label": "Playful / tense"
    }
  },
  "pillars": [
    "The green-eyed stranger",
    "The old inn",
    "The white moose hunt"
  ]
}
Field descriptions
FieldTypeDescription
distributionarrayShare of play by category.
distribution[].labelstringCategory name.
distribution[].pctnumberShare, 0–100.
engagement.overall.scorenumber | nullComposite engagement score, 0–100.
engagement.overall.labelstring | nullQualitative label, e.g. "Playful / tense".
pillarsstring[] | nullRecurring themes / pillars of play.
get_open_hooksIncluded with your memory plan

Unresolved narrative hooks — what to prep next session.

Example input

{
  "campaign_id": "a1b2c3d4-…"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to read.

Example output

{
  "hooks": [
    {
      "text": "Nobody bypasses the Choosing.",
      "session_ref": "S01AB",
      "session_date": "2026-06-20"
    }
  ]
}
Field descriptions
FieldTypeDescription
hooksarrayCurrently open narrative hooks.
hooks[].textstringThe hook description.
hooks[].session_refstringSession where the hook was introduced.
hooks[].session_datestring (YYYY-MM-DD)Date of that session.
get_previously_onIncluded with your memory plan

Previously-on context for the campaign, built from owner-scoped memory.

Example input

{
  "campaign_id": "a1b2c3d4-…"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to read.

Example output

{
  "sections": [
    {
      "title": "Last time",
      "bullets": [
        "The party followed the white moose into the mist."
      ]
    }
  ]
}
Field descriptions
FieldTypeDescription
sectionsarrayCampaign memory sections for recap/context.
sections[].titlestringSection heading.
sections[].bulletsstring[]Concise memory bullets.
get_next_session_prep_packIncluded with your memory plan

GM-only next-session prep advisory from Recap Raven’s prep cache. It may generate once, then stays cached until the next recap is ingested. Returns credit_cost: 0.

Example input

{
  "campaign_id": "a1b2c3d4-…"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to prep. Must be owned by your account.

Example output

{
  "likely_directions": [
    {
      "title": "Return to the inn",
      "detail": "The unresolved clue points back to the old inn."
    }
  ],
  "threads_to_watch": [
    "Who opened the moonstone gate?"
  ],
  "prep_suggestions": [
    "Review the innkeeper and the gate password."
  ],
  "credit_cost": 0,
  "cache_policy": "cached_until_next_recap_ingested"
}
Field descriptions
FieldTypeDescription
likely_directionsarrayGM-facing likely next directions.
threads_to_watchstring[]Threads the GM may want to keep in mind.
prep_suggestionsstring[]Concrete prep prompts for the GM.
credit_costnumberAlways 0 for this MCP tool.
cache_policystringcached_until_next_recap_ingested.
get_chronicleIncluded with your memory plan

Scenes-per-session map — the structured campaign chronicle.

Example input

{
  "campaign_id": "a1b2c3d4-…"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to read.

Example output

{
  "sessions": [
    {
      "recap_id": "…",
      "session_ref": "S01AB",
      "scenes": [
        "The market",
        "The hunt",
        "The banshee fight"
      ]
    }
  ]
}
Field descriptions
FieldTypeDescription
sessionsarrayOne entry per session.
sessions[].recap_idstring (uuid)The recap/session id.
sessions[].scenesstring[]Ordered scene labels for that session.
get_entityIncluded with your memory plan

The player-visible entity ledger derived from recorded sessions; private uploaded lore is excluded. With no name it returns the roster. With a name or alias it returns the matching card, interaction history, transcript turn links, relations, or ambiguity candidates.

Example input

{
  "campaign_id": "a1b2c3d4-…",
  "name": "Captain Vale"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to read.
namestring | omittedEntity name/alias to resolve to a single card. Omit for the roster.

Example output

{
  "entity": {
    "id": "…",
    "canonical_name": "Captain Vale",
    "kind": "npc",
    "aliases": [
      "Vale"
    ],
    "search_aliases": [],
    "interactions": [
      {
        "recap_id": "…",
        "summary": "Vale warned the party.",
        "turn_start": 12,
        "turn_end": 16
      }
    ],
    "relations": [
      {
        "subject": "Captain Vale",
        "predicate": "located_in",
        "object": "Saltmoor Harbour",
        "recap_id": "…",
        "turn_start": 41,
        "turn_end": 44,
        "visibility": "player_known",
        "session_date": "2026-05-01T00:00:00Z",
        "is_current": true,
        "predicate_class": "stateful"
      }
    ]
  }
}
Field descriptions
FieldTypeDescription
entitiesarray (roster mode)When no name is given: {canonical_name, kind, aliases, search_aliases} for each entity.
entityobject | null (card mode)When a name is given: the resolved entity card, or null if the name matches nothing.
candidatesarrayPossible entity cards when an alias is ambiguous; empty when resolution is unique.
entity.idstring (uuid)Stable campaign entity id.
entity.canonical_namestringCanonical entity name.
entity.kindstringEntity kind.values: pc | npc | creature | place | item | faction | deity | other
entity.aliasesstring[]Display aliases.
entity.search_aliasesstring[]Retrieval-only aliases.
entity.interactionsarrayGrounded history entries with recap and transcript-turn links.
entity.interactions[].recap_idstring (uuid)Session containing the interaction.
entity.interactions[].turn_startinteger | nullFirst transcript turn for the evidence link.
entity.interactions[].turn_endinteger | nullLast transcript turn for the evidence link.
entity.interactions[].identity_matchstringconfirmed or suggested; suggested links are possible alias matches, not canonical identity claims.values: confirmed | suggested
entity.relationsarrayRelations graph (oldest → newest).
entity.relations[].predicatestringe.g. located_in, ally_of, owns.
entity.relations[].recap_idstring (uuid)Session that evidences the relation.
entity.relations[].visibilitystringGM-visibility of the edge. Legacy pre-witness data can carry dm_only edges — do not surface to players.values: player_known | dm_only
entity.relations[].is_currentbooleanThe live leg of a stateful predicate.
get_mechanics_eventsIncluded with your memory plan

Turn-anchored mechanics events (attacks, spells, damage, rests, conditions) for one session — the same data as the mechanics tab.

Example input

{
  "recap_id": "…"
}
Field descriptions
FieldTypeDescription
recap_idstring (uuid)The session to read. Use list_sessions to discover ids.

Example output

{
  "recap_id": "…",
  "mechanics": [
    {
      "action": "attack",
      "actor": "Mira",
      "target": "Goblin",
      "damage_amount": 7,
      "damage_type": "slashing",
      "evidence_turn_start": 41,
      "evidence_turn_end": 41
    }
  ]
}
Field descriptions
FieldTypeDescription
recap_idstring (uuid)The session these events belong to.
mechanicsarrayTurn-anchored mechanics events.
mechanics[].actionstringEvent kind.values: attack | spell_cast | short_rest | long_rest | consumable_used | condition_applied | ability_used | form_changed
mechanics[].actorstringWho acted.
mechanics[].evidence_turn_startintegerFirst turn evidencing the event.
mechanics[].evidence_turn_endintegerLast turn evidencing the event.
get_lore_documentsIncluded with your memory plan

The list of lore documents for the campaign.

Example input

{
  "campaign_id": "a1b2c3d4-…"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to read.

Example output

{
  "documents": [
    {
      "id": "…",
      "title": "The Choosing",
      "updated_at": "2026-06-20"
    }
  ]
}
Field descriptions
FieldTypeDescription
documentsarrayLore documents.
documents[].idstring (uuid)Document identifier.
documents[].titlestringDocument title.
get_lore_documentIncluded with your memory plan

A single lore document with its full body.

Example input

{
  "campaign_id": "a1b2c3d4-…",
  "doc_id": "…"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to read.
doc_idstring (uuid)The lore document to fetch.

Example output

{
  "document": {
    "id": "…",
    "title": "The Choosing",
    "body": "…"
  }
}
Field descriptions
FieldTypeDescription
document.idstring (uuid)Document identifier.
document.titlestringDocument title.
document.bodystringFull document body (markdown).
get_lexiconIncluded with your memory plan

Lexicon entries (canonical names, aliases, type, confidence).

Example input

{
  "campaign_id": "a1b2c3d4-…"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to read.

Example output

{
  "entries": [
    {
      "id": "…",
      "canonical": "Sol’Thun",
      "type": "npc",
      "aliases": [
        "the archmage"
      ],
      "confidence": 0.92,
      "enabled": true
    }
  ]
}
Field descriptions
FieldTypeDescription
entriesarrayLexicon entries.
entries[].canonicalstringCanonical name.
entries[].typestringEntity kind.values: npc | place | item | creature | other
entries[].aliasesstring[]Alternate names / aliases.
entries[].confidencenumberExtraction confidence, 0–1.
entries[].enabledbooleanWhether this entry is active.
get_transcript_windowIncluded with your memory plan

A positional slice of a session’s stored turns (no content search — just from/to turn indices).

Example input

{
  "recap_id": "…",
  "from": 0,
  "to": 20
}
Field descriptions
FieldTypeDescription
recap_idstring (uuid)The recap/session to read. Use list_sessions to discover ids.
fromintegerStart turn index (inclusive, default 0).
tointegerEnd turn index. Omit for a 50-turn window from the start index.

Example output

{
  "recap_id": "…",
  "total_turns": 184,
  "from": 0,
  "to": 20,
  "turns": [
    {
      "index": 0,
      "t": "~00:01",
      "speaker": "GM",
      "text": "…"
    }
  ]
}
Field descriptions
FieldTypeDescription
total_turnsintegerTotal turns in the session.
fromintegerStart index returned.
tointegerEnd index returned.
turnsarrayTurns in the requested window.
turns[].indexintegerPositional index in the session.
turns[].tstringRelative timestamp, e.g. ~00:01.
turns[].speakerstringSpeaker display name.
turns[].textstringThe spoken text.
get_recapIncluded with your memory plan

The player-safe recap HTML for a ready recap. The artifact type is server-owned; there is no type input.

Example input

{
  "recap_id": "…"
}
Field descriptions
FieldTypeDescription
recap_idstring (uuid)The recap/session whose player-safe recap should be fetched.

Example output

{
  "recap": {
    "recap_id": "…",
    "content_type": "player_recap_html",
    "html": "<!doctype html>…",
    "truncated": false
  }
}
Field descriptions
FieldTypeDescription
recap.recap_idstring (uuid)The recap/session id.
recap.content_typestringAlways player_recap_html.values: player_recap_html
recap.htmlstringThe player-safe recap HTML.
recap.truncatedbooleanTrue when the MCP response cap trimmed the HTML.
search_transcriptIncluded with your memory plan

Exact keyword (full-text) search over your campaign transcript turns. Returns turns containing the exact phrase, with their session, speaker and timestamp — no LLM, no embedding, no credits.

Example input

{
  "campaign_id": "a1b2c3d4-…",
  "query": "white moose",
  "recap_id": "r1e2c3a4-…"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to search.
querystringExact phrase to match (full-text search against transcript text).
recap_idstring (uuid) | omittedOptional session scope. Use list_sessions to discover recap ids.

Example output

{
  "query": "white moose",
  "matches": [
    {
      "recap_id": "…",
      "speaker": "GM",
      "t": "~01:04",
      "text": "All you know is that it’s a white moose."
    }
  ]
}
Field descriptions
FieldTypeDescription
querystringEcho of the submitted query.
matchesarrayTranscript turns containing the exact phrase, best match first.
matches[].recap_idstring (uuid)Recap/session the match came from.
matches[].speakerstringSpeaker of the matched turn.
matches[].tstringRelative timestamp, e.g. ~01:04.
matches[].textstringThe matched transcript text.
search_factsIncluded with your memory plan

Keyword full-text search over your campaign’s scene beats — the dense, beat-by-beat summaries the chat lane reasons over. Best for exact terms (a name, an item, a place). Returns beat text with its scene/session context and turn range, so an agent can locate the moment and pull the exact transcript window next. No LLM, no embedding, no credits. For natural-language, meaning-based lookup use search_corpus.

Example input

{
  "campaign_id": "a1b2c3d4-…",
  "query": "white moose hunt",
  "recap_id": "r1e2c3a4-…"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to search.
querystringKeywords to match against beat text (full-text search).
recap_idstring (uuid) | omittedOptional session scope. Use list_sessions to discover recap ids.

Example output

{
  "matches": [
    {
      "recap_id": "…",
      "session_number": 12,
      "session_title": "The Choosing",
      "scene_title": "The hunt",
      "beat_index": 3,
      "turn_start": 120,
      "turn_end": 168,
      "text": "The party tracked the white moose north of the old inn…",
      "truncated": false
    }
  ]
}
Field descriptions
FieldTypeDescription
matchesarrayMatching beats, best match first.
matches[].recap_idstring (uuid)Session the beat came from.
matches[].session_numberinteger | nullThe GM’s session number, when set.
matches[].session_titlestring | nullThe session’s title, when set.
matches[].scene_titlestring | nullTitle of the scene the beat belongs to.
matches[].beat_indexintegerThe beat’s position within its scene.
matches[].turn_startintegerFirst turn of the beat’s window (feed into get_transcript_window).
matches[].turn_endintegerLast turn of the beat’s window.
matches[].textstringThe beat text (capped at 1200 chars).
matches[].truncatedbooleanTrue when the beat text was trimmed.

Uses chat credits

Three tools spend metered chat credits. Think finder vs answer: search_corpus (low chat credits) hands you the strongest matches as structured evidence for your own model to reason over — a fast finder, not an exhaustive index; ask_campaign_cited answers a GM-facing question with verbatim transcript quotes and turn citations; and ask_player_campaign_cited gives the shorter player-facing version through the player lane. All are rate-limited per API key in addition to your balance.

search_corpusUses low chat credits

search_corpus finds relevant campaign moments even when you do not know the exact wording. It uses semantic search and reranking to return the strongest evidence matches, including summary, session context and turn ranges. It is a finder, not an exhaustive index: only the top matches come back, so treat an empty or thin result as “nothing strong surfaced,” not proof that nothing exists. Use the matches to discover the real terms or names the table used, then run an exhaustive free keyword search with search_facts / search_transcript, or take the turn ranges straight to get_transcript_window for the verbatim segment. For a definitive, verified answer to a question — verbatim quotes and citations — use ask_campaign_cited instead (pricier, a written reply rather than structured rows). Set player_safe: true to exclude GM-only content from search results. It uses low chat credits per search, charged on any completed search, even one with no matches.

Example input

{
  "campaign_id": "a1b2c3d4-…",
  "query": "when did the party first distrust the mayor?",
  "player_safe": false
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to search.
querystringA natural-language description of what you’re looking for.
player_safeboolean (default false)When true, the retrieval is visibility-filtered — GM-only, inferred and speculation memory and GM-typed lore are excluded. Use for anything players will see.

Example output

{
  "matches": [
    {
      "object_id": "…",
      "type": "plot_event",
      "visibility": "player_known",
      "recap_id": "…",
      "session_number": 8,
      "session_title": "The Mayor’s Bargain",
      "turn_start": 212,
      "turn_end": 240,
      "text": "The party noticed the mayor’s story about the missing caravan didn’t add up…",
      "truncated": false
    }
  ],
  "credit_cost": "<chat credits charged for this search>"
}
Field descriptions
FieldTypeDescription
matchesarrayRanked memory matches, best match first.
matches[].object_idstring (uuid)The memory object’s id.
matches[].typestringThe kind of memory (e.g. plot_event, npc_fact).
matches[].visibilitystringWho knows this. On a player_safe search it is only ever player-visible.
matches[].recap_idstring (uuid) | nullThe session the memory came from.
matches[].session_numberinteger | nullThe GM’s session number, when set.
matches[].session_titlestring | nullThe session’s title, when set.
matches[].turn_startinteger | nullFirst turn of the evidence window (feed into get_transcript_window).
matches[].turn_endinteger | nullLast turn of the evidence window.
matches[].textstringThe memory summary (capped at 1200 chars).
matches[].truncatedbooleanTrue when the summary was trimmed.
credit_costnumberChat credits charged for this completed search.
ask_campaign_citedUses chat credits

Ask your campaign a GM-facing factual question and get the AI answer — the same beats answer engine as in-app chat, with verbatim transcript quotes and turn citations. Uses GM chat credits, the same cost as in-app chat. Rate-limited per API key in addition to your balance.

Example input

{
  "campaign_id": "a1b2c3d4-…",
  "question": "Where did the hunter see the moose?"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to ask.
questionstringYour question.
clarificationobject | omittedOptional: answer a clarifying question the engine asked (GM lane only).
clarification.questionstringThe clarifying question from the engine.
clarification.answerstringYour answer to that question.
supersedesstring | omittedMessage id of a prior answer to replace (GM lane only).

Example output

{
  "answer_markdown": "The hunter reported seeing the white moose near the old inn to the north of town [1].",
  "quotes": [
    {
      "turn": 104,
      "speaker": "Skoll",
      "text": "All you know is that it’s a white moose.",
      "recap_id": "…"
    }
  ],
  "confidence_label": "high",
  "credit_cost": 1
}
Field descriptions
FieldTypeDescription
answer_markdownstringThe cited answer, with inline [n] markers.
citationsarrayCitation metadata backing each marker.
quotesarrayVerbatim transcript quotes used as evidence.
confidence_labelstringCoarse confidence band.values: high | medium | low
credit_costnumberCredits charged for this answer.
quotes[].turnintegerThe cited turn index.
quotes[].recap_idstring (uuid) | nullThe session the quote came from.
ask_player_campaign_citedUses chat credits

Ask a player-facing factual campaign question and get a short player-safe answer with transcript citations. GM-only content is excluded by the server-side player lane. Uses player chat credits.

Example input

{
  "campaign_id": "a1b2c3d4-…",
  "question": "What do we know about the harbour?"
}
Field descriptions
FieldTypeDescription
campaign_idstring (uuid)The campaign to ask.
questionstringYour question.

Example output

{
  "answer_markdown": "The party knows the harbourmaster helped them find the missing crate [1].",
  "quotes": [
    {
      "turn": 104,
      "speaker": "Skoll",
      "text": "The harbourmaster pointed us to the crate.",
      "recap_id": "…"
    }
  ],
  "confidence_label": "medium",
  "credit_cost": 1
}
Field descriptions
FieldTypeDescription
answer_markdownstringThe cited answer, with inline [n] markers.
citationsarrayCitation metadata backing each marker.
quotesarrayVerbatim transcript quotes used as evidence.
confidence_labelstringCoarse confidence band.values: high | medium | low
credit_costnumberCredits charged for this answer.

Player-safe example

Building a player-facing bot or overlay? Use the player cited tool so the answer comes from the player lane, whose visibility-filtered ledger never includes GM-only content:

{
  "tool": "ask_player_campaign_cited",
  "arguments": {
    "campaign_id": "a1b2c3d4-…",
    "question": "What do we know about the harbour?"
  }
}

Where your data goes

When you connect an MCP client and use these tools, your campaign content is sent to the AI client you chose — for example ChatGPT, Claude or Gemini. That provider’s data-use and training terms apply to what you send it, not ours.

Recap Raven’s no-training guarantee covers our own pipeline and the model providers we disclose. It cannot cover a client you connect: by wiring one up you are choosing a new processor for your campaign data. Please check that client’s terms before you connect it, and use ask_player_campaign_cited or player-safe search filters (and avoid GM-only reads like lore and chronicle) for anything players will see.

Questions or feedback? See how Recap Raven works or invite the bot below.

Run Recap Raven at your next session

Invite the bot now, create your campaign, and use your first complete recording free.

Run Recap Raven at your next session

No card required · Record only with your table’s consent · Delete or export your data anytime

Questions or feedback? Join our Discord community →

Built for Discord voice. We capture the whole session for you — no logging in afterwards, no files to send us, and no guessing who spoke. Memory plans keep your editable world wiki current as you play, ready for questions about what happened, who said what, open hooks, and what to prep next.