Skip to main content
Glama
AleBrito124356

mcp-memory-vault

mcp-memory-vault

tests Python MCP SDK License: MIT

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

remember

content, namespace="default", tags=[], ttl_days=0, source=""

The stored memory. An exact duplicate (same content in the same namespace) is never stored twice: the existing memory comes back with "deduplicated": true, and new tags are merged into it ("merged_tags"). ttl_days=0 means it never expires.

recall

query, namespace="", tags=[], limit=8, match="auto"

Ranked hits with a snippet (matches in [brackets]), matched_terms, tags and a readable age ("3 days ago"), plus the normalised terms and the match_mode used. See How recall works.

forget

memory_id

Deletion confirmation with a preview of what was removed.

list_memories

namespace="", tag="", limit=20

Most recent memories first, including expires_at when a TTL is set.

update_memory

memory_id, content="", add_tags=[], ttl_days=-1, remove_tags=[], namespace="", source=""

The updated memory plus updated_fields. ttl_days: -1 keep, 0 remove, >0 expire that many days from now. namespace moves the memory. A change that would duplicate another memory is refused, and the error names that memory.

memory_stats

none

Totals, counts per namespace, the most used tags, active-TTL count, database size and path, schema_version, and search_mode ("fts5" or "like").

export_memories

namespace=""

All memories as JSON-serialisable dicts, ready for backup or migration.

import_memories

memories (the array from export_memories)

Counts of imported, skipped (duplicates) and expired items. The whole batch is validated first and written in one transaction.

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:

  1. It is split on anything that is not a letter or digit, so ACME's, deploy? and dark-mode work.

  2. Filler words are dropped (a compact English and Spanish list: "when", "does", "the", "que", "el"...), unless the query is nothing but filler.

  3. Words of three or more letters also match by prefix of a light root: deploys finds "deploy", "deployed" and "deployment", kube finds "Kubernetes". FTS5's porter stemmer still matches the exact word's inflections.

Then match decides how the terms combine:

match

Behaviour

"auto" (default)

Memories containing every term. If there are none, memories containing any term, and the result carries a note saying the hits are partial.

"all"

Strict: every term must match.

"any"

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" .-> DB

What 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 IMMEDIATE transaction, 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-vault

Claude 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 publish workflow releases to PyPI when a v* tag is pushed, and server.json describes the package for the official MCP registry. Until then, uvx mcp-memory-vault and pip install mcp-memory-vault will 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

serve (or no command)

Run the MCP server on stdio.

add CONTENT

Remember a fact (-n namespace, -t tag (repeatable), --ttl-days, --source; - reads stdin).

search QUERY

Search (--match auto|all|any, -n, -t, --limit).

list

Most recent first (-n, -t, --limit).

show ID

One memory in full.

edit ID

--content, --add-tag, --remove-tag, --namespace (move), --source, --ttl-days.

forget ID [ID...]

Delete memories.

stats

Totals, namespaces, top tags, schema, size.

export [-o FILE]

JSON backup (stdout by default).

import FILE

Import an export (or a bare JSON array; - reads stdin). Duplicates are skipped.

doctor

Check Python, SQLite, FTS5, the database (writable, integrity, schema, index sync) and the installed mcp. Read-only; exits 1 on problems.

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_memory are folded into the oldest copy: tags are merged, the earliest created_at is 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_at field.

  • 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:

  • recall defaults to match="auto": when no memory contains every term, you now get partial matches (flagged with a note) instead of nothing. Pass match="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_memory refuses to turn a memory into a duplicate of another one.

  • import_memories is all-or-nothing and skips items that have already expired (reported as expired).

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 tree

The 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: spawns python -m mcp_memory_vault.server and 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 the mcp package.

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.

Part of a family of small, dependency-light MCP servers:

License

MIT

Available Tools

8 tools
export_memoriesExport memoriesA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
namespaceNoOnly export this namespace ("" = everything).

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 memoryA
Destructive

Permanently delete one memory by id.

Returns confirmation with the id and a truncated preview of what was deleted.

ParametersJSON Schema
NameRequiredDescriptionDefault
memory_idYesId of the memory to delete (from recall or list_memories).

TDQS

A3.6/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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 memoriesA
Idempotent

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"}.

ParametersJSON Schema
NameRequiredDescriptionDefault
memoriesYesThe "memories" array produced by export_memories.

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 memoriesA
Read-only

Browse stored memories, most recent first, without a search query.

Returns {"count", "memories": [...]} with expires_at included when a TTL is set.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoOnly list memories with this tag ("" = any).
limitNoMaximum number of memories.
namespaceNoOnly list this namespace ("" = all).

TDQS

A4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines4/5

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 statisticsA
Read-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).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.9/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 memoriesA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagsNoOnly return memories carrying ALL of these tags (case-insensitive).
limitNoMaximum number of hits.
matchNo"all" = every term must match; "any" = at least one, most terms first; "auto" = "all", falling back to "any" when nothing matches every term.auto
queryYesWhat to look for: key nouns ("ACME deploy") or a plain question ("when does ACME deploy?").
namespaceNoOnly search this namespace ("" = all namespaces).

TDQS

A4.1/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 factA
Idempotent

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".

ParametersJSON Schema
NameRequiredDescriptionDefault
tagsNoOptional short labels for filtering, e.g. ["customer", "deploy"].
sourceNoOptional provenance, e.g. "user message" or "ticket #123".
contentYesThe fact to remember, as one self-contained sentence that names its subject.
ttl_daysNoDays until the memory expires; 0 = never expires.
namespaceNoLogical bucket, e.g. one per project or user.default

TDQS

A4.3/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines4/5

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 memoryA
DestructiveIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
sourceNoNew provenance note ("" = keep the current one).
contentNoNew content ("" = keep the current content).
add_tagsNoTags to add on top of the existing ones.
ttl_daysNo-1 = leave the TTL unchanged, 0 = remove it (permanent), N > 0 = expire N days from now.
memory_idYesId of the memory to update.
namespaceNoMove the memory to this namespace ("" = keep).
remove_tagsNoTags to remove (case-insensitive).

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

  1. 8 tool updatesv0.2.0
    • First observedexport_memories
    • First observedforget
    • First observedimport_memories
    • First observedlist_memories
    • First observedmemory_stats
    • First observedrecall
    • First observedremember
    • First observedupdate_memory

TDQS

A4.2/5.0

Scored across 8 tools

Disambiguation5/5

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).

Naming Consistency4/5

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.

Tool Count5/5

Eight tools is well-scoped for a persistent memory vault, covering the core lifecycle plus maintenance operations without bloat. Every tool earns its place.

Completeness5/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    A local-first MCP memory server providing persistent, searchable memory for AI agents, powered by SQLite.
    1 npm
    1
    Apache 2.0
  • A
    license
    Not graded
    quality
    D
    maintenance
    A 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
  • A
    license
    Not graded
    quality
    C
    maintenance
    An 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.
    1
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    A local-first MCP server for durable agent memory using SQLite and FTS5, enabling knowledge graph storage, search, and recall for AI agents.
    20
    1
    MIT