Skip to content

deepmem0-mcp-v0.3.0 — a UI do cofre navega o corpus

Latest

Choose a tag to compare

@fabiolenine fabiolenine released this 02 Aug 19:15

O cofre deixa de ser apenas o gestor de credenciais e passa a ser a interface gráfica da memória: as telas de corpus entram no mesmo app Starlette, com a mesma sessão, a mesma CSP fechada, o mesmo i18n PT/EN e a mesma auditoria. Nenhuma porta nova, nenhuma dependência nova.

Telas

Rota O que mostra
/memories Lista com facetas e cursor real
/memories/{id} Payload completo, ativação ACT-R, cadeia de versões, histórico, entidades vinculadas, proveniência de documento
/search Busca semântica com as_of, event_date e recordação histórica
/queue Fila de ingestão: profundidade, progresso por trecho, dead letters
/entities Entity store com identidade normalizada
/users Usuários e tokens (extraídos do painel)

Por que cada superfície lê de onde lê

Não é preferência — é restrição medida do servidor:

  • a navegação vai ao Qdrant direto porque get_memories é primeira-página-com-teto e não expõe cursor: num corpus maior que o teto, o excedente é inalcançável pela tool;
  • os campos de ACT-R não passam pela whitelist de metadata do search_memories;
  • o entity store não tem caminho MCP nenhum (list_entities faceta a collection principal, e as tools de grafo falam com um Neo4j que não está de pé);
  • fila e histórico saem do SQLite em mode=ro + query_only;
  • a busca é a exceção deliberada e vai pelo MCP, porque o valor está no pipeline (denso + BM25 + reranker + ativação + as_of), não no índice. Sempre com reinforce=false: navegar num console de operador não é um re-encontro da memória, e contá-lo enviesaria o ranking que a própria tela exibe.

Três achados do servidor real que moldaram o código

  1. facet() exige índice de payload. Campos como domain não têm e devolvem 400. As facetas são contadas em Python sobre um scroll projetado. Filtrar por campo sem índice funciona; só facetar é que não.
  2. A paginação é por valor, e o valor não é único. Com order_by o scroll não devolve next_page_offset, start_from é inclusivo, e os trechos de um documento nascem no mesmo created_at — um instante pode ter mais pontos que a página inteira. O cursor carrega os ids já entregues naquele instante: guardar só o timestamp repetiria o grupo para sempre, e um contador dependeria de uma ordem que a API não promete.
  3. O SDK esconde a causa. O transporte roda num task group, então um token recusado chegava como ExceptionGroup: unhandled errors in a TaskGroup. A causa é desembrulhada antes de virar mensagem.

Segurança e robustez

  • Telas de corpus estritamente de leitura — um teste lê o fonte do leitor e reprova qualquer verbo de escrita
  • Fonte indisponível não derruba a UI: vira card na tela, e as telas de credencial seguem servindo
  • O pacote sai com defaults neutros; o escopo e a collection de cada instalação vivem no env file, e o .env.example avisa que deixá-los em branco rende uma tela vazia sem erro nenhum

Gate

1278 testes verdes, paridade i18n PT/EN travada por teste, e smoke de 16 verificações contra corpus real.