fix(mcp): expose dreaming status and clarify document acceptance

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
MaheshtheDev 2026-10-26 18:54:22 +00:00
parent f355dc8039
commit 944471824a
7 changed files with 44 additions and 11 deletions

View file

@ -55,9 +55,17 @@ The client discovers the OAuth authorization server through
| `list_memories` | List extracted memory entries and their source document IDs |
| `list_spaces` | List spaces visible to the authenticated account |
| `who_am_i` | Return identity, access, and active-space context |
| `add_memory` | Save a memory (legacy `action: "forget"` remains supported) |
| `add_memory` | Accept a document for asynchronous memory extraction (legacy `action: "forget"` remains supported) |
| `forget_memory` | Forget a memory matching the supplied content |
`add_memory` success confirms document acceptance, not extracted or searchable
memories. In `list_documents` and `get_document`, `status: done` means content
processing completed. The separate `dreamingStatus`, when returned by the API,
is `dreaming` while generation is pending, running, or awaiting recovery after
failure, and `done` when generation settled or no memories were needed. Neither
field guarantees a nonzero memory count or that memory-vector writes finished.
These tools pass through the existing API signal without additional requests.
### MCP App launchers
| Tool | Purpose |

View file

@ -40,6 +40,7 @@ export interface DocumentSummary {
title: string | null
type: string
status: string
dreamingStatus?: ListResponseDocumentsItem["system"]["dreamingStatus"]
createdAt: string
updatedAt: string
summary: string | null
@ -111,6 +112,7 @@ function mapDocumentSummary(
title: document.title,
type: document.type,
status: document.system.status,
dreamingStatus: document.system.dreamingStatus,
createdAt: document.system.createdAt,
updatedAt: document.system.updatedAt,
summary: document.summary,

View file

@ -43,6 +43,9 @@ export function formatDocumentsList(response: DocumentsListResponse): string {
const lines = [
`- [${document.id}] "${title}" (${document.type}, ${document.status}, ${day(document.createdAt)})`,
]
if (document.dreamingStatus) {
lines.push(` dreamingStatus: ${document.dreamingStatus}`)
}
if (document.summary?.trim()) {
lines.push(` Summary: ${compactText(document.summary)}`)
}
@ -148,6 +151,9 @@ export function formatDocument(document: DocumentDetails): string {
`Document ID: ${document.id}`,
`Type: ${document.type}`,
`Status: ${document.system.status}`,
...(document.system.dreamingStatus
? [`dreamingStatus: ${document.system.dreamingStatus}`]
: []),
`Created: ${document.system.createdAt}`,
`Updated: ${document.system.updatedAt}`,
]

View file

@ -31,7 +31,7 @@ export function register(deps: ToolDeps) {
"add_memory",
{
description:
"Save a memory in the user's ACTIVE space. The target space is the one the user selected via select-space; pass namespace only to override it. To remove outdated information, use the separately exposed forget_memory tool. Legacy action='forget' remains supported for existing clients.",
"Accept a document for asynchronous memory extraction in the user's ACTIVE space. A successful response confirms document acceptance, not extracted or searchable memories. Use get_document or list_documents to check dreamingStatus; status=done refers to content processing only. The target space is the one the user selected via select-space; pass namespace only to override it. To remove outdated information, use the separately exposed forget_memory tool. Legacy action='forget' remains supported for existing clients.",
inputSchema,
outputSchema: addMemoryOutputSchema,
annotations: MEMORY_TOOL_ANNOTATIONS,
@ -43,7 +43,7 @@ export function register(deps: ToolDeps) {
const client = deps.getClient(namespace)
const result = await client.createMemory(args.content)
const message = `Memory saved (ID: ${result.id}, space: ${result.namespace})`
const message = `Document accepted (ID: ${result.id}, space: ${result.namespace}). Memory extraction is asynchronous and may still be queued or pending. Check dreamingStatus with get_document or list_documents; completion does not guarantee extracted or searchable memories.`
const structuredContent: AddMemoryOutput = withLegacyNamespace({
action: "save",
success: true,

View file

@ -31,7 +31,7 @@ export function register(deps: ToolDeps) {
{
title: "Get Document",
description:
"Read one stored document by ID from one space, including its summary and available content. Get document IDs from list_documents or from the document shown on a search_memory result. When the document is in a named space, resolve it with list_spaces and pass namespace; otherwise use the active space.",
"Read one stored document by ID from one space, including its summary, available content, and dreamingStatus when available. status=done means content processing completed, not memory readiness. dreamingStatus=dreaming means memory generation is pending, running, or awaiting recovery after failure; done means generation settled or none was needed, not guaranteed search readiness or nonzero memories. Get document IDs from list_documents or from the document shown on a search_memory result. When the document is in a named space, resolve it with list_spaces and pass namespace; otherwise use the active space.",
inputSchema,
outputSchema: getDocumentOutputSchema,
annotations: READ_ONLY_TOOL_ANNOTATIONS,
@ -48,7 +48,8 @@ export function register(deps: ToolDeps) {
id: document.id,
title: document.title,
type: document.type,
status: document.system.status,
status: document.system.status,
dreamingStatus: document.system.dreamingStatus,
createdAt: document.system.createdAt,
updatedAt: document.system.updatedAt,
summary: document.summary,

View file

@ -35,7 +35,7 @@ export function register(deps: ToolDeps) {
{
title: "List Documents",
description:
"List documents in one space with their IDs, titles, types, processing status, dates, and summaries. This does not return full document content; use get_document with an ID from this result to read one document. When the user names a space, resolve it with list_spaces and pass namespace; otherwise use the active space.",
"List documents in one space with their IDs, titles, types, processing status, dreamingStatus when available, dates, and summaries. status=done means content processing completed, not memory readiness. dreamingStatus=dreaming means memory generation is pending, running, or awaiting recovery after failure; done means generation settled or none was needed, not guaranteed search readiness or nonzero memories. This does not return full document content; use get_document with an ID from this result to read one document. When the user names a space, resolve it with list_spaces and pass namespace; otherwise use the active space.",
inputSchema,
outputSchema: listDocumentsOutputSchema,
annotations: READ_ONLY_TOOL_ANNOTATIONS,
@ -53,7 +53,8 @@ export function register(deps: ToolDeps) {
id: document.id,
title: document.title,
type: document.type,
status: document.status,
status: document.status,
dreamingStatus: document.dreamingStatus,
createdAt: document.createdAt,
updatedAt: document.updatedAt,
summary: document.summary,

View file

@ -7,11 +7,25 @@ import {
sessionScopeSchema,
} from "../../shared/types"
const documentStatusSchema = z
.string()
.describe(
"Document processing state. done means content processing completed, not that memory extraction or memory-vector writes completed.",
)
const dreamingStatusSchema = z
.enum(["dreaming", "done"])
.optional()
.describe(
"Memory-generation signal from the API, when available. dreaming means pending, running, or awaiting recovery, including after a failure. done means generation settled or no memories were needed; it does not guarantee a nonzero memory count or search readiness.",
)
const documentSummarySchema = z.object({
id: z.string(),
title: z.string().nullable(),
type: z.string(),
status: z.string(),
status: documentStatusSchema,
dreamingStatus: dreamingStatusSchema,
createdAt: z.string(),
updatedAt: z.string(),
summary: z.string().nullable(),
@ -23,8 +37,8 @@ export const addMemoryOutputSchema = z.object({
namespace: z.string(),
...legacyNamespaceOutput,
message: z.string(),
id: z.string().optional(),
status: z.string().optional(),
id: z.string().optional().describe("Accepted document ID, not a memory ID"),
status: documentStatusSchema.optional(),
forgotten: z
.array(z.object({ id: z.string(), memory: z.string() }))
.optional(),
@ -49,7 +63,8 @@ export const getDocumentOutputSchema = z.object({
id: z.string(),
title: z.string().nullable(),
type: z.string(),
status: z.string(),
status: documentStatusSchema,
dreamingStatus: dreamingStatusSchema,
createdAt: z.string(),
updatedAt: z.string(),
summary: z.string().nullable(),