Skip to main content
Glama
Polign

Recall by Polign

Official

Polign Recall

Recall is a memory for agents. The memory that avoids hallucinations, proposes facts and does not do guesswork. The recall functionality builds the current belief of the system based on how a user corrects their facts, backtracks or changes their understandings. Recall replaces the old fact and informs the agent what it replaced. It keeps the old value in a history for auditing and replaying.

Recall, mem0 and Zep answering questions about a user whose facts changed over nine months

The demo is a real run with one user over nine months. User chaned three homes, three employers, and three work emails. The demo queries six questions about her with current understanding. It is using Opus 5.5 to extract facts, answer, and judge for all three systems. The answers are at Recall 18/18, mem0 18/18, Zep 12/18. Tokens to save one message: Recall 3.0k, mem0 12.7k, Zep 14.7k.

Install

pip install polign-recall          # Python client, the recall binary, and the database it runs
brew install polign/tap/recall     # the same for Homebrew
recall mcp -write                  # MCP over stdio: remember(text), recall(question), forget(text)

Without a named database, recall keeps memory in a local database in ~/.local/share/recall, started on first use and shared by every agent on the machine. The Quickstart runs without a model or an API key. see Backends to keep the memory in the currently integrated locations.

Today that local database is polign_db, so recall needs the polign-server binary next to it. pip and Homebrew install both. go get and go install github.com/Polign/recall/cmd/recall give you the library and the binary but not the database: name one with -backend and -url, or install polign_db (pip install polign-db or brew install polign/tap/polign). In 0.23.0 a recall mcp with nothing configured and no polign-server exits before the MCP handshake; the next release serves the tools and reports the missing database on the first memory call instead. A local database that needs no second binary is being built.

Related MCP server: engram-mcp

What a correction looks like

Every change is kept. Three commands read that record:

$ recall history "which editor do I use"
user preferred editor
  believed now: user preferred editor: zed
  2026-09-01 10:00  stated, user_stated
      + user preferred editor: vim
  2026-09-20 10:00  replaced, user_stated
      - user preferred editor: vim
      + user preferred editor: emacs
  2026-10-05 10:00  replaced, user_stated
      - user preferred editor: emacs
      + user preferred editor: zed

$ recall ask -as-of 2026-09-25 "which editor do I use"
Believed as of 2026-09-25 00:00:
user preferred editor: emacs  (since 2026-09-20)
  replaced: vim  (since 2026-09-01)

$ recall diff -from 2026-09-15 -to 2026-10-31
Changed between 2026-09-15 00:00 and 2026-10-31 00:00:
- user home city: Lisbon
+ user home city: Porto
- user preferred editor: vim
+ user preferred editor: zed

Why Recall

  • Corrections are records. A new value replaces the old one by a rule you can read, and the answer arrives with what it replaced.

  • Ask about any moment. as_of, history, and diff answer what the agent believed then, and when that changed.

  • Every answer has a source. recall explain shows the message a fact came from, the rule that decided it, and its history.

  • Shared and resumable. Agents in different processes read and correct the same memory, and a crashed agent resumes from its records.

  • Your storage. polign_db, PostgreSQL with pgvector, MongoDB, or Qdrant. Apache 2.0.

Benchmark

LongMemEval user-facts subset (267 questions about a user's own facts, preferences, updates, and dates), Recall 0.19.0, Sonnet 5.5 as reader and judge, upstream prompts:

What the reader is given

Score

Nothing

6.0

The full chat history

88.0

BM25 over sessions, top 10

89.9

Recall, built-in word search

88.8

Recall with a model embedder (OpenAI text-embedding-3-small, 512 dims)

92.9

Only the sessions that hold the answer

96.6

With its built-in word search, Recall is about even with BM25 overall and behind it on preference questions (70.0 against 83.3). A model embedder puts it ahead. Since 0.20.0 one follows the extraction model: OpenAI's text-embedding-3-small with an OpenAI extractor, Ollama's nomic-embed-text with an Ollama one, and the all-MiniLM model built into the binary with an Anthropic one. With word search, Recall handed the reader about 28k tokens per question, against about 44k for BM25 and 168k for the full history.

Choose an integration

Integration

Get started

Python

Follow the quickstart below, then see the client guide.

Go

Run go get github.com/Polign/recall and follow the Go client guide.

MCP

Connect an agent to tools for remembering, recalling, and forgetting facts.

LangGraph

pip install recall-langgraph to resume LangGraph agents from their own records.

LiveKit

pip install recall-livekit for caller memory in voice agents.

Vapi

pip install recall-vapi for caller memory in Vapi assistants.

Pydantic AI

pip install recall-pydantic-ai for memory tools in Pydantic AI agents.

The Claude Code plugin is a ready-made MCP integration for memory across coding sessions, and the OpenClaw plugin (@polign/openclaw-recall on npm) gives OpenClaw agents the same memory.

Quickstart

You'll need Python 3.10+. Install the client:

pip install polign-recall

pip also brings the polign_db package, which holds the polign and polign-server binaries, so there is nothing else to download or start. This example needs no model or embedding API key.

One process saves an editor preference and then changes it:

python - <<'PY'
from polign_recall import Client

with Client(local_dir="./recall-data") as memory:
    memory.remember("user", "prefers_editor", "vim")
    memory.remember("user", "prefers_editor", "neovim")
PY

Run a second process in the same terminal. It reads the current preference, the full history, and what was believed before the correction:

python - <<'PY'
from polign_recall import Client

with Client(local_dir="./recall-data") as memory:
    print(memory.recall("user", "prefers_editor")[0].value)  # neovim

    events = memory.history("user", "prefers_editor")
    print([event.value for event in events])  # ['vim', 'neovim'] in a fresh directory

    # Ask what was believed at the moment of the first statement.
    before = memory.recall("user", "prefers_editor", as_of=events[0].observed_at)
    print(before[0].value)  # vim
PY

The correction did not erase vim. It is still there to read, which is how you answer "what did the agent believe yesterday, and when did that change?"

The first client to open ./recall-data starts a local polign-server for it in the background, and later clients share it. The memories stay in that directory after your program exits. A bare Client() does the same in ~/.local/share/recall, the memory every agent on the machine shares, the Claude plugin included. Managed local databases work on Linux and macOS.

To share memory between machines, run polign-server yourself (requires Polign v0.8.0 or later) or any other backend, leave local_dir out, and name the database with Client(backend=, backend_url=, backend_key=) or with RECALL_BACKEND, RECALL_BACKEND_URL and RECALL_BACKEND_KEY in the environment. RECALL_COLLECTION names the collection. Client.database says which database the binary resolved.

For examples covering forgetting as well, see the Python session example or Go session example.

How memory works

A memory has a subject, a predicate, and a typed value:

Subject

Predicate

Value

user

prefers_editor

neovim

recall-demo

prefers_test_framework

pytest

recall-demo

uses_technology

Go

Predicates live in a registry that declares each one's value type, whether it holds one value or several, and which predicates it contradicts (dislikes excludes likes, gave_away excludes owns). Recall includes starter registries for coding, personal assistant, support, sales, and voice agents. Add your own predicates (the registry), and the extractor files statements under them; you can change the registry later without changing what the agent remembered before. A value can be text, a number, a boolean, an enum, a date, or a reference to another subject.

For a single-valued predicate such as prefers_editor, a new assertion replaces the current value. A multi-valued predicate such as uses_technology can hold both Python and Go. Corrections preserve earlier statements, so you can read current values, inspect their history, or query what was known at an earlier time.

Forgetting records a withdrawal and removes the affected fact from current answers. It does not permanently delete the record.

An agent can also propose facts from text. Recall validates those proposals against the registry before writing them. A statement that fits no predicate is kept as a note instead of being dropped. Once you add a predicate for that kind of fact, Promote files each note under it and keeps the note in history.

Without a registry

You don't have to define predicates at all. With an open vocabulary, a write may name any predicate and its first use defines it, starting from the coding and personal starters. recall explain "<question>" shows, for each answer, the text it came from, the predicate it was filed under, the rules that decide it, and its history.

With a model configured, the MCP server goes one step further and takes plain text, with no predicates in any tool or answer:

recall setup -extract-model anthropic:claude-haiku-4-5-20251001
remember("I switched from helix to zed last week")
recall("which editor do I use?")  ->  "user prefers editor: zed" (before: helix)
forget("my editor")

The model decides how each statement is filed: which predicate, and whether a new value replaces the old one or adds to it. Once filed, replacement follows the predicate's rule as before, every filing is recorded, and a wrong one is corrected with one event (Redefine, Merge, Split) that every answer follows. The model is called on every remember and forget, and the text is sent to its provider. See text-only tools.

The benchmark above uses these text tools with an open vocabulary seeded from the personal starter.

Typed tools

recall mcp -write -typed serves tools over a fixed vocabulary instead, such as remember(subject, predicate, value). A session with the personal starter registry:

remember(user, likes, mangoes)
remember(user, dislikes, mangoes)
  -> superseded: [likes: mangoes]          # the registry says dislikes excludes likes

recall(user, dislikes)
  -> mangoes   replaced: [likes: mangoes]  # the correction arrives with the answer

remember(user, goal, "run a marathon")
remember(user, did,  "run a marathon")
recall(user, goal)
  -> run a marathon   elsewhere: [did: run a marathon]   # no rule joins goal and did,
                                                         # so the read shows both

remember(user, did, "run a marathon",
         replaces=[goal: "run a marathon", goal: "learn piano"])
  -> replaced:   [goal: run a marathon]
  -> unreplaced: [goal: learn piano]       # never believed, so reported, not dropped

No model reconciles memory on its own. Recall applies the rules the registry declares, shows the candidates that may conflict, and lets your agent confirm the rest, so every correction can be read back to the rule or the statement that made it.

Reading the record

Each step of a history is the log folded just before and just after that statement, so it agrees with a read at that instant. Agents get the same record through the history and diff MCP tools (timeline and diff with -typed), recall serve answers them over HTTP at /v1/history, /v1/timeline and /v1/diff, and the Python client has history_text, timeline and diff.

Resuming an agent

Resume gives an agent back the context it should start from, built from what it wrote down while it worked. The new process resumes from records, not from a process or container snapshot:

  • Working state: its goal, plan, progress, focus, and open questions.

  • Pointers to where its work lives, such as a git branch or an object key.

  • Turns, verbatim, and large tool outputs stored by reference.

The next process gets those records, plus memories that match its focus, sized to a token budget and rendered as one briefing for the model. A lease keeps one process per agent, so a second copy cannot write over the first. Leases need Polign v0.8.0 or later.

agent, err := client.Resume(ctx, recall.ResumeRequest{AgentID: "coder-1", TokenBudget: 8000})
if err != nil {
    return err
}
defer agent.Release(context.Background())

briefing := agent.Resumed().Briefing // hand this to the model

Resume and actions are a beta surface: the calls around the records may still change in a minor release, with the change and what to do about it in the changelog. The records themselves are stable. See STABILITY.md.

The resume example crashes an agent partway through a task and continues it in a new process. See Resuming an agent for the full API, and the Python client guide for resume in Python.

Serving many agents

recall mcp is one agent, one process, one store. recall serve is the same memory for many agents at once, over HTTP, each inside the namespace its key names. The server holds the store's credentials; agents hold Recall keys.

recall serve -backend polign -url http://polign:23000 -bootstrap-key-file admin.key   # admin.key holds one rcl_... line
recall key create -backend polign -url http://polign:23000 -namespace acme:agent-7 -expires 168h

With no database named, recall serve runs on the local database like every other command, and recall key create -namespace team:agent-1 against the same default mints a key for it: a shared memory server for several agents on one machine, with nothing configured. Its first log line says where memory is, so a container that meant to name a database and did not is told at once.

Each namespace gets its own collection, so nothing a caller sends can reach another namespace's records. Keys are stored hashed, expire if asked, renew at POST /v1/keys/renew, and are revoked by a tombstone that nothing can overwrite. POST /mcp is MCP over streamable HTTP; POST /v1/<tool> (remember, recall, forget, history, explain, diff, timeline, predicates) takes that tool's arguments as the body. Any MCP client that speaks stdio reaches the server through recall connect, with RECALL_URL and RECALL_API_KEY set.

On Kubernetes a pod needs no key at all. With recall serve -kubernetes, it posts its projected service account token (audience recall) and gets a short-lived key for <tenant>:<pod name>, fixed to that agent, which recall connect and the Python client obtain and renew by themselves from RECALL_TOKEN_FILE. The Helm chart is charts/recall in Polign/polign; the agent-sandbox demo runs it on kind. The contract every client is written against is docs/memory-api-v1.md.

Three things say where memory lives, the same three for every backend and every command:

Flag

Variable

What it is

-backend

RECALL_BACKEND

local (the default), polign, pgvector, mongodb or qdrant

-url

RECALL_BACKEND_URL

Where the database is, in the backend's own form: a directory, http://host:23000, postgres://user@host/db, mongodb://host/db, http://host:6333

-key

RECALL_BACKEND_KEY

The credential, when the backend takes one and the URL does not carry it: the API key of polign and qdrant, the password of pgvector and mongodb

Each resolves in the same order: the flag, the variable, the setup recall setup saved, the default. The flags go before the command or after it. A backend's other options are query keys on the URL, listed in the table below; anything else in the query goes to the driver as it is (postgres://host/db?schema=memory&sslmode=require).

Nothing else about the database has a variable. The names each backend had before 0.23.0 (POLIGN_URL, POLIGN_API_KEY, DATABASE_URL, PGPASSWORD, MONGODB_URI, MONGODB_PASSWORD, QDRANT_URL, QDRANT_API_KEY) keep working as aliases, with one line on stderr naming the new one, and so does a polign_db already answering at http://localhost:23000 when nothing names a backend, which is where 0.22 looked. See STABILITY.md for when they go away.

Recall provides memory rules, validation, and history; the backend provides persistence and access to the data. Agents share memory by using the same backend, collection, and namespace, with compatible Recall versions and memory definitions. Search also requires compatible embedding methods.

Concurrent reads and writes follow the backend's consistency guarantees. Recall does not add transaction isolation or replication.

Backends

local (default)

polign_db

PostgreSQL + pgvector

MongoDB

Qdrant

Package

backend/local/

polign/

backend/pgvector/

backend/mongodb/

backend/qdrant/

RECALL_BACKEND

local

polign

pgvector

mongodb

qdrant

RECALL_BACKEND_URL

a directory (default ~/.local/share/recall)

http://host:23000

postgres://user:pw@host:5432/db

mongodb://user:pw@host:27017/db

http://host:6333

RECALL_BACKEND_KEY

not used; a key is generated in the directory

the polign_db API key

the password, when the URL has none

the password, when the URL has none

the Qdrant API key

Options on the URL

?server=/path/to/polign-server

none

?schema=recall&text_search=english

?database=recall

?distance=Cosine

Server version

the polign-server beside recall, which pip and Homebrew install; started on a loopback port and left running

0.8.0 or later

PostgreSQL 13 or later with pgvector 0.6.0 or later; 0.8.0 or later recommended

6.0 or later, Atlas or self-hosted

1.10 or later

Remember, recall, forget, history, as-of

yes

yes

yes

yes

yes

Evidence links, audit export

yes

yes

yes

yes

yes

Keyword search

as polign_db

yes, BM25

yes, PostgreSQL full-text search

yes, MongoDB text search

no, vector search only

Cached reads

yes

yes

yes

yes

no, every read refolds the history

Agent leases (recall mcp -agent)

yes

yes

yes

yes

no; Go Resume with Unleased: true only

Agent writes fenced on the server

yes

yes

yes, in the write's transaction

yes on a replica set or Atlas, in the write's transaction; checked just before the write on a standalone server

no

recall setup and the Claude plugin

yes

yes

yes

yes

yes

To run Recall on a PostgreSQL database:

export RECALL_BACKEND=pgvector RECALL_BACKEND_URL=postgres://user:password@localhost:5432/mydb
recall mcp -write

The first write creates a recall schema with one table per collection and two bookkeeping tables. The role needs CREATE on the database, and the vector extension must be installed or creatable by that role.

Pitfalls on PostgreSQL:

  • A collection takes its vector size from the first write. Changing embedders needs a new collection.

  • Every write to a collection takes a row lock on that collection's revision, so writes to one collection are serialized. That is fine at conversation pace but slows a bulk import.

  • Keyword search uses the english text search configuration unless ?text_search= on the URL (Go: Config.TextSearchConfig) says otherwise. It is fixed when a collection is created.

  • On pgvector older than 0.8.0, a filtered vector search can return fewer hits than asked for, because the index stops scanning at ef_search candidates before the filter applies.

To run Recall on MongoDB:

export RECALL_BACKEND=mongodb RECALL_BACKEND_URL=mongodb://user:password@localhost:27017/recall
recall mcp -write

The database is the connection string's path, recall when it has none. The first write to a collection creates a MongoDB collection named rc_ and the collection's name, and two bookkeeping collections, recall_collections and recall_leases. The user needs readWrite on the database.

Pitfalls on MongoDB:

  • Vector search is exact: the similarity is computed in the server over the events a filter keeps. No Atlas Search index is needed and the answer is the true nearest events, but each search reads the whole filtered collection. Agent memory collections hold thousands of events, which is fast; a collection of millions is not what this backend is for.

  • Run a replica set (Atlas always is) for agents. On a standalone server there are no transactions, so a fenced agent write is checked just before it lands rather than with it, and listings are not read from one snapshot. A single-node replica set is enough.

  • A collection takes its vector size from the first write. Changing embedders needs a new collection.

  • Keyword search uses MongoDB's english text index, fixed when a collection is created.

Pitfalls on Qdrant:

  • Use a collection only Recall writes to. A point without the _recall_id payload field makes reads fail.

  • A collection takes its vector size from the first write. Changing embedders needs a new collection.

  • Unleased: true is safe only when something else keeps one process per agent. Without a lease, a crashed process that comes back can overwrite its replacement.

  • With the built-in lexical embedder, exact-word queries rank worse than on polign_db. A model embedder (-embed-model) helps paraphrases, not keywords.

To add a backend, implement Put, List and Search (contract), register it with recall.RegisterBackend in init, pass backendtest, and import it in cmd/recall/backends.go.

The core package, github.com/Polign/recall, imports nothing outside the standard library. The pgvector backend uses pgx, the MongoDB backend the official MongoDB driver, and the model package the Anthropic SDK and hugot for the embedding model that runs inside the binary. A program pulls each in only by importing that package.

Two embedders ship with Recall: lexical word search, which needs nothing, and local:all-minilm-l6-v2, a model that runs in the binary with no key and no service. -embed-model names an OpenAI, Ollama or Voyage model instead. See the embedding guide.

Repository layout

Path

Contents

recall.go, doc.go

Public Go API at github.com/Polign/recall

internal/engine/

Memory implementation and unit tests

backend/local/

The default backend: a polign_db recall runs itself

polign/

polign_db backend

backend/pgvector/

PostgreSQL + pgvector backend

backend/mongodb/

MongoDB backend

backend/qdrant/

Qdrant backend

backendtest/

Conformance suite for backends

python/

Python package and tests

model/

Extraction models and embedders, including the one built into the binary

registries/

Starter predicate registries

cmd/

The recall and recall-audit commands

examples/

Runnable Go and Python examples, including a crash-and-resume demo

deploy/

Container image and the agent-sandbox demo

eval/

Evaluation harnesses: LongMemEval, corrections, predicate matching

docs/

Guides and API reference

testdata/

Shared audit fixtures

See the development guide for the implementation map and test commands.

Documentation

What is stable and what is beta · Developer reference · Resuming an agent · Connecting through MCP · Caching memory reads · Exporting and replaying history

Support the project

If Recall kept your agent from acting on a stale fact, a star on this repository helps other people find it. Bugs, questions, and ideas go in issues.

License

Apache 2.0.

Available Tools

5 tools
diffDiffA
Read-only

What was believed differently at one instant than at another: each thing that began or stopped being believed in between. Use it to say what changed over a period, such as since the last session or during an incident.

NameRequiredDescriptionDefault
toNothe later RFC3339 instant; omit for now
fromYesthe earlier RFC3339 instant, e.g. 2026-09-01T00:00:00Z

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish readOnlyHint=true and openWorldHint=false, so safety is covered. The description earns its place by defining what the result actually contains (both things that began and things that stopped being believed), which matters because there is no output schema. It says nothing about ordering, volume, or handling of the open-ended 'to' default beyond what the schema notes.

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 sentences, no filler: the definition comes first, the usage scenario second. Every clause carries meaning and nothing repeats the name or title.

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 two-parameter read-only tool with full schema coverage and no output schema, the description supplies the one thing structured data cannot: what a 'diff' means in this belief model and what the result enumerates. Only the ordering/shape of the returned set is left implicit.

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 coverage is 100% and both parameters already document the RFC3339 format and the 'omit for now' behavior for `to`. The description reinforces the notion of two instants but adds no syntax or edge-case detail beyond the schema, so the baseline of 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?

The description states a specific operation with a precise semantic definition: the set of things that began or stopped being believed between two instants. This distinguishes it in substance from remember/recall/forget, though it never names the closest sibling (history) so the agent must infer 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 Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete when-to-use framing — 'to say what changed over a period, such as since the last session or during an incident' — which maps real scenarios onto the tool. It stops short of stating exclusions, e.g. when to prefer history over diff.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

forgetForgetA

Stop believing what a description names, such as "my editor" or "that I live in Lisbon". Returns what was withdrawn. Nothing is deleted: it stays in the history, and remembering it again brings it back.

NameRequiredDescriptionDefault
textYeswhat to forget, described in words

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does meaningful work: it discloses that nothing is deleted, that the belief remains in history, that the operation is reversible via `remember`, and that it returns what was withdrawn. It omits what happens on a miss (forgetting something not held) and any auth/permission expectations.

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?

Three short sentences, each doing distinct work: what it does, what it returns, and the reversibility guarantee. No redundancy and the core action is front-loaded.

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?

No output schema exists, and the description compensates by stating the return value and the non-destructive persistence semantics. For a one-parameter tool this is nearly complete; only edge-case behavior for a non-existent belief is missing.

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 single `text` parameter is already documented; the description adds real meaning by showing the expected form is a natural-language belief description rather than an ID or key, with two worked examples. That is more than the schema conveys.

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?

The verb phrase "stop believing what a description names" plus concrete examples ("my editor", "that I live in Lisbon") makes the operation identifiable, and the closing clause implicitly contrasts it with the sibling `remember` which restores the belief. It is clear but phrased metaphorically rather than as a plain verb+resource statement, which costs a point.

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: an agent can infer you call this when a stored belief should no longer be held, and the description notes that remembering it again reverses the effect. There is no explicit when-to-use/when-not-to-use guidance and no direct routing against siblings like `recall` or `history`.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

historyHistoryA
Read-only

How something remembered changed, in words: every statement about it, oldest first, each with what it began and ended believing, and what is believed now. Use it when the user asks what changed, when, or why something is believed, and to show a correction whole. Something since forgotten still has its history.

NameRequiredDescriptionDefault
questionYeswhat to trace, in words, such as "my editor"

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint and openWorldHint annotations, the description discloses return behavior in useful detail: every statement is returned oldest first, each with its beginning and ending beliefs, plus the current belief. It also adds the non-obvious edge case that forgotten items still retain history.

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 description is short and front-loads the core behavior before usage guidance and the forgotten-item edge case. The first sentence is dense and slightly abstract, but no sentence is clearly wasted.

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 simple one-parameter read-only tool with no output schema, the description is complete: it explains the return ordering and content, gives usage conditions, and covers the forgotten-item case. An agent has enough information to call it correctly.

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?

There is only one required parameter and the schema already has full description coverage, including an example. The main description does not add syntax or format details beyond the schema, so the baseline of 3 is appropriate.

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?

The description states a specific resource and scope: a chronological history of statements about something remembered, including past and current beliefs. It is clear enough to distinguish from a simple recall, though it does not explicitly name or contrast with the sibling tools.

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?

It gives clear usage cues: when the user asks what changed, when, or why something is believed, and when showing a correction whole. It also notes that forgotten items still have history. It does not explicitly say when to prefer a sibling like diff instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

recallRecallA
Read-only

Ask what is remembered, in words, before assuming anything about the user. Answers are what is believed now, as sentences. Each lists under before what it replaced and when, so a correction comes with the answer, and under elsewhere anything else believed about the same thing in other words, such as a later dislike beside a like; the newer statement usually holds. days_ago says how long ago it was stated. A time named in the question, such as "last week", is searched first. Each also gives under said the sentence it was drawn from, as the user said it. Pass as_of to ask what was believed at an earlier instant. Leave out question to get everything believed about the user, a profile to start a conversation with. Pass since to get only what changed after then, newest first: at the start of a session, since the last one, it says what is new.

NameRequiredDescriptionDefault
as_ofNoRFC3339 instant, e.g. 2026-09-01T00:00:00Z. Answers as of then rather than now.
sinceNoRFC3339 instant. Only what was stated after then, each with what it replaced.
questionNowhat you want to know; omit for the user's profile, or with since for everything that changed

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnlyHint=true, openWorldHint=false), yet the description goes far beyond them: it discloses the returned fields (before, elsewhere, said, days_ago), the resolution heuristic that the newer statement usually holds, that a time named in the question is searched first, and that 'since' results come newest first. With no output schema, this disclosure is doing essential work.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The opening sentence front-loads purpose and the key usage trigger, which is good, but the middle devolves into long run-on clauses ('Each lists under before what it replaced and when, so a correction comes with the answer, and under elsewhere anything else believed...') that are hard to parse. Some points are restated, e.g. 'since' is explained twice with slightly different framing.

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 zero-required-parameter read tool with no output schema, the description is substantially complete: it explains both intent variants and the shape of returned data. Gaps are the lack of sibling differentiation (history/diff) and no indication of result size, limits, or ordering for the default profile call.

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 all three parameters are already documented, but the description adds intent-level meaning: 'as_of' asks what was believed at an earlier instant, 'since' narrows to only what changed and returns newest first, and omitting 'question' yields the full profile. That is genuine value beyond the schema, though the RFC3339 format itself is left to the schema.

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?

The description makes clear this is a retrieval operation over what the system believes about the user, returning those beliefs as sentences with provenance (before/elsewhere/said). The verb phrasing 'Ask what is remembered, in words' is idiosyncratic but the resource and output shape are unambiguous. It does not distinguish itself from siblings like history or diff, which likely overlap with the 'since' changed-since-last-time behavior.

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?

Usage contexts are explicit and actionable: call before assuming anything about the user, omit 'question' to get a profile to start a conversation, pass 'since' at the start of a session to see what is new, pass 'as_of' for a historical view. What's missing is any exclusion or named alternative — nothing says when to prefer history or diff over this tool, which matters given the overlap.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

rememberRememberA

Keep something worth remembering about the user or their work: a preference, a fact, a decision, or a correction. Pass the passage as text, in the user's words where you can, or pass the conversation as messages with their roles, so that only what the user said or agreed to is kept and nothing the assistant suggested. The server works out what it says. A newer statement replaces an older one about the same thing, and the older one stays in the history. Restating something already known changes nothing.

NameRequiredDescriptionDefault
textNowhat to remember; or pass messages
messagesNoa conversation to remember instead of text, in order: only what the user said or agreed to is kept
observed_atNowhen it was said, as an RFC3339 instant like 2023-05-20T02:21:00Z; omit for now. Use it only for something said earlier, such as an imported conversation.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: it discloses that only user-attributed content is kept, that newer statements supersede older ones about the same subject, that superseded entries remain in history, and that redundant restatement is a no-op. These deduplication and idempotency semantics are exactly the behavioral traits an agent cannot infer from the schema.

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?

Purpose and content types are front-loaded, followed by parameter guidance and then behavioral rules, so structure matches reading order. It is a dense paragraph with no wasted clause, though splitting the deduplication rules into their own sentence group would aid scanning.

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 mutation-style tool with no annotations and no output schema, the description covers write semantics, attribution rules, conflict resolution, and idempotency. The remaining gap is what a successful call returns (confirmation, identifier, or nothing), which the agent may want to know for follow-up calls.

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 baseline is 3, but the description adds real meaning: it explains the text-vs-messages tradeoff and the filtering behavior of messages ('only what the user said or agreed to is kept'), plus the intent behind observed_at. It stops short of clarifying what happens when both text and messages are passed, which the schema also leaves open.

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?

Opens with a specific verb and object: 'Keep something worth remembering about the user or their work,' then enumerates the acceptable content types (preference, fact, decision, correction). The write-side framing clearly separates it from recall/forget/history/diff siblings without relying on the name alone.

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 concrete usage guidance: prefer the user's own words for text, use messages when you want role-filtering, and reserve observed_at for earlier/imported statements. It never explicitly excludes a sibling tool by name, but the write-vs-read boundary is unambiguous from context.

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. 5 tool updatesv0.22.1
    • First observeddiff
    • First observedforget
    • First observedhistory
    • First observedrecall
    • First observedremember

TDQS

A4.1/5.0

Scored across 5 tools

Disambiguation4/5

The five tools cover clearly different operations: storing, querying, withdrawing, tracing one item's history, and comparing beliefs across time. The only mild overlap is between recall's `since` mode and diff, which both answer 'what changed', though their descriptions differentiate instants versus periods.

Naming Consistency4/5

All names are single, lowercase words with a consistent terse style. However, remember/recall/forget are verbs while history and diff are nouns, a minor deviation from a pure verb convention.

Tool Count5/5

Five tools is well scoped for a focused memory service, with each tool earning its place across the read/write/history lifecycle. No tool feels redundant or missing from the core set.

Completeness5/5

The surface covers the full memory lifecycle: write (remember), read (recall with profile, point-in-time, and delta views), soft delete (forget), per-item history, and cross-instant diff. No dead ends are apparent for the stated purpose.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Open-source AI memory layer for LLM agents. Importance scoring, temporal decay, hierarchical memory (facts, summaries, themes), YMYL prioritization, and active retrieval with contradiction detection. Supports OpenAI, Anthropic, Ollama. Local-first with SQLite + FAISS.
    49
    Apache 2.0
  • A
    license
    Not graded
    quality
    D
    maintenance
    Integrates an Engram brain with Claude Code via MCP, providing tools for searching, retrieving, and adding memories.
    5 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Local memory for AI agents in one SQLite file on your own machine. Facts carry a validity window and a confidence score, so an outdated one is superseded and downweighted rather than deleted, and retrieval fuses BM25, vector similarity and a knowledge graph.
    2
    Business Source 1.1
  • A
    license
    Not graded
    quality
    C
    maintenance
    Self-hosted long-term memory for AI agents on your own Postgres. Facts are dated, versioned and superseded rather than silently overwritten, every recall ships with an inspectable trace, and agents can correct wrong memories from inside the conversation.
    2
    Apache 2.0