mcp-memory-vault
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-memory-vaultSave that I prefer dark mode in the editor."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-memory-vault
MCP server that gives any agent persistent memory: namespaced facts with tags, SQLite FTS5 search that understands plain questions, TTL expiry, and a CLI to inspect and back it all up. Local only, no external services.
Why
Agents forget everything the moment a session ends. User preferences, project decisions, environment quirks, customer details: all gone, re-learned (or re-asked) every single time. mcp-memory-vault fixes that with a small local SQLite vault. Any MCP client (Claude Desktop, Claude Code, or your own agent) can store facts as it works and recall them in any later session, with plain questions like "when does ACME prefer to deploy?". Facts are scoped by namespace, labeled with tags and can carry a TTL so short-lived context expires on its own. The storage engine is pure Python standard library: no API keys, no vector database, nothing leaves your machine.
Related MCP server: persistent-kb-mcp
Tools
Tool | Arguments | Returns |
|
| The stored memory. An exact duplicate (same content in the same namespace) is never stored twice: the existing memory comes back with |
|
| Ranked hits with a |
|
| Deletion confirmation with a preview of what was removed. |
|
| Most recent memories first, including |
|
| The updated memory plus |
| none | Totals, counts per namespace, the most used tags, active-TTL count, database size and path, |
|
| All memories as JSON-serialisable dicts, ready for backup or migration. |
|
| Counts of |
Every tool has a title, a description on each argument, and MCP annotations (readOnlyHint on recall, list_memories, memory_stats and export_memories; destructiveHint on forget and update_memory), so clients can auto-approve the safe ones. The server also sends instructions that tell the model when to remember, how to recall and how to keep memories accurate.
Errors are returned to the model as tool errors with an actionable message, for example Memory 999 not found — it may have expired or been forgotten. Use list_memories or recall to find valid ids.
How recall works
Agents ask questions, not keyword lists. The query is normalised before it reaches SQLite:
It is split on anything that is not a letter or digit, so
ACME's,deploy?anddark-modework.Filler words are dropped (a compact English and Spanish list: "when", "does", "the", "que", "el"...), unless the query is nothing but filler.
Words of three or more letters also match by prefix of a light root:
deploysfinds "deploy", "deployed" and "deployment",kubefinds "Kubernetes". FTS5's porter stemmer still matches the exact word's inflections.
Then match decides how the terms combine:
| Behaviour |
| Memories containing every term. If there are none, memories containing any term, and the result carries a |
| Strict: every term must match. |
| At least one term. Memories matching more terms rank first, then by bm25 relevance, then by recency. |
For example, recall("When does ACME prefer to deploy?") searches acme + prefer + deploy and finds "Customer ACME prefers deploys on Fridays". recall("ACME's deploy day") finds no memory containing "day", so it returns the ACME memory as a partial match with matched_terms: ["acme", "deploy"]. When nothing matches, a hint suggests what to try next.
Namespace and tag filters (tags are case-insensitive) and the limit are applied inside SQLite. On a 30-fact corpus, 17 natural-language, possessive, punctuated, prefix and Spanish queries get the right memory first every time; v0.1.0, which ANDed every raw word, got 5 of them. The table is tests/test_recall_quality.py.
How it works
flowchart LR
A[Agent / MCP client] -- stdio --> S[server.py<br/>MCP SDK 1.x or 2.x]
H[You] -- terminal --> CLI[cli.py<br/>add / search / doctor ...]
S --> C[core.py<br/>MemoryVault]
CLI --> C
C -- "one transaction per write" --> DB[(SQLite WAL<br/>~/.mcp-memory-vault/memories.db)]
DB -- triggers keep in sync --> FTS[FTS5 index<br/>memories_fts]
C -- "recall: MATCH + bm25" --> FTS
C -. "no FTS5 in this build?<br/>LIKE fallback, same semantics" .-> DBWhat the storage engine guarantees:
No duplicates.
(namespace, content)is unique, enforced by a UNIQUE index, so no path (remember, update, import, or a second process writing to the same file) can create two copies of a fact.Correct expiry. Every timestamp is stored as canonical UTC (
2026-07-23T12:00:00Z). Imported timestamps with offsets (...-08:00) are converted, so a TTL expires at the right instant. Expired memories are purged before each operation with an index lookup, and no background process is needed.Safe concurrency. A vault can be shared by the worker threads of the MCP SDK (mcp 2.x runs tools on threads) and by several processes at once (two agents plus the CLI): every write is one
BEGIN IMMEDIATEtransaction, and reads do not take the write lock, so they are not blocked by another process that is writing (the exception is a read that first has to purge an expired memory).Scale. Indexes cover the dedup lookup, the expiry purge and listing, and the full-text index is only rebuilt when it disagrees with the table. At 50,000 memories, an import takes a few seconds instead of minutes, recall takes about 3 to 45 ms on typical queries, and
list_memories(tag=...)takes under a millisecond.Versioned schema. The schema version lives in
PRAGMA user_version. A vault written by an older release is upgraded in place, in one transaction, the first time it is opened (see Upgrading from 0.1.0).
If the local SQLite build lacks FTS5, the vault falls back to a LIKE search with the same query normalisation, match modes, ranking by matched terms and bracketed snippets. memory_stats and mcp-memory-vault doctor tell you which mode is active. Set MEMORY_VAULT_DB to relocate the database file.
Quickstart
mcp-memory-vault is installed straight from GitHub (it is not on PyPI yet, see below). Any MCP client that can launch a stdio command works.
Claude Code (with uv):
claude mcp add memory-vault -- uvx --from git+https://github.com/AleBrito124356/mcp-memory-vault mcp-memory-vaultClaude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"memory-vault": {
"command": "uvx",
"args": ["--from", "git+https://github.com/AleBrito124356/mcp-memory-vault", "mcp-memory-vault"]
}
}
}Without uv, install it into any Python 3.10+ environment and point your client at the mcp-memory-vault command:
pip install git+https://github.com/AleBrito124356/mcp-memory-vault
mcp-memory-vault doctor # check the setup
mcp-memory-vault # no command = the MCP server on stdio (clients launch it for you)The server works with both major versions of the official mcp SDK (1.10+ and 2.x), so it can share an environment with other MCP tooling.
PyPI: publication is pending. The
publishworkflow releases to PyPI when av*tag is pushed, andserver.jsondescribes the package for the official MCP registry. Until then,uvx mcp-memory-vaultandpip install mcp-memory-vaultwill not find the package.
CLI
The same command is a CLI for the vault's owner: see what your agents remembered, fix or delete it, back it up, and diagnose setup problems. Every command except serve works without the mcp package. --db PATH and --json are accepted before or after the command.
Command | What it does |
| Run the MCP server on stdio. |
| Remember a fact ( |
| Search ( |
| Most recent first ( |
| One memory in full. |
|
|
| Delete memories. |
| Totals, namespaces, top tags, schema, size. |
| JSON backup (stdout by default). |
| Import an export (or a bare JSON array; |
| Check Python, SQLite, FTS5, the database (writable, integrity, schema, index sync) and the installed |
Real output:
$ mcp-memory-vault search "when does ACME prefer to deploy?"
1 hit for "when does ACME prefer to deploy?" (terms: acme, prefer, deploy; fts5, match: all)
#1 [support] Customer [ACME] [prefers] [deploys] on Fridays
tags: customer, deploy · just now · matched: acme, prefer, deploy
$ mcp-memory-vault search "ACME's deploy day"
2 hits for "ACME's deploy day" (terms: acme, deploy, day; fts5, match: any)
note: No memory contains every term, so these are partial matches, best first — check matched_terms before relying on them.
#1 [support] Customer [ACME] prefers [deploys] on Fridays
tags: customer, deploy · just now · matched: acme, deploy
#2 [support] [ACME]'s billing contact is Jane Doe
tags: customer, billing · just now · matched: acme
$ mcp-memory-vault list --tag infra
#4 [atlas] Project Atlas uses Postgres 16 with pgvector
tags: infra · just now
#3 [ops] Globex staging database resets nightly at 02:00 UTC
tags: infra · just now · expires 2026-10-23T16:51:22Z
$ mcp-memory-vault edit 2 --add-tag finance --remove-tag billing
Updated memory 2 (tags).
id: 2
namespace: support
content: ACME's billing contact is Jane Doe
tags: customer, finance
source: -
created: 2026-09-23T16:51:22Z (just now)
updated: 2026-09-23T16:51:23Z
expires: never
$ mcp-memory-vault --db memories.db stats
memories 4 (1 with a TTL)
namespaces support (2), atlas (1), ops (1)
top tags customer (2), infra (2), deploy (1), finance (1)
search fts5
schema v2
database memories.db (48.0 KiB)
$ mcp-memory-vault export -o backup.json
Exported 4 memories to backup.json
$ mcp-memory-vault --db other.db import backup.json
Imported 4 memories, skipped 0 duplicates.
$ mcp-memory-vault --db memories.db doctor
[ ok] mcp-memory-vault 0.2.0
[ ok] python 3.14.2
[ ok] sqlite 3.50.4
[ ok] fts5 available (ranked full-text search)
[ ok] database path memories.db (from --db)
[ ok] database memories.db (4 memories, integrity ok)
[ ok] schema v2 (current)
[ ok] search index in sync with the memories table
[ ok] mcp 2.2.0 (SDK 2.x, server imports fine)
All good.Example session
A support agent learns something today and uses it next week, in a completely new session.
Session 1 (Monday):
User: Heads up — ACME told us they only want production deploys on Fridays. Keep that in mind.
Agent: Noted — I'll store that so I remember it in future sessions.
Calls
remember(content="Customer ACME prefers deploys on Fridays", namespace="support", tags=["customer", "deploy"], source="user note 2026-07-20")→
{"id": 1, "deduplicated": false, "merged_tags": [], "message": "Stored memory 1 in namespace 'support'."}
Session 2 (a week later, fresh context):
User: ACME's fix is ready. When should we ship it?
Agent: Let me check what I know about ACME's deploy preferences.
Calls
recall(query="What are ACME's deploy preferences?", namespace="support")→
{"terms": ["acme", "deploy", "preferences"], "match_mode": "all", "count": 1, "hits": [{"id": 1, "snippet": "Customer [ACME] [prefers] [deploys] on Fridays", "matched_terms": ["acme", "deploy", "preferences"], "tags": ["customer", "deploy"], "age": "1 week ago"}]}Agent: ACME prefers deploys on Fridays (you told me a week ago). Today is Wednesday, so I'd schedule the release for this Friday.
Upgrading from 0.1.0
Nothing to do: the first time 0.2.0 opens an existing vault it upgrades it in place, in one transaction.
Timestamps written with an offset are converted to UTC, so TTLs expire at the right time.
Exact duplicates left behind by 0.1.0's
update_memoryare folded into the oldest copy: tags are merged, the earliestcreated_atis kept, the memory stays permanent if any copy was, and distinct sources are joined.Tags that differ only in case are merged, and memories gain an
updated_atfield.The indexes are created and the search index is rebuilt once.
Run mcp-memory-vault doctor first if you want to see what will happen: it reports the schema version without changing anything. Downgrading is not supported, so take an export first if you might need to go back. If an old 0.1.0 install keeps writing to the same file, 0.2.0 repairs those rows (timestamps, tag index) the next time it opens the vault.
Behaviour changes worth knowing:
recalldefaults tomatch="auto": when no memory contains every term, you now get partial matches (flagged with anote) instead of nothing. Passmatch="all"for the old strict behaviour.Tags are case-insensitive, and remembering an existing fact with new tags adds them instead of dropping them.
update_memoryrefuses to turn a memory into a duplicate of another one.import_memoriesis all-or-nothing and skips items that have already expired (reported asexpired).
Development
git clone https://github.com/AleBrito124356/mcp-memory-vault
cd mcp-memory-vault
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
python -m pytest
python -m mcp_memory_vault.server # run the stdio server from the source treeThe test suite covers every layer:
test_core.py,test_integrity.py,test_migration.py,test_concurrency.py: the storage engine. This covers dedup, canonical timestamps and TTLs, case-insensitive tags, index use, upgrading a raw-SQL v0.1.0 vault, and 8 threads sharing one vault. These tests need only the standard library.test_recall_quality.py: the natural-language query table, in both FTS5 and LIKE mode.test_server.py: every tool through a real in-memory MCP client session, including the error path. The model must see messages like "Memory 999 not found ... use list_memories".test_stdio_e2e.py: spawnspython -m mcp_memory_vault.serverand speaks raw JSON-RPC over stdio, the same way Claude Desktop does.test_cli.py: every CLI command as a subprocess, including a run without themcppackage.
The server tests run against whichever mcp is installed. To cover both SDK generations, run the suite once after pip install "mcp<2" and once after pip install "mcp>=2,<3". It passes on mcp 1.10.0, 1.30.0 and 2.2.0.
Related MCP servers
Part of a family of small, dependency-light MCP servers:
mcp-decision-lab: weighted decision matrices with sensitivity analysis
mcp-devils-advocate: stress-test a claim with devil's advocate, premortem and assumption audits
mcp-secret-sentinel: scan code for exposed secrets, always redacted
mcp-git-historian: churn hotspots, blame summaries, bus factor
License
MIT
Available Tools
8 toolsexport_memoriesExport memoriesARead-only
Export memories as JSON-serializable dicts for backup or migration.
Returns {"count", "namespace", "memories": [...]}; feed the "memories" array to import_memories on another vault to migrate.
| Name | Required | Description | Default |
|---|---|---|---|
| namespace | No | Only export this namespace ("" = everything). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations provide readOnlyHint=true and openWorldHint=false, so the safety profile is already covered. The description adds the concrete return shape (count/namespace/memories) and the migration workflow, which go beyond what annotations declare.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences; the purpose leads and the downstream workflow follows. Minor formatting oddity with the trailing markdown fence in the description text, but no wasted wording.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers purpose, output shape, and the migration handoff to import_memories, which is sufficient given there's no output schema and annotations cover safety. A note on large-vault size/pagination would complete it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter with 100% schema coverage, where the schema already explains that "" means everything. The description reinforces the namespace scoping via the returned namespace field but adds little syntax detail; with full schema coverage a baseline of 3-4 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (export) and resource (memories) plus the output format (JSON-serializable dicts) and the use case (backup or migration). This distinguishes it from siblings like list_memories and memory_stats.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly frames usage around backup or migration and names import_memories as the downstream tool, giving a clear when-to-use context. It doesn't state exclusions or contrast with list_memories/recall, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
forgetForget a memoryADestructive
Permanently delete one memory by id.
Returns confirmation with the id and a truncated preview of what was deleted.
| Name | Required | Description | Default |
|---|---|---|---|
| memory_id | Yes | Id of the memory to delete (from recall or list_memories). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=false, so the safety profile is covered. The description adds genuine value beyond that: it stresses 'permanently' (irreversibility) and, since there is no output schema, describes the confirmation payload with id and a truncated preview.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, with the destructive action front-loaded and the return behavior secondary. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter destructive tool with no output schema, the description covers the action, its permanence, and the shape of the return value. Only a note on error behavior for an unknown id is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the sole parameter memory_id is already fully documented in the schema, including its provenance. The description only restates 'by id' and adds no format, constraint, or edge-case detail beyond the schema baseline of 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with scope: 'Permanently delete one memory by id.' An agent can distinguish it from recall/list_memories/update_memory by the delete semantics. It does not explicitly name which sibling to prefer, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description never says when to forget a memory versus updating or exporting it, and offers no prerequisites or exclusions. The only routing hint (ids come from recall or list_memories) lives in the schema, not the description.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
import_memoriesImport memoriesAIdempotent
Import memories from a previous export_memories call.
Each item needs at least a non-empty "content"; namespace, tags, source, created_at, updated_at and expires_at are preserved when present (timestamps with offsets are converted to UTC). Everything is validated first and written in one transaction, so a bad item changes nothing. Exact duplicates (same content + namespace) and items that have already expired are skipped.
Returns {"imported", "skipped", "expired", "total_received", "message"}.
| Name | Required | Description | Default |
|---|---|---|---|
| memories | Yes | The "memories" array produced by export_memories. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: validation-before-write, single-transaction atomicity ('a bad item changes nothing'), duplicate and expired-item skipping, field preservation and timestamp-to-UTC conversion, plus the exact return keys. This is exactly the behavioral detail annotations like idempotentHint and destructiveHint cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the source relationship, then consequences, then return shape in three tight sentences. No filler; every clause carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter import tool with no output schema, the description supplies the return keys, the atomicity guarantee, and the dedup/expiry behavior. Combined with the annotations, an agent has everything needed to invoke and interpret it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% but the schema itself is nearly opaque (an array of objects with additionalProperties). The description compensates by specifying the required non-empty 'content' field and which optional fields are preserved, adding real meaning beyond the schema. It could still clarify the accepted timestamp formats more concretely.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Import memories') and ties the input source directly to the sibling tool export_memories, so an agent can immediately distinguish this from remember/update_memory and knows where the payload originates.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly frames the use case as restoring data from a prior export_memories call, which is clear context. It stops short of stating when-not to use it (e.g., for single ad-hoc additions, use remember instead), leaving that routing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_memoriesList memoriesARead-only
Browse stored memories, most recent first, without a search query.
Returns {"count", "memories": [...]} with expires_at included when a TTL is set.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | Only list memories with this tag ("" = any). | |
| limit | No | Maximum number of memories. | |
| namespace | No | Only list this namespace ("" = all). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds real value beyond that by describing the return shape and the conditional expires_at field, though it says nothing about pagination or how to retrieve beyond the limit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with no filler; the scoping constraint is front-loaded and the return-shape note follows immediately. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully compensates by stating the return keys and the conditional expires_at. Annotations cover safety, and params are fully documented. Only pagination behavior for the default limit of 20 is left unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so tag, limit, and namespace are fully documented in the schema with defaults and empty-string semantics. The description adds no parameter-level detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Browse stored memories') with ordering ('most recent first') and a scoping constraint ('without a search query'). This implicitly separates it from recall/search-style siblings, though it never names them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'without a search query' makes the usage context clear — this is the browsing path when no query exists, as opposed to a search/recall path. No explicit alternative is named, so it falls short of a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_statsVault statisticsARead-only
Get vault statistics and health information.
Returns total memories, counts per namespace, the most used tags (handy to pick tags consistently), how many have an active TTL, database file size and path, schema_version, and the active search_mode ("fts5" or "like" fallback).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds real behavioral value beyond that: it discloses the diagnostic nature of the output and surfaces the internal search_mode fallback ('fts5' vs 'like'), which is unusual and useful context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose sentence is front-loaded and efficient. The follow-up enumeration is long but each item earns its place since there is no output schema to describe the return shape; a minor redundancy exists between 'statistics and health information' and the explicit field list.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description fully carries the burden of describing the return payload: totals, per-namespace counts, top tags, active-TTL count, db size and path, schema_version, and search_mode with its enum values. An agent knows exactly what it will get back.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. The description correctly implies no inputs are needed; there is nothing further to document.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource pair ('Get vault statistics and health information') and immediately enumerates the scope of what is returned. It is clearly distinguishable from recall/remember/forget by topic, but it never explicitly contrasts itself with any sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied. The parenthetical '(handy to pick tags consistently)' hints at one diagnostic use case, and the 'health information' framing implies introspection, but there is no explicit when-to-use, when-not, or alternative tool named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
recallSearch memoriesARead-only
Search memories by full text and get the best matches first.
Punctuation and filler words ("when", "does", "the", "de", "que"...) are ignored and words also match by prefix, so plain questions work. With the default match="auto", memories containing every term come first; if none do, partial matches are returned instead, ranked by how many terms they contain, and the result carries a "note" saying so. Ranking uses SQLite FTS5 bm25 relevance with recency as tiebreaker.
Returns {"query", "terms", "search_mode", "match_mode", "count", "hits"} where each hit has id, content, snippet (matches in [brackets]), matched_terms, namespace, tags, source, created_at, updated_at and age. A "hint" explains what to try when nothing matched.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Only return memories carrying ALL of these tags (case-insensitive). | |
| limit | No | Maximum number of hits. | |
| match | No | "all" = every term must match; "any" = at least one, most terms first; "auto" = "all", falling back to "any" when nothing matches every term. | auto |
| query | Yes | What to look for: key nouns ("ACME deploy") or a plain question ("when does ACME deploy?"). | |
| namespace | No | Only search this namespace ("" = all namespaces). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, yet the description goes well beyond them: it discloses the ranking algorithm (SQLite FTS5 bm25 with recency tiebreaker), the auto-match fallback behavior, the 'note' emitted on partial matches, and the 'hint' on empty results. That is genuine behavioral context an agent would otherwise have to discover by trial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The search behavior is front-loaded and the return-shape paragraph is dense but skimmable. The sentence enumerating every hit field is somewhat list-like, but no sentence is redundant given the absence of an output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return contract and does so fully: the top-level envelope keys, per-hit fields, snippet bracketing, the note flag and the hint. Combined with annotations, an agent has everything needed to invoke and interpret recall.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, but the description adds real meaning on top: it clarifies that plain questions work, that terms match by prefix, and that match='auto' falls back from all to any with an accompanying note. These reinforce and extend the enum and query descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Search memories by full text') plus a scope promise ('best matches first'). It contrasts implicitly with list_memories by emphasizing relevance ranking and full-text matching, but never names a sibling to sharpen the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains what happens with punctuatation, filler words and prefix matching, and describes the default match='auto' fallback chain, which tells the agent how the search behaves. However, it never states when to reach for recall versus list_memories or memory_stats, so the usage context is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rememberRemember a factAIdempotent
Store a fact in persistent memory so it survives across sessions.
Use this whenever you learn something worth keeping: user preferences, project decisions, environment quirks, follow-ups. Exact duplicates (same content in the same namespace) are never stored twice: the existing memory is returned with "deduplicated": true, and any new tags are merged into it (listed in "merged_tags"). Tags are case-insensitive.
Returns the stored memory (id, content, namespace, tags, timestamps) plus "deduplicated", "merged_tags" and a human-readable "message".
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Optional short labels for filtering, e.g. ["customer", "deploy"]. | |
| source | No | Optional provenance, e.g. "user message" or "ticket #123". | |
| content | Yes | The fact to remember, as one self-contained sentence that names its subject. | |
| ttl_days | No | Days until the memory expires; 0 = never expires. | |
| namespace | No | Logical bucket, e.g. one per project or user. | default |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint=true and destructiveHint=false; the description adds genuinely new behavior: exact duplicates in the same namespace are never double-stored, the existing memory is returned with deduplicated=true, new tags are merged and reported in merged_tags, and tags are case-insensitive. This is exactly the extra context annotations cannot carry, and it is consistent with them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then trigger guidance, then edge-case semantics, then return shape. Every sentence earns its place, though the return-value paragraph is slightly verbose given it repeats field names that the caller can discover at runtime.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description correctly takes on the burden of describing the response (id, content, namespace, tags, timestamps, deduplicated, merged_tags, message). Combined with dedup, namespace scoping, and tag case rules, an agent has everything needed to call and interpret this write tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning the schema does not: dedup is scoped to 'same content in the same namespace' (clarifying namespace semantics) and tags are case-insensitive with merge behavior on duplicates. No syntax or format gaps remain.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Store a fact in persistent memory', with the scope qualifier 'so it survives across sessions'. It is clearly distinguishable from retrieval siblings like recall in spirit, but it never names an alternative explicitly, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use this whenever you learn something worth keeping' plus concrete examples (user preferences, project decisions, environment quirks, follow-ups) gives a clear trigger. It omits any when-not guidance or named alternative (update_memory, forget), which keeps it out of 5 territory.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_memoryUpdate a memoryADestructiveIdempotent
Edit an existing memory: content, tags, namespace, source or TTL.
Prefer this over storing a second, contradicting memory when a fact changes. A change that would make this memory an exact duplicate of another one in the target namespace is refused, and the error names the existing memory.
Returns the updated memory plus "updated_fields" listing what changed.
| Name | Required | Description | Default |
|---|---|---|---|
| source | No | New provenance note ("" = keep the current one). | |
| content | No | New content ("" = keep the current content). | |
| add_tags | No | Tags to add on top of the existing ones. | |
| ttl_days | No | -1 = leave the TTL unchanged, 0 = remove it (permanent), N > 0 = expire N days from now. | |
| memory_id | Yes | Id of the memory to update. | |
| namespace | No | Move the memory to this namespace ("" = keep). | |
| remove_tags | No | Tags to remove (case-insensitive). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare it as non-read-only, destructive, idempotent, and closed-world. The description adds meaningful behavioral detail beyond that: duplicate detection with a named error, and the return shape including 'updated_fields'.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core edit operation in the first sentence, then adds usage guidance, duplicate-refusal behavior, and return information without filler. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema and a rich annotated profile, the description covers the essential missing pieces: when to prefer it over creating a duplicate, duplicate-refusal behavior, and the return shape. Parameter behavior is fully covered by the schema, so nothing critical is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all seven parameters are fully documented in the input schema. The description only lists field names (content, tags, namespace, source, TTL) that the schema already defines, adding no extra syntax or constraints.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Edit') and resource ('existing memory'), enumerating mutable fields. The sentence about preferring it over storing a second memory distinguishes it from the create-oriented sibling 'remember'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear use case—when a fact changes and a second contradicting memory would otherwise be stored—and names the alternative behavior. It lacks explicit when-not guidance, but the condition for choosing this tool is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
8 tool updates
v0.2.0- First observed
export_memories - First observed
forget - First observed
import_memories - First observed
list_memories - First observed
memory_stats - First observed
recall - First observed
remember - First observed
update_memory
TDQS
Scored across 8 tools
Each tool has a clearly distinct purpose: remember (create), recall (search), list_memories (browse), update_memory (edit), forget (delete), plus stats and import/export. The descriptions explicitly disambiguate potentially overlapping operations (e.g., recall vs list_memories, remember vs update_memory).
All names use snake_case and are readable, but the pattern is mixed: some are verb-only (remember, recall, forget) while others are verb_noun (list_memories, update_memory, import_memories, export_memories) and one is noun_noun (memory_stats). Consistent casing and clear intent keep it from being confusing.
Eight tools is well-scoped for a persistent memory vault, covering the core lifecycle plus maintenance operations without bloat. Every tool earns its place.
Full CRUD lifecycle is covered (remember, recall/list_memories, update_memory, forget) along with supporting operations for stats and backup/migration via export/import. No obvious dead ends for the stated purpose.
Maintenance
Related MCP Connectors
- KogniteOAuthdev.kognite
Hosted agent memory: store, search, and recall facts across sessions from any MCP client.
- memnodeOAuthdev.memnode
Persistent, inspectable memory for AI agents with lineage, correction, and a hosted MCP endpoint.
Cloud-hosted MCP server for durable AI memory
Persistent memory for AI agents across Claude, ChatGPT and any MCP client.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceA local-first MCP memory server providing persistent, searchable memory for AI agents, powered by SQLite.1 npm1Apache 2.0
- AlicenseNot gradedqualityDmaintenanceA local-first MCP server providing persistent, searchable knowledge base via SQLite, enabling AI agents to save and recall facts across sessions without cloud dependencies.MIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server that provides persistent long-term memory for AI agents via local SQLite storage with low token overhead, enabling memory storage, retrieval, and management across sessions.1MIT
- AlicenseAqualityCmaintenanceA local-first MCP server for durable agent memory using SQLite and FTS5, enabling knowledge graph storage, search, and recall for AI agents.201MIT