Memlord
โจ Features
๐ Hybrid search โ BM25 (full-text) + vector KNN (pgvector) fused via Reciprocal Rank Fusion
๐ Multi-user โ each user sees only their own memories; workspaces for shared team knowledge
๐ ๏ธ 10 MCP tools โ store, retrieve, recall, list, search by tag, get, update, delete, move, list workspaces
๐ Web UI โ browse, search, edit and delete memories in the browser; export/import JSON
๐ OAuth 2.1 โ full in-process authorization server, always enabled
๐ PostgreSQL โ pgvector for embeddings, tsvector for full-text search
๐ Progressive disclosure โ search returns compact snippets by default; call
get_memory(id)only for what you need, reducing token usage๐ Deduplication โ automatically detects near-identical memories before saving, preventing noise accumulation
Related MCP server: Memory MCP Server
๐ How Memlord compares
Memlord | ||||
Search | BM25 + vector + RRF | Vector only (Qdrant) | BM25 + vector + RRF | BM25 + vector |
Embeddings | Local ONNX, zero config | OpenAI default; Ollama optional | Local ONNX, zero config | Local FastEmbed |
Storage | PostgreSQL + pgvector | PostgreSQL + Qdrant | SQLite-vec / Cloudflare Vectorize | SQLite + Markdown files |
Multi-user | โ | โ single-user in practice | โ ๏ธ agent-ID scoping, no isolation | โ |
Workspaces | โ shared + personal, invite links | โ ๏ธ "Apps" namespace | โ ๏ธ tags + conversation_id | โ per-project flag |
Authentication | โ OAuth 2.1 | โ none (self-hosted) | โ OAuth 2.0 + PKCE | โ |
Web UI | โ browse, edit, export | โ Next.js dashboard | โ rich UI, graph viz, quality scores | โ local; cloud only |
MCP tools | 10 | 5 | 15+ | ~20 |
Self-hosted | โ single process | โ Docker (3 containers) | โ | โ |
Memory input | Manual (explicit store) | Auto-extracted by LLM | Manual | Manual (Markdown notes) |
Memory types | fact / preference / instruction / feedback | auto-extracted facts | โ | observations + wiki links |
Time-aware search | โ natural language dates | โ ๏ธ REST only, not in MCP tools | โ | โ recent_activity |
Token efficiency | โ progressive disclosure | โ | โ | โ build_context traversal |
Import / Export | โ JSON | โ ZIP (JSON + JSONL) | โ | โ Markdown (human-readable) |
License | AGPL-3.0 / Commercial | Apache 2.0 | Apache 2.0 | AGPL-3.0 |
Where competitors have a real edge:
OpenMemory โ auto-extracts memories from raw conversation text; no need to decide what to store manually; good import/export
mcp-memory-service โ richer web UI (graph visualization, quality scoring, 8 tabs); more permissive license (Apache 2.0); multiple transport options (stdio, SSE, HTTP)
basic-memory โ memories are human-readable Markdown files you can edit, version-control, and read without any server; wiki-style entity links form a local knowledge graph; ~20 MCP tools
When to pick Memlord:
You want zero-config local embeddings โ ONNX model ships with the server, no Ollama or external API needed
You run a multi-user team server with proper OAuth 2.1 auth and invite-based workspaces
You want a production-grade database (PostgreSQL) that scales beyond a single machine's SQLite
You manage memories explicitly โ store exactly what matters, typed and tagged, not everything the LLM decides to extract
You want a self-hosted Web UI with full CRUD and JSON export, without a cloud subscription
๐ Quickstart
๐ณ Docker
cp .env.example .env
docker compose upHTTP server (multi-user, Web UI, OAuth)
# Install dependencies
uv sync --dev
# Download ONNX model (~23 MB)
uv run python scripts/download_model.py
# Run migrations
alembic upgrade head
# Start the server
memlordOpen http://localhost:8000 for the Web UI. The MCP endpoint is at /mcp.
STDIO (local single-user, no OAuth)
STDIO mode runs the MCP server over stdin/stdout โ no HTTP port, no OAuth. Ideal for local use with Claude Desktop or Claude Code.
Set MEMLORD_STDIO_USER_ID to your user ID (created after first HTTP login, or 1 for a fresh DB) so all memories are
scoped to your account.
pip install memlordCreate .mcp.json and adjust the paths and env vars:
{
"mcpServers": {
"memlord-local": {
"command": "python",
"args": [
"memlord",
"--stdio"
],
"env": {
"MEMLORD_DB_URL": "postgresql+asyncpg://postgres:postgres@localhost/memlord",
"MEMLORD_STDIO_USER_ID": "1"
}
}
}
}๐ How It Works
Each search request runs BM25 and vector KNN in parallel, then merges results via Reciprocal Rank Fusion:
flowchart TD
Q([query]) --> BM25["BM25\nsearch_vector @@ websearch_to_tsquery"]
Q --> EMB["ONNX embed\nall-MiniLM-L6-v2 ยท 384d ยท local"]
EMB --> KNN["KNN\nembedding <=> query_vector\ncosine distance"]
BM25 --> RRF["RRF fusion\nscore = 1/(k+rank_bm25) + 1/(k+rank_vec)\nk=60"]
KNN --> RRF
RRF --> R([top-N results])โ๏ธ Configuration
All settings use the MEMLORD_ prefix. See .env.example for the full list.
Variable | Default | Description |
|
| PostgreSQL connection URL |
|
| Server port |
|
| Public URL for OAuth (HTTP mode) |
|
| JWT signing secret (HTTP mode) |
| โ | User ID to use in STDIO mode (required for stdio) |
In HTTP mode, set MEMLORD_BASE_URL to your public URL and change MEMLORD_OAUTH_JWT_SECRET before deploying.
In STDIO mode, OAuth is skipped โ set MEMLORD_STDIO_USER_ID to your numeric user ID instead.
๐ ๏ธ MCP Tools
Tool | Description |
| Save a memory (idempotent by content); raises on near-duplicates |
| Hybrid semantic + full-text search; returns snippets by default |
| Search by natural-language time expression; returns snippets by default |
| Paginated list with type/tag filters |
| AND/OR tag search |
| Fetch a single memory by ID with full content |
| Update content, type, tags, or metadata by ID |
| Delete by ID |
| Move a memory to a different workspace |
| List workspaces you are a member of (including personal) |
Workspace management (create, invite, join, leave) is handled via the Web UI.
๐ป System Requirements
Python 3.12
PostgreSQL โฅ 15 with pgvector extension
uv โ Python package manager
๐จโ๐ป Development
pyright src/ # type check
ruff format . # format
pytest # run tests
alembic-autogen-check # verify migrations are up to date๐ License
Memlord is dual-licensed:
AGPL-3.0 โ free for open-source use. If you run a modified version as a network service, you must publish your source code.
Commercial License โ for proprietary or closed-source deployments. Contact sergey@memlord.com or dmitry@memlord.com to purchase.
Available Tools
11 toolsdelete_memoryADestructive
Delete a memory by name. Pass workspace to disambiguate if the name exists in multiple workspaces.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| workspace | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate destructiveHint=true, so description does not need to repeat destructiveness. It adds useful disambiguation context, but no further behavioral traits beyond what annotations provide.
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 sentences, no filler. First sentence states primary action, second adds optional guidance. Ideal conciseness for a simple tool.
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?
Given simple tool with 2 params and output schema present, description covers core operation and disambiguation. Missing details like permissions or confirmation, but adequate for invocation.
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 has 0% description coverage for parameters. Description adds the purpose of workspace (disambiguation), but does not describe name parameter type or constraints, leaving gaps.
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?
Description clearly states 'Delete a memory by name', specifying verb and resource. Sibling tools (get_memory, list_memories, etc.) have different purposes, so no ambiguity.
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?
Description explains when to use workspace parameter for disambiguation, but does not explicitly state when not to use this tool or suggest alternatives like update_memory if deletion is not intended.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
dream_reportARead-only
Candidates for memory consolidation: similar pairs, expired and expiring memories.
Read-only. The report only proposes candidates โ reviewing and acting on them
(merge, supersede, extend, delete) is done via the regular memory tools.
Similar pairs are always within a single workspace, ordered by similarity.
Use the dream prompt for the full guided consolidation procedure.
| Name | Required | Description | Default |
|---|---|---|---|
| max_pairs | No | ||
| workspace | No | Limit the report to one workspace (must have write access). Omit to cover all write-accessible workspaces. | |
| similarity_threshold | No | Minimum cosine similarity for a pair of memories to be reported. |
Output Schema
| Name | Required | Description |
|---|---|---|
| expired | No | Already-expired memories, hidden from reads but not yet purged. |
| expiring_soon | No | Memories expiring within the next 7 days; extend expires_at if still valuable. |
| similar_pairs | No | Pairs of semantically close memories within one workspace, candidates for merge/supersession review. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, and the description reinforces the non-mutating nature by stating it only proposes candidates. It also adds a behavioral detail annotations cannot convey: similar pairs are always within a single workspace and ordered by similarity. It stops short of describing result volume or what the report body contains.
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 what the report contains, then the read-only constraint, then routing guidance โ a sensible order. Every sentence carries information, though the fragment-style opening sentence is slightly compressed for the amount of detail it introduces.
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?
An output schema exists, so return-value documentation is unnecessary, and annotations cover the safety profile. Combined with the description's coverage of scope, ordering, read-only behavior, and follow-up routing, an agent has everything needed to call this correctly.
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 67% โ `workspace` and `similarity_threshold` are documented in the schema, but `max_pairs` has no description. The description's note that pairs are single-workspace and similarity-ordered adds context relevant to two of the three parameters, but it does not compensate for the undocumented `max_pairs` or clarify threshold/limit semantics beyond the schema.
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?
The description names a specific resource and scope: a report of consolidation candidates consisting of similar pairs plus expired/expiring memories. It clearly distinguishes itself from the sibling memory tools by stating it only proposes candidates while merge/supersede/extend/delete happen elsewhere.
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?
It explicitly routes the agent: this tool is for reviewing candidates, acting on them uses the regular memory tools, and the full guided procedure lives in the `dream` prompt. Both the alternative and the escalation path are named, not inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_memoryARead-only
Fetch full content of a single memory by name.
Use only when you already know the name โ e.g. after retrieve_memory() or recall_memory() which return names in their results alongside compact snippets. Do NOT use for search โ use retrieve_memory() for semantic/text search or recall_memory() for time-based queries like 'last week'. Unlike search, this also returns expired memories (expires_at in the past) โ check expires_at to tell; extend it via update_memory to bring one back.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| workspace | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| tags | Yes | |
| content | Yes | |
| metadata | No | |
| workspace | No | |
| created_at | Yes | |
| expires_at | No | |
| memory_type | Yes | fact: established fact about user, project, or system. preference: user's likes, dislikes, habits. instruction: persistent rule Claude must follow. feedback: evaluation of Claude's output. decision: a choice made with reasoning ('chose X over Y because Z'). insight: consolidated conclusion distilled from several existing memories. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish the safe read profile (readOnlyHint=true, destructiveHint=false), but the description adds a genuinely non-obvious behavior: this lookup returns expired memories that search hides, and tells the agent how to detect (expires_at) and remedy (update_memory) that state. It does not cover permissions, pagination, or duplicate-name behavior, so it falls short of a 5.
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 usage, then exclusions in short scannable clauses. Every sentence carries actionable content โ positive precondition, negative routing, and the expired-memory caveat โ with no filler.
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?
An output schema exists, so return-value explanation is unnecessary, and the description covers selection criteria, alternatives, and the expired-memory edge case. The only real gap is the unexplained 'workspace' parameter, which prevents a 5.
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?
With 0% schema description coverage, the description carries the full burden, and it does clarify that 'name' is a memory identifier sourced from retrieve_memory/recall_memory results. However, the optional 'workspace' parameter is never mentioned in the description or the schema, leaving its scope and default semantics unexplained.
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 ('Fetch full content of a single memory by name') and immediately contrasts itself with the two nearest siblings, retrieve_memory() and recall_memory(). An agent can distinguish this tool from search-style siblings without opening any schema.
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 an explicit precondition ('Use only when you already know the name'), names where names come from ('after retrieve_memory() or recall_memory()'), and states an explicit when-not with the correct alternatives for both semantic/text search and time-based queries. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_memoriesARead-only
Browse all memories ordered by creation date (newest first). Returns full content (not snippets). Use to enumerate or audit without a specific query.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | Case-insensitive exact match on a single tag name | |
| page | No | ||
| page_size | No | ||
| memory_type | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| page | No | |
| items | No | |
| total | No | |
| page_size | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds useful behavior beyond that: result ordering (newest first) and that full content is returned rather than snippets. It says nothing about pagination limits or result volume, which would have been the last piece.
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 sentences, zero filler. Ordering and return format come first, and the intended use case is stated last in a single compact clause.
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?
An output schema exists, so return values need not be re-explained, and the description still helpfully characterizes them as full content. For a read-only list tool with annotations covering safety, the only real omission is pagination guidance for the otherwise-undocumented page/page_size parameters.
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 only 25%: tag and memory_type are documented in the schema, but page and page_size carry no descriptions. The description adds no parameter information at all โ notably it never mentions that results are paginated or how page/page_size interact โ so it fails to compensate for the documented coverage gap.
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 (browse/enumerate) and resource (memories), plus concrete scope details: ordered by creation date newest-first and full content rather than snippets. The phrase 'without a specific query' implicitly separates it from query-driven siblings like search_by_tag or recall_memory, though no sibling is named.
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 ('Use to enumerate or audit without a specific query'), which tells the agent when this tool is appropriate versus retrieval/search tools. It stops short of naming specific alternatives or explicit when-not conditions, so it falls just 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.
list_workspacesARead-only
List all workspaces you are a member of (personal + shared).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint=true and destructiveHint=false. Description adds that it lists workspaces the user is a member of (personal + shared), providing context beyond annotations. No contradictions.
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?
Single sentence, front-loaded, no wasted words. Perfectly concise.
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?
Tool has no parameters, has output schema, annotations cover safety, description covers purpose and scope. Complete for a simple read-only list 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?
No parameters; schema description coverage is 100%. Baseline score of 4 for 0 parameters, as description adds no parameter info but none is needed.
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?
Description clearly states the tool lists all workspaces the user is a member of, specifying personal and shared. Verb 'List' and resource 'workspaces' are precise. Sibling tools are all memory-related, so no confusion.
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?
Description indicates when to use: to list workspaces. No explicit exclusion or alternatives, but given the tool's self-contained nature and distinct sibling set, the guidance is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
move_memoryA
Move a memory to a different to_workspace.
name: name of the memory to move. workspace: name of the target workspace (must be a member with write access). from_workspace: disambiguate source if the name exists in multiple workspaces.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| to_workspace | Yes | ||
| from_workspace | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| created | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations indicate non-destructive, but 'move' typically removes from source. The description adds workspace access requirement but does not clarify if memory is removed from source, potential side effects, or atomicity. There is a mild contradiction with destructiveHint=false.
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 description is concise with four lines covering the action and parameters. However, parameter descriptions are listed separately rather than integrated, slightly reducing flow.
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?
While the description covers parameters and basic action, it does not explain return values (despite output schema existing), error cases, or behavior on name conflict. For a 3-parameter tool, this is adequate but not comprehensive.
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 description explains each parameter with purpose and constraints (e.g., 'to_workspace: must be a member with write access', 'from_workspace: disambiguate source'). This adds significant value beyond the bare schema, especially with 0% schema description coverage.
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?
The description clearly states the action ('Move a memory') and the target ('to a different to_workspace'). It distinguishes this tool from siblings like delete_memory or store_memory by focusing on relocation.
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 implies usage for moving a memory between workspaces but does not provide explicit guidance on when to use vs. not use this tool, nor does it mention alternatives like update_memory for changing properties.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
recall_memoryARead-only
Search memories by time expression + semantics. Returns names + metadata only.
Examples: "last week", "yesterday", "about Python last month". Use get_memory(name=...) to fetch full content of a specific result. Pass workspace= to search only within a specific workspace.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Query string | |
| n_results | No | ||
| workspace | No | ||
| memory_type | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds one useful behavioral fact โ results are truncated to names and metadata rather than full records. It says nothing about result counts, ranking, or pagination beyond that, and an output schema already exists, so a 3 is appropriate.
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?
Four tight lines: capability plus output contract first, then examples, then the escape hatch to get_memory, then the workspace scoping note. Every sentence carries distinct information and nothing is repeated from the 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 an output schema present and annotations covering the safety profile, the description only needs to cover invocation semantics, which it largely does via query format examples, the result-truncation contract, and the get_memory follow-up. The unexplained n_results parameter is the one remaining gap for a search 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 only 25%, so the description must compensate, and it partially does: it explains the query accepts time expressions plus semantics and gives three concrete examples, and it explains the workspace scope parameter. It says nothing about n_results or memory_type, leaving two of four parameters to the schema alone.
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?
The description gives a specific verb and resource (search memories) and narrows scope to time expression + semantics, plus an explicit output boundary (names + metadata only). That output boundary meaningfully separates it from get_memory, which fetches full content. It does not clearly separate itself from the sibling retrieve_memory, which keeps it 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?
It gives a concrete follow-up path (use get_memory(name=...) for full content) and a scoping rule (pass workspace=<name> to restrict the search), which tells the agent when to reach for this tool. It lacks explicit exclusions relative to retrieve_memory and list_memories, so it is clear context rather than full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retrieve_memoryARead-only
Hybrid semantic + full-text search. Returns names + metadata only.
Use get_memory(name=...) to fetch full content of a specific result. Pass workspace= to search only within a specific workspace.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | Query string | |
| workspace | No | ||
| memory_type | No | ||
| similarity_threshold | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint=true and destructiveHint=false, so safety is covered. The description adds a genuinely useful behavioral trait beyond the annotations: results are truncated to "names + metadata only," which tells the agent why a follow-up call is needed. It omits pagination/limit behavior and any rate or auth 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?
Three short lines, zero filler, and the core mechanism and the "metadata only" caveat are front-loaded before the pointers to the alternative tool. 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?
An output schema exists, so return values need not be described, and the description correctly focuses on routing and scoping. The remaining gap is the undocumented tuning parameters (limit, similarity_threshold), which is the one thing an agent needs before calling this search tool correctly.
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 only 20%, so the description carries the burden for the other parameters. It explains workspace scoping semantics, but says nothing about limit (result count/pagination), similarity_threshold (what it controls or how the default 0.25 behaves), while memory_type is documented only inside the schema enum text. Two of five parameters remain undocumented anywhere.
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?
The description names the retrieval mechanism precisely ("Hybrid semantic + full-text search") and, together with the tool name retrieve_memory, makes the resource unambiguous. It also distinguishes itself from get_memory, so an agent can separate the two siblings without opening schemas. It stops just short of 5 because it never restates the resource explicitly (memories).
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?
It gives an explicit alternative and the condition for choosing it: "Use get_memory(name=...) to fetch full content of a specific result," plus a scoping condition for workspace. It does not address other plausible siblings (recall_memory, search_by_tag, list_memories), so coverage is good but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_by_tagARead-only
Find memories by exact tag match. Returns all results (no pagination).
operation="AND" (default): memory must have ALL specified tags. operation="OR": memory must have AT LEAST ONE of the specified tags. Tags are case-insensitive. Use retrieve_memory() for semantic/text search or list_memories(tag=...) to browse a single tag with pagination.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | Yes | ||
| operation | No | AND |
Output Schema
| Name | Required | Description |
|---|---|---|
| page | No | |
| items | No | |
| total | No | |
| page_size | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint=true, destructiveHint=false), but the description adds real behavioral context: no pagination (all results returned) and case-insensitive tag matching. It does not discuss result ordering or limits, but for a read-only search tool this is solid added value.
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 purpose and the non-pagination caveat, then the operation semantics, then routing to alternatives. Four short sentences, each earning its place with no repetition of the 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?
An output schema exists, so return-value explanation is unnecessary, and the description still notes the all-results/no-pagination behavior. Combined with explicit sibling routing and enum semantics, an agent has everything needed to invoke this correctly.
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 0%, so the description must carry the load, and it does: it defines operation='AND' (default, all tags required) vs 'OR' (at least one tag), and clarifies tags are exact and case-insensitive. Only minor gaps remain, such as the uniqueItems constraint in the schema.
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 ('Find memories by exact tag match') and immediately narrows scope with 'exact tag match' plus 'Returns all results (no pagination)'. It is clearly distinguishable from retrieve_memory and list_memories, both of which are named explicitly.
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 routes the agent: use retrieve_memory() for semantic/text search and list_memories(tag=...) to browse a single tag with pagination, implying this tool for multi-tag exact matching without pagination. The when-to-use and when-to-use-something-else conditions are both stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
store_memoryAIdempotent
Save a new memory. Idempotent: returns existing if content already stored.
name: human-readable name, unique within the workspace. workspace: name of the workspace to store into. Omit to store as a personal memory. force: skip near-duplicate check and store unconditionally. expires_at: optional UTC expiry; after it passes the memory is hidden from reads.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| tags | No | ||
| force | No | Skip near-duplicate check and store unconditionally. | |
| content | Yes | ||
| metadata | No | ||
| workspace | No | Name of the workspace to store into (must be a member). Omit or pass None to store as a personal memory. | |
| expires_at | No | UTC timestamp after which the memory is hidden from search and list results (still retrievable by exact name via get_memory). Expired memories are purged via the profile 'clean up expired' button. None = never expires. | |
| memory_type | Yes | fact: established fact about user, project, or system. preference: user's likes, dislikes, habits. instruction: persistent rule Claude must follow. feedback: evaluation of Claude's output. decision: a choice made with reasoning ('chose X over Y because Z'). insight: consolidated conclusion distilled from several existing memories. |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| created | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint=true and destructiveHint=false, so the baseline is set. The description adds real value beyond them: a near-duplicate check runs by default and is skipped only with force, expired memories remain retrievable by exact name via get_memory, and purging happens through a profile clean-up action. It does not describe return shape, but that is defensible given the idempotency note.
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 one-line purpose followed by compact per-parameter bullets; nothing is wasted. The only blemish is that the workspace and force blurbs are near-verbatim duplicates of the schema descriptions, which is mild redundancy rather than bloat.
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?
An output schema exists, so return values need no explanation, and the description covers creation semantics, dedup behavior, workspace scoping, and expiry. It is adequate for an 8-parameter write tool, though it could say more about what content or memory_type should contain and where the sibling update_memory takes over.
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?
With only 50% schema description coverage across 8 parameters, the description must compensate, and it does for the four most ambiguous ones: name uniqueness, workspace membership vs personal-memory default, force semantics, and the expiry lifecycle. content, tags, and metadata are left unexplained, but those are largely self-evident and memory_type carries a detailed enum in the schema.
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?
The opening sentence gives a specific verb+resource ("Save a new memory") and the word "new" implicitly distinguishes it from the update_memory sibling. However, it never explicitly names or contrasts with update_memory, recall_memory, or retrieve_memory, so an agent must infer the boundary itself.
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 states the tool is idempotent and returns existing content, which implies the caller need not pre-check for duplicates, but it never states when to use this over update_memory for existing memories or why not to use it for retrieval. No prerequisites, exclusions, or alternative routing are given despite ten siblings covering overlapping memory operations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_memoryB
Update an existing memory identified by name. Only provided fields are changed.
new_name: rename the memory to this name. workspace: disambiguate if the name exists in multiple workspaces. expires_at: set or extend the UTC expiry; omit to leave it unchanged.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| tags | No | ||
| content | No | ||
| metadata | No | ||
| new_name | No | ||
| workspace | No | ||
| expires_at | No | Set or extend the UTC expiry. Omit to leave unchanged. | |
| memory_type | Yes | fact: established fact about user, project, or system. preference: user's likes, dislikes, habits. instruction: persistent rule Claude must follow. feedback: evaluation of Claude's output. decision: a choice made with reasoning ('chose X over Y because Z'). insight: consolidated conclusion distilled from several existing memories. |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| created | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare idempotentHint=false and destructiveHint=false; the description usefully adds that unspecified fields are preserved, which is not in the annotations. It still omits what happens on name collision, whether renames are reversible, and why the call is non-idempotent, so it adds partial rather than rich behavioral 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?
Four short lines, front-loaded with the core action and then one line per non-obvious field. The per-field list is efficient, though the expires_at line is a verbatim restatement of the schema description and earns no new 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?
An output schema exists, so return-value explanation is unnecessary, and the partial-update rule is stated. For an 8-parameter mutation tool with non-idempotent behavior, the description is still thin on collision/rename semantics and on how content, tags, and metadata interact with existing values.
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 only 25%, so the description carries extra burden. It explains new_name, workspace, and expires_at, and duplicates the schema's expires_at wording, but says nothing about tags, content, or metadata โ including whether they replace or merge with existing values, which is the most consequential ambiguity for a 8-parameter tool.
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 ('Update an existing memory') and adds the partial-update semantic ('Only provided fields are changed'), which is a meaningful differentiator from store_memory or delete_memory. It does not, however, distinguish itself from move_memory, which appears to be the natural alternative for changing workspace.
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 implied through the field explanations: workspace is described as a disambiguator and expires_at as an extend-or-set action. There is no explicit when-to-use framing, and the workspace note potentially conflicts with the existence of move_memory, leaving the agent to infer which tool performs workspace changes.
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.9- Added
dream_report - Changed
get_memory3 fields changed- added
Output schema / properties / expires_atAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] +} - changed
Output schema / properties / memory_type / descriptionPrevious value: -"fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z')."New value: +"fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').\ninsight: consolidated conclusion distilled from several existing memories." - changed
Output schema / properties / memory_type / enumPrevious value: -[ - "fact", - "preference", - "instruction", - "feedback", - "decision" -]New value: +[ + "fact", + "preference", + "instruction", + "feedback", + "decision", + "insight" +]
- Changed
list_memories4 fields changed- changed
Input schema / properties / memory_type / anyOfPrevious value: -[ - { - "description": "fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').", - "enum": [ - "fact", - "preference", - "instruction", - "feedback", - "decision" - ], - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "description": "fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').\ninsight: consolidated conclusion distilled from several existing memories.", + "enum": [ + "fact", + "preference", + "instruction", + "feedback", + "decision", + "insight" + ], + "type": "string" + }, + { + "type": "null" + } +] - added
Output schema / properties / items / items / properties / expires_atAdded value: +{ + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Expires At" +} - changed
Output schema / properties / items / items / properties / memory_type / descriptionPrevious value: -"fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z')."New value: +"fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').\ninsight: consolidated conclusion distilled from several existing memories." - changed
Output schema / properties / items / items / properties / memory_type / enumPrevious value: -[ - "fact", - "preference", - "instruction", - "feedback", - "decision" -]New value: +[ + "fact", + "preference", + "instruction", + "feedback", + "decision", + "insight" +]
- Changed
recall_memory2 fields changed- changed
Input schema / properties / memory_type / anyOfPrevious value: -[ - { - "description": "fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').", - "enum": [ - "fact", - "preference", - "instruction", - "feedback", - "decision" - ], - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "description": "fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').\ninsight: consolidated conclusion distilled from several existing memories.", + "enum": [ + "fact", + "preference", + "instruction", + "feedback", + "decision", + "insight" + ], + "type": "string" + }, + { + "type": "null" + } +] - changed
Output schema / properties / items / items / properties / memory_type / anyOfPrevious value: -[ - { - "description": "fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').", - "enum": [ - "fact", - "preference", - "instruction", - "feedback", - "decision" - ], - "title": "MemoryType", - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "description": "fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').\ninsight: consolidated conclusion distilled from several existing memories.", + "enum": [ + "fact", + "preference", + "instruction", + "feedback", + "decision", + "insight" + ], + "title": "MemoryType", + "type": "string" + }, + { + "type": "null" + } +]
- Changed
retrieve_memory3 fields changed- changed
Input schema / properties / memory_type / anyOfPrevious value: -[ - { - "description": "fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').", - "enum": [ - "fact", - "preference", - "instruction", - "feedback", - "decision" - ], - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "description": "fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').\ninsight: consolidated conclusion distilled from several existing memories.", + "enum": [ + "fact", + "preference", + "instruction", + "feedback", + "decision", + "insight" + ], + "type": "string" + }, + { + "type": "null" + } +] - changed
Output schema / properties / result / items / properties / memory_type / descriptionPrevious value: -"fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z')."New value: +"fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').\ninsight: consolidated conclusion distilled from several existing memories." - changed
Output schema / properties / result / items / properties / memory_type / enumPrevious value: -[ - "fact", - "preference", - "instruction", - "feedback", - "decision" -]New value: +[ + "fact", + "preference", + "instruction", + "feedback", + "decision", + "insight" +]
- Changed
search_by_tag3 fields changed- added
Output schema / properties / items / items / properties / expires_atAdded value: +{ + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Expires At" +} - changed
Output schema / properties / items / items / properties / memory_type / descriptionPrevious value: -"fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z')."New value: +"fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').\ninsight: consolidated conclusion distilled from several existing memories." - changed
Output schema / properties / items / items / properties / memory_type / enumPrevious value: -[ - "fact", - "preference", - "instruction", - "feedback", - "decision" -]New value: +[ + "fact", + "preference", + "instruction", + "feedback", + "decision", + "insight" +]
- Changed
store_memory3 fields changed- added
Input schema / properties / expires_atAdded value: +{ + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "UTC timestamp after which the memory is hidden from search and list results (still retrievable by exact name via get_memory). Expired memories are purged via the profile 'clean up expired' button. None = never expires." +} - changed
Input schema / properties / memory_type / descriptionPrevious value: -"fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z')."New value: +"fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').\ninsight: consolidated conclusion distilled from several existing memories." - changed
Input schema / properties / memory_type / enumPrevious value: -[ - "fact", - "preference", - "instruction", - "feedback", - "decision" -]New value: +[ + "fact", + "preference", + "instruction", + "feedback", + "decision", + "insight" +]
- Changed
update_memory3 fields changed- added
Input schema / properties / expires_atAdded value: +{ + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Set or extend the UTC expiry. Omit to leave unchanged." +} - changed
Input schema / properties / memory_type / descriptionPrevious value: -"fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z')."New value: +"fact: established fact about user, project, or system.\npreference: user's likes, dislikes, habits.\ninstruction: persistent rule Claude must follow.\nfeedback: evaluation of Claude's output.\ndecision: a choice made with reasoning ('chose X over Y because Z').\ninsight: consolidated conclusion distilled from several existing memories." - changed
Input schema / properties / memory_type / enumPrevious value: -[ - "fact", - "preference", - "instruction", - "feedback", - "decision" -]New value: +[ + "fact", + "preference", + "instruction", + "feedback", + "decision", + "insight" +]
10 tool updates
- Added
delete_memory - Added
get_memory - Added
list_memories - Added
list_workspaces - Added
move_memory - Added
recall_memory - Added
retrieve_memory - Added
search_by_tag - Added
store_memory - Added
update_memory
10 tool updates
v0.2.8- Removed
delete_memory - Removed
get_memory - Removed
list_memories - Removed
list_workspaces - Removed
move_memory - Removed
recall_memory - Removed
retrieve_memory - Removed
search_by_tag - Removed
store_memory - Removed
update_memory
5 tool updates
v0.2.7- Changed
get_memory1 field changed- removed
Output schema / properties / created_at / formatRemoved value: -"date-time"
- Changed
list_memories5 fields changed- added
Output schema / properties / page / defaultAdded value: +1 - added
Output schema / properties / page_size / defaultAdded value: +0 - added
Output schema / properties / total / defaultAdded value: +0 - added
Output schema / properties / total_pages / defaultAdded value: +0 - removed
Output schema / requiredRemoved value: -[ - "items", - "total", - "page", - "page_size", - "total_pages" -]
- Changed
recall_memory5 fields changed- added
Output schema / properties / itemsAdded value: +{ + "items": { + "properties": { + "content": { + "title": "Content", + "type": "string" + }, + "created_at": { + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "id": { + "title": "Id", + "type": "integer" + }, + "memory_type": { + "anyOf": [ + { + "enum": [ + "fact", + "preference", + "instruction", + "feedback" + ], + "title": "MemoryType", + "type": "string" + }, + { + "type": "null" + } + ] + }, + "tags": { + "items": { + "type": "string" + }, + "title": "Tags", + "type": "array", + "uniqueItems": true + }, + "workspace_id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Workspace Id" + } + }, + "required": [ + "id", + "content", + "memory_type", + "tags", + "created_at" + ], + "title": "RecallResult", + "type": "object" + }, + "title": "Items", + "type": "array" +} - removed
Output schema / properties / resultRemoved value: -{ - "items": { - "properties": { - "content": { - "type": "string" - }, - "created_at": { - "format": "date-time", - "type": "string" - }, - "id": { - "type": "integer" - }, - "memory_type": { - "anyOf": [ - { - "enum": [ - "fact", - "preference", - "instruction", - "feedback" - ], - "type": "string" - }, - { - "type": "null" - } - ] - }, - "tags": { - "items": { - "type": "string" - }, - "type": "array", - "uniqueItems": true - }, - "workspace_id": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null - } - }, - "required": [ - "id", - "content", - "memory_type", - "tags", - "created_at" - ], - "type": "object" - }, - "type": "array" -} - removed
Output schema / requiredRemoved value: -[ - "result" -] - added
Output schema / titleAdded value: +"RecallPage" - removed
Output schema / x-fastmcp-wrap-resultRemoved value: -true
- Changed
retrieve_memory1 field changed- removed
Output schema / properties / result / items / properties / created_at / formatRemoved value: -"date-time"
- Changed
search_by_tag9 fields changed- added
Output schema / properties / itemsAdded value: +{ + "items": { + "properties": { + "content": { + "title": "Content", + "type": "string" + }, + "created_at": { + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "id": { + "title": "Id", + "type": "integer" + }, + "memory_type": { + "enum": [ + "fact", + "preference", + "instruction", + "feedback" + ], + "title": "MemoryType", + "type": "string" + }, + "metadata": { + "additionalProperties": true, + "title": "Metadata", + "type": "object" + }, + "tags": { + "items": { + "type": "string" + }, + "title": "Tags", + "type": "array", + "uniqueItems": true + }, + "workspace_id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Workspace Id" + } + }, + "required": [ + "id", + "content", + "memory_type", + "tags", + "created_at" + ], + "title": "MemoryListItem", + "type": "object" + }, + "title": "Items", + "type": "array" +} - added
Output schema / properties / pageAdded value: +{ + "default": 1, + "title": "Page", + "type": "integer" +} - added
Output schema / properties / page_sizeAdded value: +{ + "default": 0, + "title": "Page Size", + "type": "integer" +} - removed
Output schema / properties / resultRemoved value: -{ - "items": { - "properties": { - "content": { - "type": "string" - }, - "created_at": { - "format": "date-time", - "type": "string" - }, - "id": { - "type": "integer" - }, - "memory_type": { - "enum": [ - "fact", - "preference", - "instruction", - "feedback" - ], - "type": "string" - }, - "metadata": { - "additionalProperties": true, - "type": "object" - }, - "tags": { - "items": { - "type": "string" - }, - "type": "array", - "uniqueItems": true - }, - "workspace_id": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null - } - }, - "required": [ - "id", - "content", - "memory_type", - "tags", - "created_at" - ], - "type": "object" - }, - "type": "array" -} - added
Output schema / properties / totalAdded value: +{ + "default": 0, + "title": "Total", + "type": "integer" +} - added
Output schema / properties / total_pagesAdded value: +{ + "default": 0, + "title": "Total Pages", + "type": "integer" +} - removed
Output schema / requiredRemoved value: -[ - "result" -] - added
Output schema / titleAdded value: +"MemoryPage" - removed
Output schema / x-fastmcp-wrap-resultRemoved value: -true
10 tool updates
v0.2.4- First observed
delete_memory - First observed
get_memory - First observed
list_memories - First observed
list_workspaces - First observed
move_memory - First observed
recall_memory - First observed
retrieve_memory - First observed
search_by_tag - First observed
store_memory - First observed
update_memory
TDQS
Scored across 11 tools
Retrieval tools (retrieve_memory, recall_memory, get_memory, list_memories, search_by_tag) overlap in purpose, but descriptions clearly distinguish semantic/text search, time-based search, direct name lookup, browsing, and exact tag search. CRUD, workspace, and consolidation tools are clearly separate.
Almost all tools follow a consistent snake_case verb_noun pattern (store_memory, update_memory, retrieve_memory, etc.). The one outlier is dream_report, which is noun-based rather than verb-based, but the set remains predictable overall.
11 tools is well-scoped for a memory management server. Each tool appears to cover a distinct operation, and the count sits comfortably within the typical 3-15 range without obvious bloat.
Core memory lifecycle is covered: store, get, update, delete, move, search, list, and expiry handling. Notable gaps remain: there is no create/delete workspace tool despite list_workspaces, and no tool to add or remove tags despite search_by_tag, which could leave agents unable to set up tag-based searches.
Maintenance
Related MCP Connectors
Cloud-hosted MCP server for durable AI memory
An MCP memory server. One memory your agents share โ across models, devices and apps.
One memory, every AI. A shared, user-owned markdown memory your AI clients read and write over MCP.
Related MCP Servers
AlicenseAqualityFmaintenanceAn MCP server that integrates with mem0.ai to help users store, retrieve, and search coding preferences for more consistent programming practices.9662Apache 2.0- AlicenseBqualityDmaintenanceProvides dynamic short-term and long-term memory management with keyword-based relevance scoring, time-decay models, and trigger-based recall. Optimized for Chinese language support with jieba segmentation.216 npm1BSD 3-Clause

Memory Nexusofficial
AlicenseNot gradedqualityDmaintenancePersistent memory and handoff intelligence layer for MCP agents. Most memory servers retrieve text โ Memory Nexus compounds operational context, learning from usage and progressively synthesizing observations into higher-order intelligence across sessions and tools.MIT- FlicenseNot gradedqualityDmaintenanceProvides persistent AI agent memory using a local vector database for long-term semantic storage and short-term session scratchpads. It enables low-latency memory operations including search, storage, and bulk management without external cloud dependencies.-