From 944471824a6adf9b5e992c4818222d95b1c72aab Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Mon, 26 Oct 2026 18:54:22 +0000 Subject: [PATCH] fix(mcp): expose dreaming status and clarify document acceptance Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- apps/mcp/README.md | 10 ++++++++- apps/mcp/src/server/client/index.ts | 2 ++ apps/mcp/src/server/format.ts | 6 ++++++ apps/mcp/src/server/tools/add-memory.ts | 4 ++-- apps/mcp/src/server/tools/get-document.ts | 5 +++-- apps/mcp/src/server/tools/list-documents.ts | 5 +++-- apps/mcp/src/server/tools/output-schemas.ts | 23 +++++++++++++++++---- 7 files changed, 44 insertions(+), 11 deletions(-) diff --git a/apps/mcp/README.md b/apps/mcp/README.md index 26476920..9f02d620 100644 --- a/apps/mcp/README.md +++ b/apps/mcp/README.md @@ -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 | diff --git a/apps/mcp/src/server/client/index.ts b/apps/mcp/src/server/client/index.ts index 4d2a2638..ded7d4a4 100644 --- a/apps/mcp/src/server/client/index.ts +++ b/apps/mcp/src/server/client/index.ts @@ -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, diff --git a/apps/mcp/src/server/format.ts b/apps/mcp/src/server/format.ts index d177ac68..2c0ef3fb 100644 --- a/apps/mcp/src/server/format.ts +++ b/apps/mcp/src/server/format.ts @@ -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}`, ] diff --git a/apps/mcp/src/server/tools/add-memory.ts b/apps/mcp/src/server/tools/add-memory.ts index 97bdd6da..92e3db29 100644 --- a/apps/mcp/src/server/tools/add-memory.ts +++ b/apps/mcp/src/server/tools/add-memory.ts @@ -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, diff --git a/apps/mcp/src/server/tools/get-document.ts b/apps/mcp/src/server/tools/get-document.ts index f68c13c8..5670f1be 100644 --- a/apps/mcp/src/server/tools/get-document.ts +++ b/apps/mcp/src/server/tools/get-document.ts @@ -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, diff --git a/apps/mcp/src/server/tools/list-documents.ts b/apps/mcp/src/server/tools/list-documents.ts index c886f364..61ed7f0d 100644 --- a/apps/mcp/src/server/tools/list-documents.ts +++ b/apps/mcp/src/server/tools/list-documents.ts @@ -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, diff --git a/apps/mcp/src/server/tools/output-schemas.ts b/apps/mcp/src/server/tools/output-schemas.ts index 5a75e8c7..71a4947c 100644 --- a/apps/mcp/src/server/tools/output-schemas.ts +++ b/apps/mcp/src/server/tools/output-schemas.ts @@ -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(),