Skip to content
vviinn DocsDocs Beta

Conversation Memory

Conversation memory is a subsystem that provides durable, append-only, per-conversation logs. It offers a structured way for agents to store and retrieve working memory, allowing conversations to persist and evolve over time. It supports appending new items and offers various read access patterns, including recalling recent history (recall_memory), replaying full conversations (replay_memory), and listing available conversations (list_conversations).

All conversation memory operations require Basic authentication. Clients using Bearer tokens will be rejected at the tool layer.

The core data structures in the conversation memory subsystem define how data is stored and accessed.

An opaque, pseudonymous handle for a conversation, validated at construction. It must be:

  • An opaque string of 8–64 characters from [A-Za-z0-9_-].
  • Client-chosen and stable for the duration of a single conversation.
  • Never derived from personal data.

Invalid input is a hard error, ensuring that malformed IDs do not silently lead to orphaned data.

A per-conversation sequence number, assigned in strict append order. Sequence numbers are 0-based and gapless within a single conversation.

Represents a single appended record in a conversation’s memory log:

  • seq: The sequence number assigned to this item.
  • recorded_at: The server-side commit time for the item. All items within the same batch share the same recorded_at timestamp.
  • payload: The stored value, always a JSON object. Its keys make the item self-describing. Contents are stored verbatim and are not interpreted by the system, allowing for flexible data structures.

The public API representation of a MemoryItem, as returned by recall_memory and replay_memory. For its full schema, refer to McpMemoryItem in MCP Data Types.

A witness of a committed append operation, representing an inclusive contiguous sequence range [first, last] for a batch of items. This range is non-empty by construction, as empty batches are rejected.

Defines how items are selected from a conversation’s log during a read operation:

  • Tail { count }: Selects the last count items in ascending sequence order. Returns fewer items if the log contains less than count.
  • Range { start, limit }: Selects up to limit items starting from the specified start sequence number. Returns fewer items at the end of the log, or an empty list if start is past the end.

An opaque keyset position used to paginate conversation listings. It captures the last_appended_at timestamp and conversation_id of the last conversation in a previous page.

Defines how a listing selects one bounded read of a site’s conversations:

  • cursor: An optional ListCursor to resume the listing strictly after this position. None starts the listing from the most recently active conversation.
  • limit: The maximum number of conversation summaries to return in one page.

One bounded read of a site’s conversation listing, containing:

  • summaries: A list of ConversationSummary objects, ordered by last_appended_at descending, with ties broken by ascending conversation_id.
  • next_cursor: An optional ListCursor to continue the listing; None once the listing is exhausted.

Provides metadata about a conversation without retrieving its full content:

  • conversation_id: The ID of the conversation.
  • created_at: The recorded_at timestamp of the first item in the conversation.
  • last_appended_at: The recorded_at timestamp of the last item in the conversation.

The public API representation of a ConversationSummary, as returned by list_conversations. For its full schema, refer to McpConversationSummary in MCP Data Types.

To prevent resource exhaustion and ensure predictable performance, conversation memory enforces several capacity limits:

  • Per-item payload: Individual item payloads are capped at 256 KiB.
  • Per-batch total payload: The sum of all item payloads in a single append batch is capped at 1 MiB.
  • Per-conversation item count: A single conversation can store a maximum of 100,000 items.

Attempts to exceed these limits are rejected with specific errors (see Error Handling).

The append_memory tool allows agents to append batches of items to a conversation’s durable memory log.

Append a batch of items to a conversation’s durable, ordered memory log and receive the assigned sequence range (first_seq to last_seq, inclusive) as the durability acknowledgment. Each item is one self-describing JSON object, stored verbatim; the batch commits atomically and in order. The conversation_id is a pseudonymous handle the client mints itself: an opaque string of 8-64 characters from [A-Za-z0-9_-] (UUIDs and nanoids fit), stable for one conversation, and never derived from personal data such as names, e-mail addresses, or account ids. This tool requires Basic authentication. The maximum size for a single item payload is 256 KiB, and the total payload size for a batch is 1 MiB. A conversation can hold a maximum of 100,000 items. Memory must never block the conversation: the append acknowledgment is a durability signal, not flow control. Validation errors are permanent; any other failure is safe to retry after buffering the batch, and duplicates from retries are tolerated.

{
"properties": {
"conversation_id": {
"description": "The pseudonymous handle of the conversation to append to, minted by the client: 8-64 characters from `[A-Za-z0-9_-]`, stable for one conversation, never derived from personal data. A malformed id is rejected outright — it never falls back to a fresh conversation.",
"type": "string"
},
"items": {
"description": "The items to remember, in order. Each item is one JSON object whose keys make it self-describing; contents are stored verbatim, never interpreted. The batch commits atomically — all items or none — and must not be empty.",
"items": {
"additionalProperties": true,
"type": "object"
},
"maxItems": 250,
"minItems": 1,
"type": "array"
}
},
"required": [
"conversation_id",
"items"
],
"title": "AppendMemoryRequest",
"type": "object"
}
{
"properties": {
"first_seq": {
"description": "Sequence number assigned to the first item of the batch. Sequence numbers are per conversation, 0-based, gapless, in append order.",
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"last_seq": {
"description": "Sequence number assigned to the last item of the batch; the batch occupies the inclusive range `[first_seq, last_seq]`.",
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"first_seq",
"last_seq"
],
"title": "AppendMemoryResponse",
"type": "object"
}

The recall_memory tool allows agents to retrieve the most recent items from a conversation’s memory log.

Return the most recent items of a conversation’s durable, ordered memory log — the everyday way a client rehydrates recent context at the start of a session or after a gap. The response carries the last count items in ascending sequence order, so the oldest of the returned tail comes first; count defaults to 50 (max 1000), and a log holding fewer items returns them all. A conversation with no items — including one never appended to — reads as an empty list, not an error, so a fresh conversation id needs no special-casing. To read the log from a chosen position, or rebuild a conversation from the start, use replay_memory; to discover which conversations exist for your site, use list_conversations. The conversation_id is a pseudonymous handle the client mints itself: an opaque string of 8-64 characters from [A-Za-z0-9_-] (UUIDs and nanoids fit), stable for one conversation, and never derived from personal data such as names, e-mail addresses, or account ids. This tool requires Basic authentication. Memory must never block the conversation: the append acknowledgment is a durability signal, not flow control. Validation errors are permanent; any other failure is safe to retry after buffering the batch, and duplicates from retries are tolerated.

{
"properties": {
"conversation_id": {
"description": "The pseudonymous handle of the conversation to read, minted by the\nclient: 8-64 characters from `[A-Za-z0-9_-]`, stable for one\nconversation, never derived from personal data. A malformed id is\nrejected outright; an unknown one reads as an empty list.",
"type": "string"
},
"count": {
"default": 50,
"description": "How many items to return, counted from the end of the log: the last\n`count` items in ascending sequence order, fewer if the log holds\nfewer, none for `0`. Defaults to 50.",
"format": "uint64",
"maximum": 1000,
"minimum": 0,
"type": "integer"
}
},
"required": [
"conversation_id"
],
"title": "RecallMemoryRequest",
"type": "object"
}
{
"$defs": {
"McpMemoryItem": {
"properties": {
"payload": {
"additionalProperties": true,
"description": "The remembered JSON object, exactly as it was appended — contents are\nstored verbatim, never interpreted.",
"type": "object"
},
"recorded_at": {
"description": "Server-side commit time of the item's batch, as an RFC3339 timestamp;\nall items appended in one batch share it.",
"type": "string"
},
"seq": {
"description": "Sequence number of the item: per conversation, 0-based, gapless, in\nappend order.",
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"seq",
"recorded_at",
"payload"
],
"type": "object"
}
},
"properties": {
"items": {
"description": "The recalled items in ascending sequence order. Empty when the\nconversation holds no items — including one never appended to.",
"items": {
"$ref": "#/$defs/McpMemoryItem"
},
"type": "array"
}
},
"required": [
"items"
],
"title": "RecallMemoryResponse",
"type": "object"
}

The replay_memory tool allows agents to rebuild a conversation’s state from a known position.

Return a conversation’s durable, ordered memory log from a given position onward, in ascending sequence order — the read that rebuilds conversation state from the record, for example restoring a conversation after a restart. The response carries up to limit items starting at sequence number offset; offset defaults to 0. Fewer than limit items come back at the end of the log (max 1000), and a page shorter than limit — including an empty one — means the end was reached; an offset past the end reads as an empty list. To restore a whole conversation, start at offset 0, after each page continue at the last returned item’s sequence number plus one, and stop at the first page shorter than limit. Sequence numbers are per conversation, 0-based, and gapless, so the sequence number doubles as the offset — there is no cursor token. A conversation with no items — including one never appended to — reads as an empty list, not an error. For the everyday read of the most recent items, to rehydrate recent context, use recall_memory; to discover which conversations exist for your site, use list_conversations. The conversation_id is a pseudonymous handle the client mints itself: an opaque string of 8-64 characters from [A-Za-z0-9_-] (UUIDs and nanoids fit), stable for one conversation, and never derived from personal data such as names, e-mail addresses, or account ids. This tool requires Basic authentication. Memory must never block the conversation: the append acknowledgment is a durability signal, not flow control. Validation errors are permanent; any other failure is safe to retry after buffering the batch, and duplicates from retries are tolerated.

{
"properties": {
"conversation_id": {
"description": "The pseudonymous handle of the conversation to read, minted by the\nclient: 8-64 characters from `[A-Za-z0-9_-]`, stable for one\nconversation, never derived from personal data. A malformed id is\nrejected outright; an unknown one reads as an empty list.",
"type": "string"
},
"limit": {
"description": "Maximum number of items to return, in ascending sequence order\nstarting at `offset`. A page shorter than `limit` — including an\nempty one — signals that the end of the log was reached.",
"format": "uint64",
"maximum": 1000,
"minimum": 0,
"type": "integer"
},
"offset": {
"default": 0,
"description": "Sequence number to start reading from; sequence numbers are per\nconversation, 0-based, and gapless, so this is also the position in\nthe log. Defaults to 0.",
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"conversation_id",
"limit"
],
"title": "ReplayMemoryRequest",
"type": "object"
}
{
"$defs": {
"McpMemoryItem": {
"properties": {
"payload": {
"additionalProperties": true,
"description": "The remembered JSON object, exactly as it was appended — contents are\nstored verbatim, never interpreted.",
"type": "object"
},
"recorded_at": {
"description": "Server-side commit time of the item's batch, as an RFC3339 timestamp;\nall items appended in one batch share it.",
"type": "string"
},
"seq": {
"description": "Sequence number of the item: per conversation, 0-based, gapless, in\nappend order.",
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"seq",
"recorded_at",
"payload"
],
"type": "object"
}
},
"properties": {
"items": {
"description": "The items from `offset` onward, in ascending sequence order. Fewer\nthan `limit` items means the end of the log was reached. An unknown\nconversation or an `offset` past the end yields an empty list.",
"items": {
"$ref": "#/$defs/McpMemoryItem"
},
"type": "array"
}
},
"required": [
"items"
],
"title": "ReplayMemoryResponse",
"type": "object"
}

The list_conversations tool allows agents to discover which conversations exist for their site.

List the conversations stored for the authenticated site: each with its id and its created and last-appended timestamps, ordered most-recently-active first. It returns no item contents — to read a conversation’s contents use recall_memory (recent items) or replay_memory (from a chosen position); to check whether a specific already-known conversation has anything stored, a non-empty recall_memory is the existence check. This tool is for discovering which conversations exist, not for probing one you already know. Results are bounded: limit caps one call and defaults to 50 (max 1000); when more remain, next_cursor is returned — pass it back as cursor to continue, and a null next_cursor marks the end of the listing. This lists only your authenticated site’s conversations; there is no hard isolation below the site — to keep two sets of conversations hard-separated, use separate sites. The conversation_id is a pseudonymous handle the client mints itself: an opaque string of 8-64 characters from [A-Za-z0-9_-] (UUIDs and nanoids fit), stable for one conversation, and never derived from personal data such as names, e-mail addresses, or account ids. This tool requires Basic authentication. Memory must never block the conversation: the append acknowledgment is a durability signal, not flow control. Validation errors are permanent; any other failure is safe to retry after buffering the batch, and duplicates from retries are tolerated.

{
"properties": {
"cursor": {
"default": null,
"description": "An opaque continuation token from a previous response's next_cursor;\nomit to start from the most recently active conversation.",
"type": [
"string",
"null"
]
},
"limit": {
"default": 50,
"description": "Maximum number of conversations to return in one call. Defaults to\n50.",
"format": "uint64",
"maximum": 1000,
"minimum": 0,
"type": "integer"
}
},
"title": "ListConversationsRequest",
"type": "object"
}
{
"$defs": {
"McpConversationSummary": {
"properties": {
"conversation_id": {
"description": "The pseudonymous conversation id, exactly as minted by the client.",
"type": "string"
},
"created_at": {
"description": "When the conversation's first item was recorded, as an RFC3339\ntimestamp.",
"type": "string"
},
"last_appended_at": {
"description": "When the conversation's most recent item was recorded, as an RFC3339\ntimestamp — the field the list is ordered by, most recent first.",
"type": "string"
}
},
"required": [
"conversation_id",
"created_at",
"last_appended_at"
],
"type": "object"
}
},
"properties": {
"conversations": {
"description": "The next conversations of your site's listing, ordered\nmost-recently-active first. Each entry carries only its id and\ntimestamps, never stored items.",
"items": {
"$ref": "#/$defs/McpConversationSummary"
},
"type": "array"
},
"next_cursor": {
"description": "Opaque token to pass back as `cursor` to continue the listing; `null`\nonce the listing is exhausted.",
"type": [
"string",
"null"
]
}
},
"required": [
"conversations"
],
"title": "ListConversationsResponse",
"type": "object"
}

Operations on conversation memory can result in specific errors, categorized for client handling:

  • InvalidConversationId: Indicates a malformed ConversationId. This is a client fault and a permanent error.
  • EmptyBatch: Occurs when an append batch contains zero payloads. This is a client fault and a permanent error.
  • PayloadTooLarge: An individual item payload exceeds the 256 KiB limit. This is a client fault and a permanent error.
  • BatchTooLarge: The total payload size of an append batch exceeds the 1 MiB limit. This is a client fault and a permanent error.
  • ConversationFull: Appending items would cause the conversation to exceed its 100,000 item limit. This is a client fault and a permanent error.
  • Unavailable: Signifies that the memory storage backend is currently unavailable. This is a retryable error.
  • Timeout: An append operation timed out while waiting for conversation access. This is a retryable error.
  • Io: Represents an I/O error during memory storage operations. This is a retryable error.
  • Corrupted: Indicates that the conversation log is corrupted at a specific byte offset. This is a permanent error.

Detailed reasons for an InvalidConversationId:

  • TooShort: The ID length is below the minimum requirement.
  • TooLong: The ID length exceeds the maximum allowed.
  • InvalidCharacters: The ID contains characters outside the allowed charset [A-Za-z0-9_-].