Memnest Memory MCP Server
Persistent graph memory for AI agents using LadybugDB — an embedded graph database with native vector search and full-text search.
Give your AI agent memory that persists across sessions, deduplicates automatically, and models knowledge as a graph with typed relationships.
Why Memnest?
- Graph memory — memories linked via Topic nodes and relationships (RELATED_TO, SUPERSEDES, EXPLAINS) with Cypher queries
- Three-layer auto-dedup — exact hash + semantic similarity + LLM-driven consolidation
- Workspace namespacing — memories scoped per project;
global_searchopt-out - HNSW vector search — fast cosine similarity over FastEmbed embeddings
- Topic auto-linking — tags become graph nodes, enabling traversal queries
- Embedded — no Docker, no server process, single database directory
- Zero config — sensible defaults, just install and run
- Importance & access tracking — memories ranked by relevance and usage
Benchmarks
Memnest scores 82.9% on the LOCOMO benchmark — the standard evaluation for long-term conversational memory (ACL 2024).
| Category | Score |
|---|---|
| Single-hop | 84.4% |
| Multi-hop | 76.9% |
| Open-domain | 85.7% |
| Temporal | 86.5% |
| Adversarial | 76.6% |
| Overall | 82.9% |
Evaluated with Claude Sonnet 4.5 as the answer agent and Haiku 4.5 as the judge, using the industry-standard LLM-as-a-Judge methodology. All 5 LOCOMO categories included.
Re-measured on 0.24.1 (same protocol, 199 questions): 84.4% and 85.4%
across two runs of the default legacy fusion. Note the run-to-run noise —
two runs of the identical configuration flipped 16 individual questions and
differed by 1.0 point, so treat sub-2-point differences on this benchmark as
inconclusive.
Fusion modes
MEMORY_FUSION=rrf (reciprocal rank fusion) exists because summing raw cosine
with max-normalized BM25 adds incomparable scales. It fixes three measured
scoring artifacts — see the 0.22.0 notes — but it did not improve
answers, so legacy remains the default:
legacy |
rrf |
|
|---|---|---|
| LOCOMO overall | 84.4% / 85.4% | 82.4% |
| Gold-evidence recall @20 (no LLM) | 58.2% | 66.3% |
| Gold-evidence recall @5 (no LLM) | 46.9% | 46.9% |
| Gold-evidence MRR @20 (no LLM) | 0.354 | 0.346 |
| Top-1 score on unanswerable questions | 0.70 | 0.93 |
| Score spread across top 4 | ~0.17 | ~0.01 |
The retrieval-only numbers are deterministic and show the real trade: rrf
surfaces considerably more gold evidence inside the top 20 (+8.1 points
recall) but ranks it slightly lower (−0.008 MRR). Because the answer agent
already reads the top 20, the extra recall didn't convert into better answers,
and an independent A/B on a 38-fact corpus lost two answers outright to
top-rank precision.
Two further costs, both measured:
- Scores stop discriminating.
rrfinflates absolute scores (top-1 rises 0.70 → 0.93) and compresses their spread to ~0.01 across the top 4, versus ~0.17 underlegacy, because rank 1 contributes 1.0 per channel however weak the match is. Exact ties between adjacent results are normal. In practice you cannot threshold on anrrfscore, and ordering inside the band is decided by the tiebreak rather than by relevance. - No absolute quality signal. Neither mode separates answerable from
unanswerable questions by score, so this isn't a lost refusal signal — but
an
rrfscore carries no information about how good the match actually is. - Superseded memories can be demoted out of the window. The supersession
penalty is a score multiplier (×0.5), which is proportionate against
legacy's ~0.17 spread and heavy againstrrf's ~0.01: underrrfa superseded memory usually falls below unrelated results rather than merely below its own correction. That is still a correct demotion — the current version ranks first in both modes — but it meansrrfcannot show you a stale version for comparison. The pathological case, where the penalty hid the only relevant memory, applied to supersession cycles and is fixed: cycle members are exempt (see 0.28.2). A rank demotion rather than a multiplier would be the coherent analogue under rank fusion.
Use rrf when you want maximum recall in a window you will read entirely and
stability under corpus edits. Keep legacy when you want scores that mean
something, which is why it is the default.
Architecture advantages
- Zero LLM calls in the server — intelligence lives in the agent, not the memory layer
- Local embeddings — no API key needed (
bge-small-en-v1.5, 384-dim) - Single embedded database — no Docker, no PostgreSQL, no separate vector DB
- Hybrid search — Vector (HNSW) + Full-text (BM25) + Graph (PageRank + Louvain communities)
- Minimal retrieval surface — the benchmark agent above scored 82.9% using only
memory_search,memory_getand acalculatorfor date arithmetic. Retrieval quality comes from the server, not from agent-side orchestration.
Quick Start
# Run directly with uvx (no install needed)
uvx memnest-mcp
Or install and run:
pip install memnest-mcp
memnest-mcp
Configure a project (Kiro)
From your project root, one command writes the workspace-level MCP config (with the memory scope pinned to the project) plus the recall/persist/dream agent hooks:
memnest-mcp config kiro # configure the current directory
memnest-mcp config kiro --check # verify only
memnest-mcp config kiro --no-hooks # MCP server config only
This writes .kiro/settings/mcp.json (server + pinned workspace),
.kiro/hooks/memnest-recall.json and memnest-persist.json (automatic recall
and persistence), and .kiro/steering/memnest-dream.md — a manual steering
file you invoke with /memnest-dream to consolidate memory.
The config is always workspace-level (<project>/.kiro/), so each project
gets its own correctly-scoped memory database at <project>/.memnest/.
Reconnect MCP servers in Kiro afterwards. The Kiro Power (below) remains
optional on top for keyword activation and skills.
MCP Configuration
Add to your MCP client config (Kiro, Claude Desktop, Cursor, etc.):
{
"mcpServers": {
"memnest": {
"command": "uvx",
"args": ["memnest-mcp@latest"],
"env": {
"FASTMCP_LOG_LEVEL": "ERROR"
}
}
}
}
That's it — zero config required. All settings have sensible defaults.
Tools
| Tool | What it does |
|---|---|
memory_store |
Store a memory (single or batch) with auto-dedup, auto-link to Topic nodes |
memory_search |
Hybrid semantic + keyword search, ranked by relevance |
memory_update |
Update content, importance, or tags (single or batch) |
memory_delete |
Delete one or more memories and their relationships |
memory_get |
Read one memory in full — untruncated content plus its edges |
memory_list |
Enumerate memories by recency / category / topic / importance (no ranking, pages to any depth) |
memory_relate |
Create RELATED_TO / SUPERSEDES / EXPLAINS relationships (single or batch, idempotent) |
memory_unrelate |
Remove a relationship — one type or all types between a pair |
memory_query |
Run any Cypher query — traversals, writes, extension calls (INSTALL/LOAD), table scans |
memory_schema |
Inspect live DB schema: tables, columns, indexes, extensions |
memory_topics |
List all topics (tags) with memory counts |
memory_stats |
Database statistics: counts, categories, topics, top memories, runtime health |
memory_dream |
Periodic consolidation — auto-prune stale, auto-merge trivial duplicates, surface clusters for review |
memory_reindex |
Rebuild both search indexes (vector HNSW and full-text BM25) |
memory_export |
Write all memories and edges to a portable JSON file |
memory_import |
Restore an export — ids remapped, edges rewired, dedup applied |
memory_set_workspace |
Pin the workspace scope and database location |
memory_graph_html |
Generate an interactive HTML visualization of the graph |
memory_traverse |
Deprecated — use memory_query(read_only=True) |
memory_stats is also safe to paste by default: the workspace and database
paths are reduced to basename#hash, which keeps identity (two calls on one
database match, different databases differ) without naming your directory tree.
Every derived diagnostic — db_inside_workspace, private_to_workspace, the
workspace count — is computed server-side and unaffected. Pass
include_paths=True when debugging locally.
Exports are safe to share by default: workspace values are absolute paths, so
they are replaced with opaque labels (workspace-1) that preserve the
distinction between workspaces without disclosing directory layout. Pass
include_workspace_paths=True for a local backup where you want the real
values. Import ignores the field either way and assigns the current workspace.
Graph Data Model
(:Memory) — content, embedding, category, tags, importance, access_count, timestamps
(:Topic) — auto-created from tags
(:Memory)-[:ABOUT]->(:Topic) # memory is about a topic
(:Memory)-[:RELATED_TO]->(:Memory) # memories are related
(:Memory)-[:SUPERSEDES]->(:Memory) # newer memory replaces older
Example: Store and Search
# Store a memory (via MCP tool call)
memory_store(
content="User prefers Python over Node.js for backend tools",
category="preference",
tags=["python", "nodejs", "backend"],
importance=4
)
# Search memories
memory_search(query="what language does the user prefer")
# Traverse the graph
memory_query(
cypher_query="MATCH (m:Memory)-[:ABOUT]->(t:Topic {name: 'python'}) RETURN m.content"
)
Example: Graph Relationships
# Link related memories
memory_relate(from_id=5, to_id=3, relationship="RELATED_TO")
# Mark a decision as superseded
memory_relate(from_id=8, to_id=2, relationship="SUPERSEDES")
# Find all memories about a topic
memory_query(
cypher_query="MATCH (m:Memory)-[:ABOUT]->(t:Topic) RETURN t.name, COUNT(m) ORDER BY COUNT(m) DESC"
)
Three-Layer Deduplication
Every memory_store call runs through three dedup layers:
- Exact hash — SHA256 of normalized content. Identical content is rejected, importance bumped.
- Semantic similarity — If cosine similarity > 0.92 with an existing memory, merges into it (keeps longer content, merges tags, bumps importance).
- Consolidation — Periodic via
memory_dream. Auto-prunes stale low-importance memories, auto-merges trivial duplicates (similarity ≥ 0.95), surfaces clusters for LLM-driven review.
Categories
| Category | Use for |
|---|---|
learning |
Technical knowledge, facts, how things work |
preference |
User preferences and choices |
decision |
Architecture decisions, tool choices |
pattern |
Recurring workflows, conventions |
general |
Everything else (default) |
Configuration
All settings are optional — defaults work out of the box.
| Environment Variable | Default | Description |
|---|---|---|
MEMORY_DB_PATH |
.memnest/memory.lbug (in cwd) |
LadybugDB database path. Use :memory: for ephemeral testing |
MEMORY_DEDUP_THRESHOLD |
0.92 |
Semantic similarity threshold for auto-dedup |
MEMORY_MERGE_TAG_OVERLAP |
0.5 |
Minimum tag Jaccard overlap before two similar memories may merge |
MEMORY_MERGE_VALUE_GATE |
1 |
Refuse to merge near-identical memories whose values disagree (500ms vs 900ms). Set 0 to restore pure-similarity merging (unsafe) |
MEMORY_CONFLICT_THRESHOLD |
0.85 |
Similarity at which two results are flagged near_duplicate |
MEMORY_CONFLICT_VALUE_FLOOR |
0.5 |
Similarity floor for value_disagreement flagging — same subject, different value, however differently worded |
MEMORY_EMBEDDING_MODEL |
BAAI/bge-small-en-v1.5 |
FastEmbed model for embeddings |
MEMORY_EMBEDDING_DIM |
384 |
Embedding dimension (must match model) |
MEMORY_WORKSPACE |
cwd |
Workspace identifier for memory namespacing |
MEMORY_RESPONSE_FORMAT |
toon if installed, else json |
Response serialization. toon is more token-efficient for LLM context |
MEMORY_SEARCH_LIMIT |
10 |
Max results from memory_search |
MEMORY_LIST_LIMIT |
20 |
Default page size for memory_list |
MEMORY_MAX_CONTENT |
500 |
Content truncation length in search/list results |
MEMORY_LATENCY_WARN_MS |
200 |
Log a warning when an op exceeds this (ms) |
MEMORY_DREAM_MIN_OPS |
10 |
Min ops since last dream before next runs |
MEMORY_DREAM_MIN_HOURS |
24 |
Min hours since last dream before next runs |
MEMORY_DREAM_MIN_MEMORIES |
20 |
Min total memories before dream is allowed (skipped otherwise) |
MEMORY_DREAM_PRUNE_DAYS |
30 |
Auto-prune memories older than N days (with low importance) |
MEMORY_DREAM_PRUNE_MAX_IMP |
2 |
Auto-prune only memories at or below this importance |
MEMORY_DREAM_TRIVIAL_THRESHOLD |
0.95 |
Cosine similarity ≥ this is auto-merged in dream |
MEMORY_DREAM_CLUSTER_LOW |
0.88 |
Cluster-review window: [low, trivial) is surfaced for agent review |
MEMORY_CONSOLIDATE_CLUSTERS |
10 |
Max clusters returned per memory_dream run |
MEMORY_CONSOLIDATE_SCAN |
1000 |
Memories examined per dream run — a rotating window, not a horizon. Above this size the window advances each run, so the whole corpus is covered over ceil(corpus / window) runs at unchanged per-run cost. memory_dream reports scan_coverage |
MEMORY_ALLOW_DESTRUCTIVE |
false |
Allow DELETE/DROP/TRUNCATE/REMOVE/SET/COPY through memory_query. Off by default for safety. Prefer memory_update, memory_delete, memory_unrelate |
MEMORY_SEARCH_CANDIDATES |
100 |
Rows each search channel retrieves before fusion. Independent of top_k. Does not affect index-health coverage: above this size the census switches to a dedicated id-only probe |
MEMORY_FUSION |
legacy |
Channel fusion: legacy (raw cosine + max-normalized FTS), normalized (min-max vector), or rrf (reciprocal rank fusion — only each channel's ordering enters the score, so channel scales can't interact and scores stay stable when memories are added or deleted). rrf stays opt-in: it measured below legacy on LOCOMO (see Fusion modes) |
MEMORY_GRAPH_WEIGHT |
0.15 |
Weight of the graph-centrality channel. This is the one relevance-independent channel — PageRank runs over the Memory+Topic graph, so it acts as a tag-popularity prior, and it is dormant until memory_dream runs. On a tag-dense corpus, setting 0 measured strictly better (MRR@20 0.354 → 0.370). Consider 0 if your memories are heavily tagged |
MEMORY_RRF_K |
60 |
Rank-decay constant for rrf mode. Channel value is (K+1)/(K+rank): 1.0 at rank 1, ~0.87 at rank 10 |
MEMORY_MAX_STORE_CHARS |
20000 |
Content longer than this is truncated on store |
MEMORY_MAX_BATCH |
500 |
Max items per batch call |
MEMORY_GRAPH_MAX_NODES |
2000 |
Max nodes memory_graph_html will render before refusing |
MEMORY_EMBED_TIMEOUT_S |
30 |
Soft timeout for embedding model load (warm-up only) |
In-Memory Mode (Testing)
"env": { "MEMORY_DB_PATH": ":memory:" }
All data is ephemeral — lost on restart. Useful for testing.
Kiro Power
This repo includes a ready-to-use Kiro Power in the power/memnest/ directory, packaged in the Agent Plugins v1.0.0 format with:
- Plugin manifest with activation keywords (
power/memnest/plugin.json) - Pre-configured MCP server (
power/memnest/mcp.json) - Two Kiro agent hooks for automatic recall and persistence (
power/memnest/dev.kiro/hooks/, v1 hook schema — IDE/CLI only; on Kiro Web the agent follows the same workflow from the getting-started skill)- memnest-recall (
UserPromptSubmit) — searches memory before responding to each prompt - memnest-persist (
Stop) — stores important info when the agent finishes - consolidation runs on demand via
memory_dream(see the getting-started skill)
- memnest-recall (
- Agent Skills with the setup guide and Cypher query examples (
power/memnest/skills/)
Install in Kiro: Add Custom Power → https://github.com/arunkumars-mf/memnest-mcp/tree/main/power/memnest
Architecture
AI Agent (Kiro, Claude, etc.)
│
├─ memory_store ──→ embed content → dedup check → insert node → link topics
├─ memory_search ─→ embed query → HNSW vector search → tag boost → rank
├─ memory_query ──→ execute Cypher → return graph results
│
└─ LadybugDB (embedded, single directory)
├─ Memory nodes (content + FLOAT[384] embeddings)
├─ Topic nodes (auto-linked from tags)
├─ HNSW vector index (cosine similarity)
└─ Graph relationships (ABOUT, RELATED_TO, SUPERSEDES, EXPLAINS)
Requirements
- Python 3.10+
- Dependencies installed automatically:
real-ladybug,fastembed,mcp - ~130MB disk for the embedding model (downloaded on first run)
TOON Format (Optional)
Memnest supports TOON (Token-Oriented Object Notation) as a response format, reducing token usage by 30–60% compared to JSON. This is useful when memory results are fed back into LLM context.
TOON is optional — the server falls back to compact JSON automatically if the package isn't installed. To enable it:
pip install "memnest-mcp[toon]"
Or with uvx (requires the --prerelease=allow flag since toon-format is currently in beta):
uvx --prerelease=allow --with "toon-format==0.9.0b1" memnest-mcp@latest
To switch formats at runtime, set the environment variable:
MEMORY_RESPONSE_FORMAT=toon # compact, token-efficient (default when installed)
MEMORY_RESPONSE_FORMAT=json # standard JSON (default when toon is not installed)
The official Python implementation of TOON is toon-format/toon-python, currently at v0.9.0-beta.1. Once it reaches a stable 1.0 release, the --prerelease=allow flag will no longer be necessary.
Contributing
Issues and PRs welcome. See LICENSE for terms.
License
Changelog
0.28.3
explainno longer advertises a penalty it did not apply. Cycle members are exempt from the ×0.5 supersession multiplier, but the block still printedsuperseded_penalty: 0.5next to a score that was never halved. It now reportsnullwithsuperseded_penalty_exempt: "supersession_cycle", and a penalised row's score is asserted to equalsum(weighted) × penalty.superseded: truestill shows, because each member genuinely is superseded — what changed is only whether a penalty was charged.
0.28.2
- Supersession-cycle members are exempt from the ×0.5 penalty. In a cycle every member is superseded by construction, so the flag says nothing about which is stale while the multiplier still destroys ranking. Measured: for one query the answering memory scored an unpenalised 0.769 (vector 0.857, FTS 1.0) and was halved to 0.385, below three unrelated memories at ~0.41 — so at
top_k=2it was not returned, and because the cycle warning is scoped to returned rows the warning vanished with it. The caller asking exactly the affected question got unrelated results and no indication anything was wrong. Cycle members now rank on relevance withsupersession_cycleattached, which fixes the same failure underrrf, where the compressed score spread made it unavoidable. - Ordinary correction chains are unaffected: stale versions are still demoted.
0.28.1
supersession_cycleis scoped to the returned rows. It was keyed off the superseded set derived from scored candidates (the pool of 100), which on any workspace smaller than the pool is the whole corpus — so one unresolved cycle attached the warning to every unrelated search. Now it triggers only when a returned row is a cycle member, then reports the full cycle so the loop is repairable.- Records two findings from the graph-channel investigation: PageRank does propagate (a hub with 7 incoming edges reached 4× the teleport floor) but only
RELATED_TOfeeds a memory incoming rank —ABOUTpoints Memory→Topic, andSUPERSEDES/EXPLAINSare excluded from the projection entirely, so on a corpus with few assertedRELATED_TOedges nearly every memory sits at the floor andk_degreeis the only varying term. And underrrfthe multiplicative supersession penalty makes superseded memories unreachable.
0.28.0
memory_dream(dry_run=True)now reports contradictions. SCC detection on the SUPERSEDES subgraph was gated behind the write path, so a genuine cycle reportedcontradictions: []on inspection and only surfaced when run for effect — a diagnostic reading clean on a state that isn't. Detection is read-only; there was never a reason for the gate.memory_searchsurfaces a supersession cycle. In a cycle no memory is current, so every member is equally penalised, the oldest value can rank first, and the documented current-answer query returns zero rows — which reads as "no information" rather than "contradictory information". Asupersession_cyclefield now names the members and the repair, alongsidepotential_conflicts.MEMORY_GRAPH_WEIGHTis configurable (default unchanged at0.15). The graph channel is relevance-independent and dormant until dream runs; on a tag-dense corpus disabling it measured strictly better (hit@5 0.469 → 0.485, MRR@20 0.354 → 0.370). Deleting all 858 auto-inferred edges changed nothing, locating the effect inABOUTedges to Topic nodes — i.e. tag popularity, not knowledge structure.benchmark/anchors.pypins retrieval anchors for both graph states. The long-used "anchors bit-identical" check was only valid on a corpus where dream had never run, so it would read as a regression on any real workspace. Cold and warm values are now recorded separately and both asserted.
0.27.0
- Result ordering no longer depends on the order memories were stored. Two fixes to the same defect class: the
rrfrank transform broke channel-value ties by memory id (and ids encode insertion order, so identical BM25 scores produced arbitrary ranks that propagated into different fused scores), and the final sort broke score ties by dict order. Channel ranks now use competition ranking — equal values get equal rank — and final ties break on importance, then recency, then id. A 4-memory fixture that reordered its own results purely by store order now doesn't. - This was costing
rrfmeasurable quality: gold-evidence recall@20 rises 64.3% → 66.3% and recall@5 45.4% → 46.9% (now equal tolegacy).legacyis unaffected — it does no rank transform, and anchors are bit-identical. - Documents the
rrfscore-compression cost: spread across the top 4 is ~0.01 versus ~0.17 underlegacy, sorrfscores cannot be thresholded.
0.26.2
- Verifies a real restore into a separate on-disk database, not just an in-memory one: embeddings recomputed, index fully reachable, restored memories findable, supersession still resolving to current.
0.26.0
Closes two silent coverage losses that appeared at ordinary corpus sizes, not extreme ones.
- Index-health coverage no longer lapses above the candidate pool. The per-query census compared ranked vector hits against the corpus, which only works while the pool (100) covers it — so the detector for the worst bug class protected a shrinking slice as a workspace grew (2% at 5,000 memories). Above the pool it now runs a dedicated id-only probe at
k=corpus: measured 19.7 ms against a 191.8 ms search, ~10% overhead, 100% coverage at every size.explain_meta.census_modereports which path ran. - Dream's scan cap is a rotating window, not a horizon. It always examined the newest
MEMORY_CONSOLIDATE_SCANbyupdated_at, so once a workspace passed the cap everything older was never considered for merge or prune again. The window now advances each run and wraps, covering any corpus over successive runs at unchanged per-run cost.memory_dreamreportsscan_coverage. memory_statsreportsdb_scope— whether the one-database-per-workspace invariant that makes lock-free operation safe actually holds, judged from which workspaces own memories in the file rather than from configuration. Warns when a sharedMEMORY_DB_PATHhas put unrelated projects in one graph.- Soak harness gains
--sessions N: N short sessions as separate processes, each verifying what the previous one left behind. This is the realistic stress pattern for one connection per workspace, and it is where the delete-churn bug actually manifested.
0.25.0
- Dream review clusters now carry only pairs that still need a decision. Different-subject and disjoint-scope pairs are separate permanently and are dropped; same-subject value conflicts are unresolved, so they stay and are labelled
gate: "value_conflict"with the non-destructive resolution named.
0.24.1
memory_deletereaps orphanedTopicnodes (a long-lived database had accumulated 273 orphans against 24 live topics);memory_dreamdoes the same for its own prune/merge deletions and reportstopics_reaped.- The post-delete index census is exception-isolated — diagnostics can never fail a committed write.
0.24.0
Root-caused the recurring silent loss of vector-search coverage: LadybugDB 0.15.3 delete maintenance progressively orphans surviving HNSW nodes when transient batches are inserted then deleted. Reproduced standalone (repro), monotonic, in-process, persists across restarts. Onset is non-monotonic in burst size and seed-dependent, which is why several earlier experiments wrongly cleared it.
memory_deletenow censuses index reachability and rebuilds on shortfall, so a session's deletes can't hand the next session a degraded index.memory_statsreportsvector_index.status: "degraded"when the census contradicts the cached probe verdict.
0.23.0
- One shared implementation of the delete+recreate path used by store-dedup, update and dream merge (three copies had drifted; dream was zeroing
access_count). Store and update preserve the count; dream merge sums the merged members'.
0.22.0
- New
MEMORY_FUSION=rrf(opt-in). Fixes three artifacts of summing incomparable channel scales: survivor keyword scores rescaling 2.24× when the top hit was deleted, a +0.166 score jump that inverted a ranking, and a plateau of identical scores when the vector channel was dead. See Fusion modes for why it is not the default.
0.19.0
Surface hardening from a full tool-by-tool review.
- Security: the
memory_querydestructive-query guard was bypassable. It matched the substring"DELETE "— with a literal trailing space — soMATCH (m:Memory)\nDETACH\nDELETE\nm;reported success and deleted every memory withMEMORY_ALLOW_DESTRUCTIVE=false. Queries are now classified after stripping comments and string literals, matching keywords on word boundaries. - Breaking:
read_only=Truenow rejects any mutation. It previously permittedCREATE/MERGE/SET, so an overwrite succeeded under a flag named read-only.MEMORY_ALLOW_DESTRUCTIVEnow also coversSET,REMOVEandCOPY— an overwrite destroys the previous value as surely as a delete. - New
memory_unrelate: edges could be created but never removed, andmemory_query's DELETE is blocked by default, so a mistakenSUPERSEDESwas permanent. This is also the supported way to break a circularSUPERSEDESchain thatmemory_dreamreports. memory_getnow returns edges (include_edges=Trueby default) plussuperseded/superseded_by. Answering "what does this replace?" no longer requires Cypher.- Ranking fix: the search candidate pool was
top_k * 3, so the page size decided which memories were scored at all — on a 25-memory corpus,top_k=10surfaced two memories that outranked every resulttop_k=5returned. The pool is now fixed (MEMORY_SEARCH_CANDIDATES, default 100) and independent oftop_k. Scores are unchanged; only coverage improves. - Pagination:
memory_search(offset=...)withoffset/has_morein the response. Rank 11+ was previously unreachable. - New
memory_export/memory_import: JSON backup and restore including edges, with id remapping so an import can merge into an existing database.memory_relateis now idempotent (status: "exists"), so re-importing no longer doubles every edge. - Input validation across every tool: two-sided clamping (
preview_chars=-5used to slice content from the wrong end;top_k=0returned adegradedflag blaming the embedding model), content and batch size caps, and honest statuses (memory_deletereporteddeletedwhen every id was missing;memory_list(min_importance='high')raised a rawValueError). memory_getandmemory_listare no longer labelled compatibility aliases — each does something no other tool does.memory_traverseis marked deprecated.
0.3.0
- Default database is now per-workspace:
.memnest/memory.lbugin the current directory. No more cross-workspace lock conflicts. - Set
MEMORY_DB_PATHto use a custom location (e.g.~/.memnest/memory.lbugfor global shared memory). - Hybrid search: Vector (HNSW) + Full-text (BM25) + Graph scoring with PageRank, Louvain community detection, and K-Core decomposition.
- LOCOMO benchmark: 82.9% overall score.
0.2.0
Compatibility-preserving redesign with improved safety defaults.
- New tools:
memory_query(general Cypher),memory_schema,memory_topics,memory_dream,memory_graph_html. Batch mode added tomemory_store,memory_update,memory_relate,memory_delete. - Breaking:
MEMORY_ALLOW_DESTRUCTIVEnow defaults tofalse. Set it totrueif you previously relied onmemory_querydeleting nodes. - Breaking: tag storage migrated from comma-joined strings to JSON arrays. Old rows are still readable; rewriting (e.g. via
memory_update) upgrades them to JSON. memory_get,memory_list,memory_traversefrom 0.1.x are retained as compatibility aliases. (As of 0.19.0memory_getandmemory_listare first-class again; onlymemory_traverseremains deprecated.)- TOON serialization is now the default response format when
toon-formatis installed; setMEMORY_RESPONSE_FORMAT=jsonto opt out. memory_relatevalidates that both endpoints exist before returningcreated(used to silently no-op on typo'd IDs).memory_graph_htmlis now XSS-safe (HTML-escaped tooltips, DOMtextContentfor the detail panel), refuses to render >MEMORY_GRAPH_MAX_NODES, and rotates snapshots.- Workspace filter pushed inside the vector index
WITHclause so search recall isn't starved across workspaces. - Dream consolidation: dedupes parallel edges across merges, isolates clusters by workspace, persists state via atomic sidecar JSON.
Release files for memnest-mcp 0.29.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| memnest_mcp-0.29.2.tar.gz | 851.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| memnest_mcp-0.29.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 962.0 kB
Release files / memnest_mcp-0.29.2.tar.gz
| Download URL | memnest_mcp-0.29.2.tar.gz |
|---|---|
| Size | 851.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5b2e80bf1211cff4989d5d29e082df9009021d009830435933c4eada6dbb3d34
|
|
BLAKE2b-256 checksum How to use checksums |
2b0c57f00d82772115e9c1dccf1b72f2637fbc87f26333ef586c466e2a12c36e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.4
|
Release files / memnest_mcp-0.29.2-py3-none-any.whl
| Download URL | memnest_mcp-0.29.2-py3-none-any.whl |
|---|---|
| Size | 110.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4934e2a22ee9cb906ed52bca4db681bd4a9715ac693f36df5e9a16f139386ae2
|
|
BLAKE2b-256 checksum How to use checksums |
cb1855a8e0777b7a814cede210e09efd7226065cb40dfd71e590e62d427e6c22
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.4
|