sessionmem
sessionmem is a local-first MCP memory server for persisting project context across AI sessions, with tools to store, retrieve, inspect, summarize, and manage memories.
Search compact memory indexes and browse timelines by memory ID or UTC date range, including superseded history.
Retrieve memories ranked by relevance, recency, and importance, with fallback fetch/startup-injection tools for hosts lacking MCP resources or prompts.
Store single or batched memories such as decisions, facts, warnings, preferences, and summaries, with tags, importance, expiry, and redaction controls.
List all memories or fetch a specific memory by exact ID.
Permanently delete memories and reset access-pattern counters.
Ingest raw session events, summarize sessions into durable memories, and run the session-end summarization and retention-prune pipeline.
View aggregate project statistics for stored memories and ingested session events.
Keep data locally in SQLite with secret redaction and retention enabled by default; optional team sharing and cloud summarization are available per the README.
sessionmem
Project memory between sessions, stored on your machine.
New session. Claude starts fresh.
WITHOUT sessionmem:
You explain the stack. The JWT bug from last week.
The Stripe migration that's halfway done. The billing code to stay away from.
Same questions. Different day.
WITH sessionmem:
[warning] JWT blacklist must be checked before issuing new tokens. Fixed PR #47.
[decision] Stripe migration ~50% done. Do NOT use /lib/billing-v1.
[fact] Stack: TypeScript, Next.js, Postgres.
Claude: "Looks like you're mid-Stripe migration. Where do you want to pick up?"sessionmem is an MCP server that stores decisions, warnings, and project context across sessions. Claude Code hooks capture supported tool events and load relevant memories automatically. Other hosts use its MCP tools and installed instructions; session automation depends on the host. It works with Claude Code, Cursor, Cline, Codex, Windsurf, and other MCP hosts.
Default retrieval uses SQLite FTS5 BM25 and entity overlap. An optional local MiniLM model adds semantic candidates. Weights are installed separately; queries make no network calls and fall back to BM25 when local inference is unavailable. See measured comparisons for quality gains, missed questions, and latency costs.
By default, everything stays on your machine. You don't need an account or a cloud service. Data only leaves your computer if you enable sharing or cloud summarization.
Quickstart
You need a terminal (Command Prompt, Terminal, or PowerShell) and Node.js, version 20.19+ on the Node 20 line, or 22.13+. Node 22 LTS is recommended. No programming experience is required.
1. Install sessionmem
npm install -g sessionmem2. Register it with your AI tool
Run this in your project folder after configuring your AI tool (Claude Code, Cursor, etc.):
sessionmem install
# Optional: select one host explicitly, including in automation:
sessionmem install --adapter claude-code
# Other names: cursor, cline, codex, windsurf, antigravity, qcoder, genericinstall detects installed hosts from local executables, including from a plain
terminal, and configures every host found. Automatic discovery currently supports
Claude Code on PATH or in its standard native install locations. Use
--adapter <name> for the other adapters or to override discovery. The existing
SESSIONMEM_ADAPTER environment override also works; the flag takes precedence.
If no supported host is found, the command says so and exits nonzero before
creating files. Discovery and configuration work fully offline.
This initializes the database and configures the selected adapters:
Registers
sessionmemwith your AI tool's MCP host so the host can start it automatically.Creates
~/.sessionmem/config.jsonwith secret redaction enabled and a 90-day retention window, if the file doesn't already exist.Adds instructions to the selected host's guidance file, such as
~/.claude/CLAUDE.mdfor Claude Code or~/.codex/AGENTS.mdfor Codex. You can re-run the command without duplicating those instructions.Installs Claude Code's SessionStart, SessionEnd, and PostToolUse hooks and prints what was configured per host. If a host fails, the remaining hosts are still attempted and the command exits nonzero.
Enables and starts one per-user login service for
sessionmem watch. Re-running install updates that registration in place and restarts capture. Capture continues after closing the terminal and starts again at login.
Login capture uses a LaunchAgent in ~/Library/LaunchAgents on macOS, a
systemd --user service on Linux, and a Scheduled Task with a user logon trigger
on Windows. Linux requires systemd and an available user service manager; macOS
requires a GUI login session. If registration or startup fails, install exits
nonzero, preserves completed setup, and prints a repair hint. After fixing the
OS service error, run sessionmem autostart enable.
The watcher captures existing and updated Claude Code, Codex CLI, and Cursor history offline, without API keys. It starts immediately after install; no manual scan or watch process is required. Hosts outside these three can use MCP memory tools, but do not have a transcript reader.
3. Restart your AI tool
Restart your editor or agent so it loads the MCP registration. Your host starts
sessionmem run automatically; running it directly starts a stdio server that
waits for MCP messages, so it can appear to hang in a terminal. For an unknown
host (generic), install writes a project-local .mcp.json; if your host uses
another format or location, copy its server entry into that host’s MCP config.
After restarting:
In Claude Code, the installed PostToolUse, SessionEnd, and SessionStart hooks capture supported tool events, summarize them, and load prior memories automatically.
Codex and Cursor use the auto-started watcher for transcript capture. Install does not wire lifecycle capture hooks for these hosts. Their MCP tools and installed instructions provide recall and explicit memory operations.
Other MCP hosts use sessionmem's tools and installed instructions; automatic transcript capture requires a supported transcript reader.
Check the installation offline:
sessionmem doctor
# For an explicitly selected host:
sessionmem doctor --adapter claude-codeRelated MCP server: codemem
Table of Contents
What problem does this solve?
Most AI coding assistants rely on the current conversation for context. Start a new session and you may need to explain the project's setup, libraries, fixed bugs, and design decisions again.
sessionmem keeps short notes between sessions:
While you work, it captures session events.
At session end, it summarizes decisions, warnings, and useful facts into stored memories.
At the next session start, it loads the most relevant memories within a small token budget.
Claude Code runs these steps through the installed hooks. Other hosts need their agent to call the MCP memory and lifecycle tools; the installed guidance explains how to do that.
How is sessionmem different?
Compared with projects such as claude-mem and other cloud or Claude-only memory tools, sessionmem focuses on local storage and support for multiple MCP hosts:
sessionmem | Typical cloud/Claude-only memory tools | |
Where is data stored? | A single SQLite file on your computer ( | Often a hosted service, a cloud vector database, or a separate server process you have to run |
Account / sign-up required? | No | Sometimes |
Which AI tools does it work with? | Claude Code, Cursor, Codex, Cline, Windsurf, Antigravity, QCoder, and any other MCP-compatible host | Usually just one specific tool (commonly Claude Code only) |
Secret redaction | Built in, on by default. API keys, tokens, passwords, and private keys are scrubbed before anything is saved. | Often not handled, or left to the user |
Token budget control | Injected memories are trimmed to a small, fixed token budget (see benchmarks below) | Varies, often unbounded |
Entity boost (optional) | Case-insensitive names and explicit aliases add a bounded score boost alongside relevance, recency and importance. Local only, defaults off. | Varies |
Scopes | Optional local context labels on sessions, memories and entity associations. Capture detects a directory or project label; queries can filter or boost a selected scope. All scopes by default. | Varies |
Old/stale memory cleanup | Built-in retention policy automatically prunes old memories (configurable, on by default) | Often no automatic cleanup ("memory rot") |
Team sharing | Optional, via a shared folder you already control (network drive, synced directory). No server needed. | Usually requires a shared hosted backend |
Offline-capable | Yes. Works with no network connection by default. | Usually requires network access to the memory service |
The SQLite file is easy to inspect, back up, or delete, and you can use it across AI tools from different vendors.
Benchmark results
npm run benchmark evaluates conversational retrieval on the committed LoCoMo
corpus: 10 conversations, 272 sessions, 5,882 turns, and 1,527 scored questions.
It captures dialogue through the public storeMemory API and asks the original
questions through retrieveMemories, fully offline with no API keys.
The evaluation reports hit rate, precision, recall, complete-evidence retrieval, and latency. Production retrieval uses offline BM25 ranking with English stemming; conversational questions test recall beyond exact copies of memory text. See benchmark results and the methodology, dataset license, and metric definitions.
npm run build
npm run benchmark
npm run benchmark -- --output benchmarks/results/locomo.jsonHow it works (in plain English)
┌──────────────────────────────────────────────┐
│ Your AI tool │
│ (Claude Code, Cursor, Codex, Cline, ...) │
└───────────────────────┬──────────────────────┘
│
┌───────────▼───────────┐ ┌──────────────┐
│ sessionmem adapter │ │ sessionmem │
│ (translates for your │ │ CLI │
│ specific AI tool) │ │ (you type │
└───────────┬───────────┘ │ commands) │
│ └──────┬───────┘
▼ │
┌──────────────────────────────────────────────┐
│ sessionmem core engine │
│ watches sessions · writes summaries · │
│ finds relevant memories · trims to fit │
└───────────────────────┬──────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ One SQLite file on your computer │
│ ~/.sessionmem/memories.db │
└──────────────────────────────────────────────┘Adapters connect each AI tool to sessionmem. Supporting another tool doesn't require changing the memory engine.
The core engine stores memories, ranks their relevance, and selects what fits in the next session's context budget. Every adapter uses the same engine.
The database is a local file. You can back it up, move it, inspect it, or delete it.
See docs/architecture.md for the technical overview.
CLI command reference
Command | What it does |
| Detect installed hosts, configure integrations, write default config, and enable login capture; the flag selects one host. |
| Check the store, schema, auto-start, binary paths, capture freshness, transcript discovery, hooks, MCP wiring, and canary recall offline; print PASS/FAIL and repair hints. |
| Start login capture, stop and unregister it, or inspect its registration and binary paths. |
| Stop and unregister login capture, then remove sessionmem from the selected host. |
| Start the MCP server. |
| Open the local read-only web viewer (default port 3777). |
| Start the local single-user REST API (default port 3778). |
| Check the local version and database reachability. |
| Search current memories by text query (limit 1–100, default 10). Include superseded facts with |
| List up to 200 recent memories for the current project; warns when truncated. |
| List extracted entities, typed relations, and their source memory IDs. Defaults to the current project. |
| List supersession chains with old/new values, source memory IDs, reasons, and timestamps. |
| Show memory details (content capped at 2000 characters; use export for full content). |
| Delete a memory by ID. |
| Export all current-project memories to JSON (default |
| Import up to 1000 valid records from UTF-8 JSON into the current project. Existing IDs are preserved, including with |
| Import existing Claude Code, Codex CLI, and Cursor transcripts into local session memories. Reports files found, sessions imported, memories created, skips, and errors. |
| Capture new or updated Claude Code, Codex CLI, and Cursor transcripts. Polls every 5 seconds by default; |
| Show memory statistics for the current project. |
| Show token savings from compression and injection, with percentage. |
| Scan stored memories for secrets; |
| Prune old memories (dry-run by default). |
| Read and write policy config. |
| Manage shared-path team memory mode. |
| Push local memories and pull teammate memories via the shared path. |
| List projects or preview up to 50 recent memories from one project. |
| Preview duplicate memories; |
| Refresh memories with stale embedding versions. |
| Print prior context as Claude Code SessionStart hook JSON. |
| Read a Claude Code PostToolUse JSON payload from stdin and capture supported tool events. |
| Summarize ingested events and apply retention pruning; reads the hook session ID from stdin. |
Use sessionmem --help or sessionmem <command> --help for options, and
sessionmem --version for the installed version. Destructive commands require
--force, --apply, or --purge as shown above. team disable preserves
teammate memories unless --remove-team-memories is passed.
The default database is ~/.sessionmem/memories.db. Set SESSIONMEM_DB_PATH
to use another file; its parent directories are created automatically and the
default directory is not created by database commands. Server logs are written
to logs/mcp.log beside the selected database (disabled for :memory:). Config remains at
~/.sessionmem/config.json. uninstall --purge deletes the selected database.
Quote paths containing spaces (for example "C:\Users\Ada Lovelace\memory.db"
on Windows). In JSON config files, use forward slashes or escaped backslashes
for Windows paths. Imports accept CRLF and a UTF-8 BOM; convert other encodings to UTF-8.
SESSIONMEM_PROJECT_ID pins the project bucket (useful when moving a repository);
otherwise it is derived from the repository root or working directory.
SESSIONMEM_ADAPTER selects the install/doctor/uninstall host unless --adapter is set.
SESSIONMEM_DEBUG=1 enables ingest-hook diagnostics on stderr.
Local REST API and JavaScript client
sessionmem serve --api
curl 'http://127.0.0.1:3778/v1/search?query=database&limit=5'This is a local single-user API, not a hosted service. It binds to 127.0.0.1
and uses the current repository's project, including SESSIONMEM_PROJECT_ID
overrides. It supports compact search, timelines, full details, saves and deletes
through the same service methods as MCP. Other projects cannot be selected by a
request. Set SESSIONMEM_API_TOKEN or --token to require bearer authentication
on every route. Cross-origin browser requests and unexpected Host headers are
rejected. Non-loopback binds require --allow-remote and print a warning.
import { SessionmemClient } from "sessionmem/client";
const client = new SessionmemClient("http://127.0.0.1:3778");
const index = await client.searchMemoryIndex({ query: "database", limit: 5 });
if (index.memories.length) console.log(await client.getMemory(index.memories[0].id));The fetch client includes TypeScript declarations and adds no runtime dependencies. See API documentation for authentication, limits, all client methods and curl examples.
Inspect memories in your browser
sessionmem ui
sessionmem ui --port 8080
sessionmem ui --port 0 # Pick an available portThe command prints its URL and opens your default browser. It binds only to
127.0.0.1, needs no authentication, and serves all assets locally using Node's
built-in HTTP server. No external services, CDNs, or additional runtime dependencies
are used. If browser launch is unavailable, open the printed URL manually. Press
Ctrl-C to stop the server and close its database connection.
The viewer starts on the current project, with a selector for other projects in
the same store. Browse saved memories, search through the existing recall path,
inspect extracted entities and relations with their source memories, and follow
supersession chains with old/new values, source IDs, assertion times, detection
times, and partial/full status. Search returns up to 50 results and defaults to
current facts; select Include superseded facts in search to recall history.
Browsing lists all saved records, including superseded and expired ones, in pages
of 50. Source IDs open full memory details. Entity visibility and history links
use the same rules as sessionmem entities and sessionmem history.
The database is opened read-only. Browsing and on-demand search do not increment
access counts, migrate the schema, or change memories. Only HTTP GET and HEAD are
accepted; no write, delete, or edit routes are exposed. Responses are not cached,
and cross-origin browser requests and unexpected Host headers are rejected. Run
sessionmem ping first to initialize a missing store or upgrade an older schema.
The usual SESSIONMEM_DB_PATH and SESSIONMEM_PROJECT_ID overrides
apply. Anyone with access to this computer can read the local viewer while it is
running; stop it when finished inspecting private memories.
Import existing sessions and watch for new ones
When a fact changes, sessionmem can link its replacement locally. For example, “I use VS Code” followed by “I switched to Neovim” supersedes the earlier editor choice. Recall excludes fully superseded memories by default. retrieveMemories accepts the optional includeHistory: true; sessionmem search --include-history searches earlier facts too. sessionmem history shows what replaced what. The old memory stays available through show, list, and export.
Detection uses deterministic entity/relation rules, shared purpose words, a small tool-category vocabulary, and explicit negation or replacement phrases. It needs no API or model. Unfamiliar wording can be missed, and ambiguous changes can be misclassified. A memory with independent claims remains searchable while any claim is current; history labels these partial supersessions. See supersession details.
Install starts capture for existing history and new sessions automatically. For a manual import or a foreground diagnostic run:
sessionmem scan
sessionmem watch --once
sessionmem watch --interval 10
sessionmem scan --host cursorBoth commands sweep all detected transcript histories by default:
Claude Code:
~/.claude/projects/**/*.jsonl.Codex CLI:
~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl.Cursor:
User/globalStorage/state.vscdbunder~/Library/Application Support/Cursoron macOS,~/.config/Cursoron Linux, or%APPDATA%/Cursoron Windows.
Missing history directories are allowed. Use --transcripts-dir "/path/to/history"
to select another transcript tree; each JSONL file's host is detected from its records.
For Cursor, the override accepts its User directory or a state.vscdb path.
Use --host cursor, --host codex, or --host claude-code to select one host,
including when using an override. A Cursor User directory or .vscdb file is
also detected without --host. Files that do not match a supported format, or
the selected host, produce an explicit unsupported format error.
Both commands work offline without API keys and always use the local summarizer,
even if cloud summarization is enabled elsewhere. sessionmem doctor checks
transcript discovery for all three hosts, parses JSONL samples, and validates
Cursor's composer indexes and message rows when history is present.
Transcript user/assistant text, supported Claude tool uses (Bash, Edit, Write,
MultiEdit), and Codex function calls pass through the existing event-ingestion,
redaction, and session-summary pipeline. Codex tool events retain the native tool
name and call_id. Encrypted agent_message payloads and obvious injected machine
blocks, including plugin catalogues and environment context, are excluded. Each
session gets one summary memory, including short sessions with only one event.
Updated sessions refresh that summary. Project buckets come from
each Claude transcript's cwd, Codex session_meta.payload.cwd, or Cursor's
workspace path, using the repository root when available; the directory where you run scan/watch does not
select the project. SESSIONMEM_PROJECT_ID can explicitly pin all imports to one
bucket. Transcripts without capturable events are skipped. Claude transcripts
without a working directory are also skipped; Codex session metadata must contain
an ID and working directory. Nested subagent files get separate session summaries.
Summary memories record sourceAdapter as claude-code, codex, or cursor
according to the transcript host. Cursor session IDs come from composerId.
Cursor stores messages in cursorDiskKV bubble rows in its global SQLite
database. The importer supports workspace composer.composerData indexes
(Cursor 2.6 and earlier) and the central composer.composerHeaders index
(Cursor 3.0 and later). It captures up to 4,000 characters of user/assistant text
per bubble and excludes tool-only bubbles and internal tool/code fields. Missing
tables, index keys, or required conversation data produce an explicit
unsupported format for cursor error.
Cursor databases are never written. Each sweep copies the database and its WAL to a private temporary directory, checking for concurrent changes during the copy. SQLite opens the copy read-only, using immutable mode when URI support is available and there is no WAL to replay. Cursor's live database is never opened by SQLite. Busy copies are reported and retried. Each sweep reads a fresh snapshot; per-composer checkpoints skip unchanged messages, and streamed bubble updates refresh the existing event without duplicating it.
Codex resumes create new rollout files. Files with the same session ID are grouped,
and replayed events are deduplicated across files, sweeps, and restarts. A Codex
sub-agent keeps its own session_meta.payload.id, even when parent_thread_id
points to a parent session.
Re-running either command does not duplicate memories or transcript events.
File and composer checkpoints live in the selected memory database, and unchanged
files or composers are skipped across restarts. For Cursor, files found counts
global databases, and skipped counts unchanged or empty composers.
Stable event IDs also make interrupted imports safe to
retry. Partial or malformed JSONL lines are reported and retried on later sweeps;
valid events in the same file can still be captured. A single sweep exits with
status 1 if it encounters errors. The daemon keeps running and retries errors.
watch prints its first sweep and subsequent imports or errors. A manual run
stays in the foreground until SIGINT or SIGTERM. Login capture uses the same
watcher with an absolute Node executable and absolute sessionmem entry point;
it does not need a shell, a TTY, or your interactive PATH.
Control login capture explicitly:
sessionmem autostart status
sessionmem autostart disable
sessionmem autostart enableenable updates one registration and starts capture immediately. disable stops
the registered watcher and removes its login registration, preserving memories.
The next sessionmem install enables it again. This control affects the login
watcher; Claude Code hooks and explicit MCP memory tools remain active.
Registrations:
OS | Registration |
macOS |
|
Linux |
|
Windows | Scheduled Task |
Capture output and failures are appended with timestamps to logs/watch.log
beside the selected database (default ~/.sessionmem/logs/watch.log). The
watcher also writes memories.db.watch-checkpoint.json beside the default store
after each completed sweep. Doctor checks this checkpoint's age, capture errors,
and transcript checkpoint count; unchanged history and an empty history are
healthy when the watcher continues completing sweeps. A checkpoint older than
two minutes fails the default 5-second watcher check. For a custom polling
interval, the limit is the greater of two minutes and three intervals.
SESSIONMEM_DB_PATH selected at install or enable is saved as an absolute
watcher argument. Run enable with that variable again to switch stores. The
policy config remains ~/.sessionmem/config.json. After moving sessionmem or
changing Node versions, run sessionmem autostart enable to update the absolute
paths. For failures before the watcher can open its log, inspect launchctl print gui/<uid>/io.sessionmem.watch, journalctl --user -u sessionmem-watch.service, or Windows Task Scheduler's task history.
Uninstall
sessionmem uninstall --adapter claude-code
# Also delete the selected memory database:
sessionmem uninstall --adapter claude-code --purgeUninstall stops capture and removes the login registration before removing MCP
configuration, Claude hooks, and agent guidance for the selected host. It keeps
the database, config and logs by default. Use the same SESSIONMEM_DB_PATH as
install when selecting a custom database to purge. If stopping or unregistering
the watcher fails, uninstall reports the OS error and leaves the database intact.
For multiple installed hosts, repeat uninstall with each adapter to remove its
MCP configuration and guidance.
Privacy, secrets, and your data
Storage, retrieval, and summarization run locally by default. There is no account, telemetry, or hosted memory service. Settings live in ~/.sessionmem/config.json.
Secrets are scrubbed automatically
Before saving memory content, sessionmem replaces common secret patterns with REDACTED:
Email addresses
API keys (
sk-..., AWSAKIA..., GitHubghp_.../gho_..., etc.)Bearer tokens and JWTs
Private key blocks (
-----BEGIN ... PRIVATE KEY-----)Connection-string style secrets (
password=...,secret=...)
Redaction is on by default. To scan and clean up older memories:
sessionmem redact-scan # see what would be redacted
sessionmem redact-scan --apply # actually redact in placeFull details: docs/privacy-and-retention.md.
Memory rot: keeping memory accurate over time
Old decisions and duplicate facts can accumulate in a memory store, causing the assistant to use outdated information. This is sometimes called "memory rot."
sessionmem handles it through retention, ranking, and sync rules:
Retention pruning: memories older than a configurable window (90 days by default) are eligible for deletion. A lightweight check runs at session end. You can also run it manually:
sessionmem retention prune # dry run - shows what *would* be deleted sessionmem retention prune --force # actually deletesImportance-weighted ranking: retrieval ranks memories by offline BM25 lexical relevance, entity overlap, recency, and importance. Older, less important notes rank lower even before they are pruned.
Token-budgeted injection: only the highest-ranked memories are loaded, trimmed to a small token budget (see benchmarks). The context stays within that budget as the store grows.
Conflict resolution in team mode: merging teammate memories uses last-write-wins by id to avoid stale duplicates and keeps the higher importance score so a warning isn't downgraded.
The conversational benchmark measures retrieval quality separately from retention and startup token budgets.
Export your memories before pruning if you want to keep a copy:
sessionmem exportTeam mode (optional)
To share decisions and warnings across your team's AI assistants, point sessionmem at a folder everyone can read and write, such as a network drive or synced directory:
sessionmem team enable <shared-path>
sessionmem syncTeam mode is off by default. Nothing is shared until you enable it.
Memories are shared as files in that folder; no server is needed.
Teammate memories appear with an
author:prefix identifying their source.Redaction runs on every pulled memory using your redaction policy.
Full details, including the trust model: docs/team-mode.md.
Cloud summarization (optional, off by default)
By default, session summaries are created locally, with no API calls.
To use Claude's API for higher-quality summaries, set allowCloudSummarization=true and provide an ANTHROPIC_API_KEY. If cloud summarization fails after retries, sessionmem uses local summarization. Failures are recorded for diagnosis; see the configuration guide below.
Details: docs/cloud-summarization.md.
Automatic memory by host
After installation, the login-started watcher captures supported local transcripts. Recall on hosts without native hooks follows installed agent instructions, so it depends on the agent executing the memory tools.
Host | Capture | Recall |
Claude Code | Tool/end hooks and transcript watcher | SessionStart and UserPromptSubmit hooks inject context |
Codex | Rollout watcher | Global AGENTS.md and MCP instructions require startup and new-topic searches |
Cursor | Composer SQLite watcher | Project always-apply rule and MCP instructions require searches |
Windsurf, Cline | Instructed agent saves; no transcript importer | Installed rules and MCP instructions |
Antigravity, QCoder | Instructed saves; native adapter paths remain unverified | Instruction-driven, subject to host loading |
Generic MCP | Instructed saves if the host reads AGENTS.md or MCP instructions | Instruction-driven, subject to host support |
Install detects available Claude Code, Codex, Cursor and Windsurf CLI executables.
Other hosts use --adapter at setup. Missing guidance now fails installation.
Doctor checks capture and recall separately, identifies instruction-driven modes,
and provides repair hints. See automatic memory for
exact scope, supported formats, tool permissions and the CI install-to-recall test.
Memory retrieval tools
Use searchMemoryIndex for a compact list of matches, memoryTimeline to inspect
nearby records, and getMemory for selected full details. Compact tools default
to 10 results and cap one-line summaries at 160 characters. See
retrieval tools and optional ranking for inputs,
visibility rules and measured token costs.
Temporal retrieval defaults off because it did not improve the pinned-clock
LoCoMo run. Entity coverage is enabled for BM25 and disabled when MiniLM is
active. This raises default hit rate from 63.92% to 64.44%, precision from 14.05%
to 14.32%, and recall from 57.45% to 58.27%; optional hybrid quality is preserved.
The entityLinkBoost setting overrides this automatic choice. Source-informed
adaptive and additive alternatives remain opt-in. See
all before/after results and losses.
An independent bounded entity boost is available with
sessionmem config set entityBoost true. Exact names and explicit aliases can
add at most 0.06 to the final ranking score, while recency and importance still
apply. Queries without known entities keep their scores. It defaults off:
LoCoMo hit rate @5 rose from 64.44% to 64.51%, but precision and recall fell.
See the measured tradeoffs. Compact search, timeline
and details by ID keep the same interfaces and response limits.
Capture also records an optional context label called a scope. It uses the real
working directory name, falling back to the project ID for headless capture.
Override it with scope on capture requests, --scope <name> on scan/watch,
SESSIONMEM_SCOPE, or sessionmem config set scope <name> for new sessions.
Run sessionmem scopes --json to inspect local labels and counts.
sessionmem search "deployment" --scope release filters a context;
adding --scope-mode boost favors that context while retaining other results.
Queries without a scope keep their existing response bytes and ranking.
Existing databases upgrade automatically without labelling historical records.
See scope behavior and migration safety.
Supported tools
sessionmem works with any MCP-compatible host, including:
Claude Code
Cursor
Codex
Cline
Windsurf
Antigravity
QCoder
Other tools that implement the Model Context Protocol can connect too.
Further documentation
Automatic memory: capture and recall per host, diagnostics and CI evidence.
Retrieval tools: compact search, timeline, full details and optional ranking.
Architecture: how the core engine, adapters, CLI, and SQLite storage fit together.
Benchmark: conversational retrieval results and reproduction steps.
Privacy and retention: secret redaction, retention pruning, and config.
Team mode: shared-path team memory.
Cloud summarization: the opt-in cloud summarization path.
Migration: the SQLite migration system and version-upgrade policy.
Troubleshooting: install failures, adapter issues, and
better-sqlite3native-build problems.
Troubleshooting
For install failures, adapter issues, missing session data, or better-sqlite3 native-build problems, see docs/troubleshooting.md.
Start with offline diagnostics:
sessionmem doctor
sessionmem doctor --adapter claude-code # explicit host overridedoctor reports a separate PASS or FAIL for the memory store, schema, transcript
discovery for Claude Code, Codex and Cursor, login auto-start registration,
registered binary paths, watcher capture checkpoint freshness, hook definitions
shipped with the current version, configured MCP command, and a canary
write/recall. It exits nonzero if any check fails and prints fix hints,
including exact commands for safe repairs. It does not create a missing store or
apply migrations. Its temporary canary is isolated from your projects and rolled
back even on failure. The MCP check starts the installed local command and verifies
its version, tools, and a stats response; it does not require a running agent.
Use sessionmem ping to initialize a missing store or apply pending schema
migrations, or sessionmem install --adapter claude-code to refresh Claude Code's
MCP registration and hooks. Use sessionmem autostart enable to refresh the
login service and absolute binary paths; inspect logs/watch.log beside the
database when capture fails. Run repairs with the same SESSIONMEM_DB_PATH as
doctor when using a custom store.
If stats shows sessions: 0 after real work, see “0 sessions” / no session data recorded. Memories are keyed to the repository root, so every directory inside one repo shares a bucket; outside a repo the working directory itself is the key.
To check database access and memory counts:
sessionmem ping # can the local database be opened?
sessionmem stats # is data being stored?FAQ
How do I give Cursor, Cline, or Windsurf memory between sessions?
Install sessionmem (npm i -g sessionmem), then run sessionmem install in your project. Use --adapter cursor, --adapter cline, or --adapter windsurf when auto-detection cannot identify your host.
How do I give Claude Code persistent memory?
Use the same install steps above. sessionmem also ships as a Claude Code plugin (the .claude-plugin directory in the repo) for Claude Code's native plugin system.
Is there a local MCP memory server that works offline with no API key?
Yes. sessionmem stores memories in a single SQLite file at ~/.sessionmem/memories.db and works offline by default. Sharing and cloud summarization are optional and off by default.
How is sessionmem different from claude-mem? sessionmem works with Claude Code, Cursor, Cline, Codex, Windsurf, Antigravity, QCoder, and other MCP hosts. It redacts secrets (API keys, tokens, JWTs) by default, prunes old memories automatically, and includes reproducible benchmarks.
Does sessionmem send my code to the cloud? No. Nothing leaves your machine by default. The optional cloud summarization path is opt-in and off by default.
How do I see how many tokens sessionmem saved me?
Run sessionmem savings to see a breakdown of storage compression (raw session tokens vs memory tokens) and injection efficiency. Add --json for machine-readable output.
Security
See the security policy for supported versions, private vulnerability reporting through GitHub security advisories, and response expectations.
Contributing
Issues and pull requests are welcome. The codebase is TypeScript, tested with Vitest, and linted with ESLint:
npm ci
npm run build
npm run typecheck
npm test
npm run lintMCP config for local development: Clone the repository, build it, copy
.mcp.json.example to .mcp.json, and replace the example path with the absolute
path to your checkout’s dist/cli/index.js. This runs your local build.
sessionmem install registers the sessionmem executable on PATH instead. The .mcp.json file is gitignored because it contains machine-specific paths.
License
Available Tools
15 toolsbatchStoreMemoryA
Persist multiple memory units in a single atomic SQLite transaction. Significantly faster than calling storeMemory repeatedly for session-end writes of 10-20 memories.
WHEN TO CALL: At session end or whenever you have multiple memories to store at once. Reduces overhead from per-insert fsync by wrapping all writes in one transaction.
WHEN NOT TO CALL: For a single memory — use storeMemory instead. For imports from external files — use importMemories.
Each item in the memories array follows the same schema as storeMemory (memoryId, sessionId, sourceAdapter, kind, content, importance). Invalid items are reported individually; valid items are still stored atomically.
NOTE: the per-item memory echoed back in the response has its content truncated to 2000 characters (a batch can return many rows). The full body is still persisted — fetch it with getMemory if you need the complete text. (Single-record storeMemory echoes the full content.)
| Name | Required | Description | Default |
|---|---|---|---|
| memories | Yes | Array of memory objects to store. Each must include: memoryId (unique UUID), sessionId, sourceAdapter, kind, content (self-contained text), importance (1-10). Minimum 1 item, maximum 100. Per-item results may include `warningCodes` (e.g. 'session_write_limit_warning', 'redaction_partial_failure') — advisory signals, not failures. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds meaningful context beyond the annotations (idempotentHint=false, destructiveHint=false): atomic wrapping, per-insert fsync savings, per-item partial success where invalid items are reported but valid items still commit, and 2000-char content truncation in the echoed response with a pointer to getMemory. That is rich disclosure. However, the interaction between 'atomic' and 'valid items are still stored' is ambiguous, and it doesn't state duplicate-memoryId behavior despite declaring non-idempotency.
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 purpose, then WHEN/WITHOUT/NOTE blocks that make scanning easy. Minor redundancy: 'Significantly faster than calling storeMemory repeatedly' and 'Reduces overhead from per-insert fsync' say the same thing twice.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries the return-value burden and does so: per-item error reporting, warningCodes semantics, and content truncation with a recovery path via getMemory. Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the primary parameter additionally carries its own inline description with required fields and warningCodes. The prose mostly restates that structure and points to storeMemory's schema, so this is the baseline case where the schema does the heavy lifting.
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 ('Persist multiple memory units in a single atomic SQLite transaction') and immediately scopes it against siblings: not storeMemory for singles, not importMemories for file imports. An agent can pick this over the 14 siblings without opening a 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?
Has explicit WHEN TO CALL (session end, 10-20 memories at once) and WHEN NOT TO CALL sections that name the two alternative tools and the condition selecting each. No inference required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fetch_memoriesA
Fallback memory retrieval for hosts that do not support MCP resources. Call this instead of accessing the sessionmem:// resource URI directly when the host lacks resource support. Semantically equivalent to retrieveMemories — returns stored memories ranked by relevance to the query. Read-only; no side effects.
WHEN TO CALL: At session start and mid-session when you need to retrieve context and the host does not support MCP resources. Do not call if the host supports MCP resources — use the sessionmem:// resource URI or retrieveMemories tool instead.
Parameter query: natural-language description of what context you need to recall (e.g. 'API design decisions', 'database schema choices').
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Natural-language description of what context you need to recall. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses it is read-only with no side effects, and returns memories ranked by relevance. No annotations provided, so description fully informs agent.
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 concise paragraphs, front-loaded with purpose, then usage, then parameter detail. No unnecessary words.
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 one parameter, no output schema, and moderate complexity, description fully covers purpose, usage, and parameter meaning.
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 covers parameter with description, and description adds examples of query values. Since schema coverage is 100%, baseline is 3; the added examples justify a 4.
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?
Clearly states it is a fallback memory retrieval for hosts without MCP resource support, returns memories ranked by relevance, and distinguishes from siblings like retrieveMemories and the resource URI.
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 specifies when to call (session start, mid-session when host lacks resource support) and when not to call (host supports resources, instead use URI or retrieveMemories).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
forgetMemoryADestructive
Permanently delete a single memory by ID. The record is removed from the local SQLite store immediately and CANNOT be recovered. Destructive and irreversible.
WHEN TO CALL: Only when a memory is known to be incorrect, dangerously outdated, or a duplicate that would mislead future sessions.
WHEN NOT TO CALL: If there is any doubt. A memory that is merely old or low-relevance does not need deletion — retrieval ranking deprioritizes it automatically.
| Name | Required | Description | Default |
|---|---|---|---|
| memoryId | Yes | Exact UUID of the memory to permanently delete. Obtain from a prior listMemories or retrieveMemories call. Deletion is immediate and irreversible. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations (destructiveHint=true), description adds details: deletion from local SQLite store, immediate, irreversible, and unrecoverable, providing full 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?
Concise with a main sentence plus structured WHEN TO CALL/WHEN NOT TO CALL sections. Every sentence adds value; no waste.
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 one required parameter, no output schema, and simple functionality, the description covers purpose, usage guidelines, and behavioral transparency completely.
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 already describes memoryId in detail (UUID, obtain from prior calls, immediate deletion). Description adds no new parameter info beyond the schema, so baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action (permanently delete) and the resource (a single memory by ID), distinguishing it from siblings like batchStoreMemory or storeMemory. The 'WHEN TO CALL' and 'WHEN NOT TO CALL' sections further clarify scope.
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 provides when (memory incorrect/dangerously outdated/duplicate) and when not to call (doubt, merely old/low-relevance), with clear alternatives implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
getMemoryARead-onlyIdempotent
Fetch a single memory record by its exact ID. Returns the full record: content, kind, importance, timestamps, and session metadata. Read-only; no side effects.
WHEN TO CALL: After searchMemoryIndex or memoryTimeline, fetch selected IDs for full details. IDs from retrieveMemories or listMemories also work.
For topic searches, start with searchMemoryIndex. getMemory requires an exact ID.
| Name | Required | Description | Default |
|---|---|---|---|
| memoryId | Yes | Exact memory ID from searchMemoryIndex, memoryTimeline, retrieveMemories or listMemories. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint, and the description's 'Read-only; no side effects' reinforces rather than contradicts them. It adds genuine value beyond the annotations by enumerating the returned payload (content, kind, importance, timestamps, session metadata), which matters because there is no output schema.
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 and return shape, then a clearly labeled WHEN TO CALL section, then a short alternative hint. No sentence is redundant and length is proportionate to a one-parameter read 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?
Because there is no output schema, the description usefully lists returned fields and covers the exact-ID prerequisite. It stops short of stating behavior on a missing/invalid ID (empty result vs error), which is the one remaining gap for an agent calling with a stale ID.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single memoryId parameter is already documented with its origin sources. The description restates the 'exact ID' constraint without adding format, length, or failure-mode detail the schema lacks, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Fetch a single memory record by its exact ID') and immediately distinguishes itself from the search/timeline siblings by requiring an exact ID. The returned fields are enumerated, so the agent knows precisely what it gets back.
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 WHEN TO CALL block is explicit: call after searchMemoryIndex or memoryTimeline to hydrate selected IDs, and it names retrieveMemories and listMemories as additional ID sources. It also gives an exclusion — for topic searches start with searchMemoryIndex instead — so the routing decision is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
handleSessionEndAIdempotent
Run the full session-end pipeline: auto-summarize the session's ingested events into a durable memory (when enough events exist) and apply a light retention prune of stale memories. Idempotent on the summary memory (upsert by sessionId).
WHEN TO CALL: Once, at the very end of a session, after ingesting session events via ingestSessionEvents. Lets sessionmem generate and store the session summary for you.
WHEN NOT TO CALL: Mid-session, or when you have already written your own summary (use summarizeSessionToMemory instead). On Claude Code this also runs automatically via the installed SessionEnd hook, so calling it explicitly is usually unnecessary there.
Provide sessionId and sourceAdapter. memoryId (optional) pins the summary's id; omit to derive ${sessionId}-summary. config (optional) tunes autoSummarize / minimumEventThreshold / cloud summarization; omit for sensible local-only defaults.
RESPONSE status is one of: 'stored', 'skipped_threshold' (too few events), 'skipped_disabled', 'failed'. warningCodes may carry cloud/local fallback signals.
| Name | Required | Description | Default |
|---|---|---|---|
| scope | No | ||
| config | No | ||
| memoryId | No | ||
| sessionId | Yes | ||
| sourceAdapter | Yes | ||
| workingDirectory | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint and destructiveHint=false, but the description adds real value beyond them: the idempotency mechanism (upsert by sessionId), the existence of a retention prune of stale memories, threshold-gated summarization, and the four possible status outcomes plus warningCodes for cloud/local fallback. It does not detail what the prune actually removes or what permissions/keys cloud summarization requires.
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?
Well front-loaded: one-sentence pipeline summary, then labeled WHEN TO CALL / WHEN NOT / parameter notes / response codes. Slightly padded by the repeated 'omit for sensible defaults' phrasing and some incidental detail, but nothing is genuinely wasted.
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?
No output schema, yet the description enumerates the status values and warningCodes, which is the main return-value need. The remaining gap is undocumented optional params (scope, workingDirectory, several config keys) that an agent could mis-set silently.
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% across 6 params including a nested config object, so the description must compensate. It explains sessionId, sourceAdapter, memoryId's default derivation, and three config fields — helpful — but leaves scope, workingDirectory, factMode, summaryTokenCap, redactionEnabled, and anthropicApiKey entirely undocumented.
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 composite action (summarize ingested events into durable memory plus a light retention prune) and names the exact alternative (summarizeSessionToMemory) it differs from. An agent can distinguish it from siblings like ingestSessionEvents or storeMemory 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?
Explicit WHEN TO CALL (once, at the very end, after ingestSessionEvents) and WHEN NOT TO CALL (mid-session, or when a summary already exists — use summarizeSessionToMemory instead). It even notes the Claude Code SessionEnd hook makes explicit invocation usually unnecessary, which is exactly the routing info an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ingestSessionEventsAIdempotent
Push raw session events (tool calls, decisions, file edits, user turns) to sessionmem so they can be summarized at session end and counted toward token-savings analytics. Writes immediately, in a single transaction. Re-ingesting the same (sessionId, eventIndex) is a no-op, so retries are safe.
WHEN TO CALL: Periodically during a session (e.g. at task boundaries) to record what happened, OR in one batch shortly before the session ends. This is what powers automatic session-end summarization and sessionmem savings.
WHEN NOT TO CALL: For durable, individually-important facts/decisions — use storeMemory for those. Session events are transient raw material for summarization, not first-class memories.
Each event needs: id (unique), eventIndex (monotonic 0-based order within the session), eventType (e.g. 'tool_use', 'user_message'), payloadJson (a JSON string of the event body).
LIMITS: at most 500 events per call. For more than 500 events, call this tool multiple times in chunks — re-ingestion of already-stored events is safe (idempotent via the (project, session, eventIndex) UNIQUE index), so overlapping chunks never double-count.
| Name | Required | Description | Default |
|---|---|---|---|
| scope | No | ||
| events | Yes | ||
| sessionId | Yes | ||
| replaceExisting | No | ||
| workingDirectory | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing immediate single-transaction writes, idempotency keyed on the (project, session, eventIndex) UNIQUE index, and the 500-event cap. It is consistent with idempotentHint=true, but never mentions the replaceExisting parameter, which could change the no-op-on-reingest behavior an agent relies on.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads what the tool does, then organizes when-to/when-not/limits into scannable blocks. Every sentence carries actionable information; nothing is 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?
With no output schema and no annotations covering safety beyond idempotency, the description covers transactionality, idempotent retry semantics, and batch limits thoroughly. The one material gap is the undocumented replaceExisting flag and scope, which affect how an agent should shape repeat calls.
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 carries the documentation burden; it does explain the nested event fields (id, eventIndex, eventType, payloadJson) but omits createdAt, scope, workingDirectory and especially replaceExisting, whose effect on the idempotency guarantee is unstated. Useful but incomplete compensation.
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 ('Push raw session events ... to sessionmem') plus the downstream purpose (session-end summarization, token-savings analytics). It explicitly distinguishes itself from storeMemory, so an agent can tell ingestion of transient events from storing first-class memories without opening either 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?
Provides explicit WHEN TO CALL (periodically at task boundaries, or one batch before session end) and WHEN NOT TO CALL, naming storeMemory as the alternative for durable facts. It also gives operational guidance for oversized batches (chunk at 500, overlapping is safe).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
listMemoriesARead-onlyIdempotent
Return every memory stored for the current project, unfiltered and without ranking. Read-only; no side effects.
WHEN TO CALL: When you need a complete inventory of stored memories — to audit what has been saved, detect duplicates, or build a full summary of all known context.
WHEN NOT TO CALL: For normal context loading at session start — use retrieveMemories instead, which ranks by relevance. listMemories returns the entire store unfiltered and can be very large.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true; description confirms read-only with no side effects and warns the output can be very large, adding value beyond annotations.
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 a clear main sentence followed by structured usage guidelines (WHEN TO CALL, WHEN NOT TO CALL), front-loading essential information with no wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a list tool without output schema, the description covers purpose, usage, and behavioral traits well. Minor gap: does not describe the return format, but given the simplicity and annotations, it is nearly complete.
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%, and the description does not explain the 'limit' parameter or its effect, despite the parameter having constraints in the schema. The description should compensate for low schema coverage but fails to do so.
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 tool returns every memory unfiltered, and contrasts with retrieveMemories which ranks by relevance, making the purpose specific and distinguishable from siblings.
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 provides WHEN TO CALL (audit, detect duplicates, build full summary) and WHEN NOT TO CALL (session start; suggests retrieveMemories instead), with clear alternative named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memoryTimelineARead-onlyIdempotent
Browse compact memories in capture order around memoryId, or within an inclusive UTC fromDate/toDate range. Provide an ID or both dates. Includes superseded history by default. Default limit 10, maximum 50. Use getMemory for full details. Does not update access counters.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| scope | No | ||
| toDate | No | ||
| fromDate | No | ||
| memoryId | No | ||
| includeHistory | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent annotations by disclosing that superseded history is included by default, that the default limit is 10 with a max of 50, and that the call does not bump access counters — a non-obvious side-effect distinction that matters for agents reasoning about memory usage stats.
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?
Six short sentences, zero filler, with the primary selection modes front-loaded and constraints (limits, defaults, counter behavior) trailing. Every sentence carries a distinct operational fact.
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?
Six optional parameters, no output schema, and no annotations beyond safety hints — the description covers modes, bounds, defaults, and history behavior, and notes output is 'compact' versus getMemory's full records. Only the undocumented `scope` parameter keeps it from being complete.
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 burden well: it explains memoryId, fromDate/toDate (inclusive, UTC), limit (default 10, max 50), and includeHistory (superseded history included by default). The `scope` parameter is never mentioned anywhere, which is the one real 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?
Names a specific verb and resource (browse compact memories) with two precise selection modes: capture order around memoryId, or an inclusive UTC fromDate/toDate range. It also distinguishes itself from getMemory, which returns full details rather than compact entries.
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?
"Provide an ID or both dates" gives a clear admission condition, and "Use getMemory for full details" routes the agent to the right sibling for the expanded-record case. It does not position itself against listMemories, retrieveMemories, or searchMemoryIndex, so the sibling routing is only partial.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resetAccessCountsAIdempotent
Reset access-pattern counters for all memories in the current project. Sets access_count to 0 and clears last_accessed timestamps without deleting any memories. Useful after large refactors when old access patterns no longer reflect current relevance.
WHEN TO CALL: After major codebase restructuring, project pivots, or when access-boosted rankings no longer reflect current relevance.
WHEN NOT TO CALL: During normal operation — access patterns self-correct as usage shifts.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide destructiveHint=false and idempotentHint=true. The description adds context by detailing the exact state changes (setting counters to 0, clearing timestamps) and affirming no deletions. No contradiction with annotations.
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?
Description is clear and well-structured with separate sections for purpose and usage guidelines. Slightly verbose but efficient; could be trimmed without losing meaning.
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 the tool's simplicity (no params, no output schema), the description fully covers purpose, behavior, usage contexts, and side effects. Leaves no relevant gaps.
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 zero parameters and 100% schema coverage (empty schema), baseline is 4. The description compensates by explaining the action and its effects, adding value 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 clearly states the tool resets access-pattern counters for all memories in the current project, specifying it sets access_count to 0 and clears timestamps without deletion. It distinguishes from siblings like forgetMemory or listMemories by focusing on counters rather than storage or retrieval.
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 provides 'WHEN TO CALL' and 'WHEN NOT TO CALL' sections, advising use after major refactors and against use during normal operation where self-correction occurs. This gives clear context and alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retrieveMemoriesA
Semantically search stored memories and return the top matches ranked by a weighted combination of relevance, recency, and importance. Read-only; no side effects.
WHEN TO CALL: (1) At the start of every session — pass the current task or file as the query to pre-load relevant context. (2) Mid-session whenever a new topic, file, or decision area arises that may have prior context. Do NOT call on every user turn.
WHEN NOT TO CALL: If you already retrieved memories for this topic this session. Use getMemory if you have a specific memoryId. Use listMemories only to audit the full store, not for context loading.
Returns up to limit results (default 20). mode='auto' is the standard startup path; mode='on-demand' signals an explicit mid-session lookup. depth='deep' runs a broader semantic sweep at higher latency — use when the topic is unfamiliar. Phrase query as what you need to recall, not what you are about to do.
NOTE: this tool updates access-pattern counters on the memories it returns (used to boost frequently-recalled memories in future ranking), so it is NOT side-effect-free despite being a lookup.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | 'auto' for the standard startup context-load path. 'on-demand' for an explicit mid-session retrieval triggered by a specific task or question. | auto |
| tags | No | Optional tag filter. When provided, only return memories that have ALL listed tags. | |
| depth | No | 'default' for standard semantic search. 'deep' for a broader sweep that surfaces less-similar memories — use when the topic is new or unfamiliar. | default |
| limit | No | Maximum number of memories to return. Integer 1-100, default 20. Increase for broad topic sweeps; keep at default for focused lookups. | |
| query | Yes | Natural-language description of what you need to recall. Phrase as a topic or question (e.g. 'database connection settings', 'auth flow decisions') — not an action ('store info about...'). | |
| includeHistory | No | Include superseded facts for historical questions. Omit for current facts only. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The opening claims 'Read-only; no side effects,' which directly contradicts the readOnlyHint=false annotation. Although a later NOTE admits that access-pattern counters are updated and the tool is not side-effect-free, the definition remains internally inconsistent in a way that could mislead an agent about mutation.
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 definition is front-loaded with purpose and organized into clear WHEN TO CALL / WHEN NOT TO CALL sections. It is somewhat long and repeats schema details, and the incorrect 'Read-only; no side effects' line is wasted and harmful, but the structure is otherwise efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a six-parameter retrieval tool with no output schema, it covers ranking, default result count, mode/depth usage, and alternatives well enough to call correctly. The side-effect contradiction prevents a higher score, but the schema fills in tag and includeHistory semantics.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all six parameters are already documented in the input schema. The description largely restates mode, depth, query phrasing, and limit behavior, with no additional syntax or edge-case guidance 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 states a specific verb and resource: semantically search stored memories and return top matches ranked by relevance, recency, and importance. It distinguishes itself from siblings by naming getMemory for memoryId lookups and listMemories for store auditing.
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 explicit WHEN TO CALL triggers for session start and mid-session topic changes, plus WHEN NOT TO CALL conditions including avoiding repeated retrieval and not calling every user turn. It also routes specific cases to getMemory and listMemories.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchMemoryIndexARead-onlyIdempotent
Search a compact memory index. Returns IDs, one-line previews, kinds, capture dates and scores. Start here for topic lookups, use memoryTimeline for nearby context, then getMemory for selected full bodies. Default limit 10, maximum 50. Does not update access counters. hasMore refers to the bounded candidate pool.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | ||
| limit | No | ||
| query | Yes | ||
| scope | No | ||
| scopeMode | No | ||
| includeHistory | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavioral context beyond the annotations: it describes return fields, default and maximum limit, that access counters are not updated, and how hasMore relates to the bounded candidate pool. Annotations already cover read-only and idempotent behavior, and the description complements them well.
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 front-loaded, information-dense, and free of filler. Each sentence adds practical value about workflow, return shape, limits, or side effects.
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?
It covers the search workflow, return shape, limit defaults, and hasMore semantics, which is useful for a tool without an output schema. However, for a six-parameter tool with no schema descriptions, it leaves key parameters like tags, scope, scopeMode, and includeHistory unexplained.
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 explain parameter meanings. It only clarifies limit (default 10, maximum 50) and implies query via "topic lookups"; tags, scope, scopeMode (filter vs boost), and includeHistory are not explained at all.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: "Search a compact memory index." It also distinguishes the tool from memoryTimeline and getMemory by positioning it as the starting point for topic lookups and full-body retrieval.
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: "Start here for topic lookups, use memoryTimeline for nearby context, then getMemory for selected full bodies." This gives clear when-to-use guidance and names the relevant alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
startup_inject_memoriesA
Fallback startup-injection for hosts that do not support MCP prompts. Call this once at the very start of a session instead of relying on the automatic sessionmem startup prompt when the host lacks prompt support. Injects the top relevant memories for the current project into the working context. No parameters required.
WHEN TO CALL: Once per session start, before any user task work begins, when the host does not surface MCP prompts automatically. Do not call if the host already surfaces the sessionmem startup prompt — calling both duplicates injected context.
Note: access counts are incremented on retrieval.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description carries full burden. Discloses that access counts are incremented on retrieval and that it is a fallback. However, does not detail criteria for 'top relevant memories' or side effects if called multiple times.
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 concise paragraphs with clear structure, including a 'WHEN TO CALL' note. No redundant sentences.
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 no output schema and no annotations, description covers purpose, usage, and a behavioral note. Could mention behavior when no relevant memories exist or if called multiple times, but overall adequate.
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, so baseline 4. Description adds context about the injection purpose but no need for parameter details.
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 it's a fallback to inject memories when host doesn't support MCP prompts. It specifies the action (injects top relevant memories for current project) and distinguishes from siblings like 'retrieveMemories' or 'fetch_memories' by explaining it's a session start injection.
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 states when to call (once per session start, when host lacks prompt support) and when not to call (if host already surfaces sessionmem startup prompt). Provides alternative guidance (rely on automatic prompt) to avoid duplication.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
statsARead-onlyIdempotent
Return aggregate statistics for the current project: total stored memory count and total ingested session event count. Read-only; no side effects.
WHEN TO CALL: For diagnostic or monitoring purposes — to confirm memories were stored after a session, check store health, or report usage numbers.
WHEN NOT TO CALL: As part of normal context loading. stats returns counts only, not content; use retrieveMemories to load actual context.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint and idempotentHint. Description adds the specific statistics returned and reaffirms no side effects. Valuable context but not essential beyond annotations.
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 well-structured sentences: purpose, when to call, when not to call. No redundancy, every sentence adds value.
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?
Complete for a simple parameterless tool with no output schema. Covers purpose, usage guidelines, and differentiates from siblings.
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 exist, so description adds no param info. Baseline is 4; description is clear about what the tool does without needing to reference parameters.
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 specifies the exact resource and action: returning aggregate statistics (total stored memory count and total ingested session event count) for the current project. It clearly distinguishes from sibling tools like retrieveMemories.
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 states when to call (diagnostic/monitoring) and when not to call (not for normal context loading), with an alternative tool suggested.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
storeMemoryA
Persist a single memory unit to the local SQLite store. Accepts decisions, facts, architectural choices, warnings, and session summaries. NOT idempotent — each call creates a new record even with identical content. Writes to disk immediately.
WHEN TO CALL: After any significant decision, discovery, or conclusion that should be available in a future session. Good candidates: technology choices, non-obvious constraints, bug root-causes, architectural decisions, key facts about the codebase.
WHEN NOT TO CALL: For trivial observations, transient state, or content that duplicates what was just retrieved. Do not store entire files or full conversation transcripts.
kind categories: 'decision', 'fact', 'summary', 'warning', 'preference'. Write content to be self-contained — it must be useful without any surrounding conversation context. importance 1-10 (10 = most critical); directly affects retrieval ranking in future sessions.
RESPONSE may include warningCodes: 'session_write_limit_warning' (this session has stored many memories — stop storing trivia and prefer batchStoreMemory) and 'redaction_partial_failure' (a redaction rule errored; the write still succeeded). Treat them as advisory signals, not errors.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | Yes | Category of this memory. One of: 'decision', 'fact', 'warning', 'preference', 'summary'. These are the only recognized kinds — others are rejected. | |
| tags | No | Optional array of tag strings (max 10, each max 50 chars) for categorizing this memory. Example: ['auth', 'db-schema']. Tags are filterable via retrieveMemories. | |
| content | Yes | The memory text. Must be self-contained and specific — written so it is useful without surrounding conversation context. Avoid vague phrases like 'the user decided to...'. | |
| memoryId | Yes | Caller-supplied unique UUID for this memory (e.g. crypto.randomUUID()). Used for deduplication and for later retrieval by ID via getMemory. | |
| expiresAt | No | Optional UTC ISO timestamp (e.g. '2026-12-31T00:00:00Z') after which this memory is excluded from retrieval. Use for time-limited context like a temporary workaround. | |
| sessionId | Yes | Identifier for the current session. Used to group memories by session for diagnostics. Use a consistent ID within a single session. | |
| importance | Yes | Integer 1-10 indicating criticality (10 = most important). Directly affects ranking in future retrieveMemories calls. Use 8-10 for decisions that must not be forgotten; 3-5 for useful but non-critical facts. | |
| sourceAdapter | Yes | Name of the adapter or host creating this memory (e.g. 'claude-code', 'cursor', 'generic'). Used for provenance tracking. | |
| redactionEnabled | No | If true, PII is stripped from content before storage. Omit to use the project-level redaction setting from config.json. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only carry idempotentHint=false and destructiveHint=false; the description adds material context beyond them — immediate disk writes, the non-idempotent duplicate-record behavior, redaction behavior, and the meaning of advisory warningCodes. Nothing contradicts the annotations.
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 operation, then cleanly partitioned into WHEN TO CALL / WHEN NOT TO CALL / parameter notes / response notes. Despite its length, each block carries distinct, actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter mutation tool with no output schema, the description covers invocation context, behavioral caveats, and return-signal semantics (warningCodes). An agent has everything needed to call it correctly and interpret the response.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all 9 parameters. The description's notes on kind categories and importance's effect on retrieval ranking largely restate the schema rather than adding syntax or format detail, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Persist a single memory unit to the local SQLite store') and immediately scopes it as single-unit, which distinguishes it from the sibling batchStoreMemory. An agent can identify the operation without opening the 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?
Explicit WHEN TO CALL and WHEN NOT TO CALL sections with concrete examples (technology choices, bug root-causes vs. trivial observations, transcripts). It also routes to the alternative (batchStoreMemory) inside the write-limit warning, giving a clear switch condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
summarizeSessionToMemoryAIdempotent
Store an agent-authored session summary as a durable 'summary' memory in one call. Upserts on memoryId, so calling it again with the same memoryId replaces the prior summary rather than duplicating it.
WHEN TO CALL: At session end when you have already written a concise summary of what was accomplished and want to persist it directly (the simpler alternative to handleSessionEnd's automatic summarization).
WHEN NOT TO CALL: When you want sessionmem to generate the summary from ingested session events — use handleSessionEnd for that. For non-summary facts/decisions use storeMemory.
Provide: memoryId (stable id for this session's summary), sessionId, sourceAdapter, summary (the text), importance (1-10; 7 is typical for summaries).
| Name | Required | Description | Default |
|---|---|---|---|
| scope | No | ||
| summary | Yes | ||
| memoryId | Yes | ||
| sessionId | Yes | ||
| importance | Yes | ||
| sourceAdapter | Yes | ||
| workingDirectory | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint=true and destructiveHint=false, and the description usefully explains *why*: upserting on memoryId replaces the prior summary instead of duplicating, so an agent understands the overwrite behavior. It does not cover auth requirements, size/retention limits, or what a successful call returns, keeping it 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 and upsert semantics, then organized into WHEN TO CALL / WHEN NOT TO CALL / Provide blocks. Slightly list-heavy for the payload, but nearly every line carries decision-relevant information rather than restating 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 no output schema and no annotation coverage of returns, the description still gives an agent everything needed to invoke it correctly: purpose, routing, idempotency behavior, and key parameter meanings. Only the response shape and the meaning of scope/workingDirectory are absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must carry the load, and it does for five of seven parameters — notably defining memoryId as a stable per-session id and giving a practical anchor for importance (1-10; 7 is typical). scope and workingDirectory are left entirely unexplained, so it does not fully compensate.
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 action and resource: storing an agent-authored session summary as a durable 'summary' memory, and explicitly frames it as the one-call, caller-written counterpart to summarization. The upsert-on-memoryId clause further pins down the semantics so it is distinguishable from storeMemory and handleSessionEnd.
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?
Has explicit WHEN TO CALL and WHEN NOT TO CALL blocks naming the alternatives (handleSessionEnd for generated summaries, storeMemory for non-summary facts). The selection condition between the two paths is stated plainly rather than inferred.
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.
6 tool updates
v1.10.0- Changed
batchStoreMemory2 fields changed- added
Input schema / properties / memories / items / properties / scopeAdded value: +{ + "anyOf": [ + { + "maxLength": 160, + "minLength": 1, + "pattern": "^[^\\x00-\\x1f\\x7f]+$", + "type": "string" + }, + { + "type": "null" + } + ] +} - added
Input schema / properties / memories / items / properties / workingDirectoryAdded value: +{ + "maxLength": 4096, + "minLength": 1, + "type": "string" +}
- Changed
handleSessionEnd2 fields changed- added
Input schema / properties / scopeAdded value: +{ + "anyOf": [ + { + "maxLength": 160, + "minLength": 1, + "pattern": "^[^\\x00-\\x1f\\x7f]+$", + "type": "string" + }, + { + "type": "null" + } + ] +} - added
Input schema / properties / workingDirectoryAdded value: +{ + "maxLength": 4096, + "minLength": 1, + "type": "string" +}
- Changed
ingestSessionEvents2 fields changed- added
Input schema / properties / scopeAdded value: +{ + "anyOf": [ + { + "maxLength": 160, + "minLength": 1, + "pattern": "^[^\\x00-\\x1f\\x7f]+$", + "type": "string" + }, + { + "type": "null" + } + ] +} - added
Input schema / properties / workingDirectoryAdded value: +{ + "maxLength": 4096, + "minLength": 1, + "type": "string" +}
- Changed
memoryTimeline1 field changed- added
Input schema / properties / scopeAdded value: +{ + "anyOf": [ + { + "maxLength": 160, + "minLength": 1, + "pattern": "^[^\\x00-\\x1f\\x7f]+$", + "type": "string" + }, + { + "type": "null" + } + ] +}
- Changed
searchMemoryIndex2 fields changed- added
Input schema / properties / scopeAdded value: +{ + "anyOf": [ + { + "maxLength": 160, + "minLength": 1, + "pattern": "^[^\\x00-\\x1f\\x7f]+$", + "type": "string" + }, + { + "type": "null" + } + ] +} - added
Input schema / properties / scopeModeAdded value: +{ + "enum": [ + "filter", + "boost" + ], + "type": "string" +}
- Changed
summarizeSessionToMemory2 fields changed- added
Input schema / properties / scopeAdded value: +{ + "anyOf": [ + { + "maxLength": 160, + "minLength": 1, + "pattern": "^[^\\x00-\\x1f\\x7f]+$", + "type": "string" + }, + { + "type": "null" + } + ] +} - added
Input schema / properties / workingDirectoryAdded value: +{ + "maxLength": 4096, + "minLength": 1, + "type": "string" +}
3 tool updates
v1.9.0- Changed
getMemory1 field changed- changed
Input schema / properties / memoryId / descriptionPrevious value: -"Exact UUID of the memory to fetch. Obtain from a prior retrieveMemories or listMemories result."New value: +"Exact memory ID from searchMemoryIndex, memoryTimeline, retrieveMemories or listMemories."
- Added
memoryTimeline - Added
searchMemoryIndex
4 tool updates
v1.6.0- Changed
batchStoreMemory3 fields changed- added
Input schema / properties / memories / items / properties / expiresAtAdded value: +{ + "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?Z$", + "type": "string" +} - added
Input schema / properties / memories / items / properties / tagsAdded value: +{ + "items": { + "maxLength": 50, + "minLength": 1, + "type": "string" + }, + "maxItems": 10, + "type": "array" +} - changed
Input schema / properties / memories / items / requiredPrevious value: -[ - "memoryId", - "sessionId", - "sourceAdapter", - "content", - "importance" -]New value: +[ + "memoryId", + "sessionId", + "sourceAdapter", + "kind", + "content", + "importance" +]
- Changed
ingestSessionEvents2 fields changed- changed
Input schema / properties / events / items / requiredPrevious value: -[ - "id", - "eventIndex", - "eventType", - "payloadJson" -]New value: +[ + "id", + "eventType", + "payloadJson" +] - added
Input schema / properties / replaceExistingAdded value: +{ + "type": "boolean" +}
- Changed
retrieveMemories2 fields changed- added
Input schema / properties / includeHistoryAdded value: +{ + "description": "Include superseded facts for historical questions. Omit for current facts only.", + "type": "boolean" +} - added
Input schema / properties / tagsAdded value: +{ + "description": "Optional tag filter. When provided, only return memories that have ALL listed tags.", + "items": { + "maxLength": 50, + "minLength": 1, + "type": "string" + }, + "maxItems": 10, + "type": "array" +}
- Changed
storeMemory3 fields changed- added
Input schema / properties / expiresAtAdded value: +{ + "description": "Optional UTC ISO timestamp (e.g. '2026-12-31T00:00:00Z') after which this memory is excluded from retrieval. Use for time-limited context like a temporary workaround.", + "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?Z$", + "type": "string" +} - added
Input schema / properties / tagsAdded value: +{ + "description": "Optional array of tag strings (max 10, each max 50 chars) for categorizing this memory. Example: ['auth', 'db-schema']. Tags are filterable via retrieveMemories.", + "items": { + "maxLength": 50, + "minLength": 1, + "type": "string" + }, + "maxItems": 10, + "type": "array" +} - changed
Input schema / requiredPrevious value: -[ - "memoryId", - "sessionId", - "sourceAdapter", - "content", - "importance" -]New value: +[ + "memoryId", + "sessionId", + "sourceAdapter", + "kind", + "content", + "importance" +]
11 tool updates
v1.1.2- Changed
batchStoreMemory10 fields changed- changed
Input schema / properties / memories / descriptionPrevious value: -"Array of memory objects to store. Each must include: memoryId (unique UUID), sessionId, sourceAdapter, kind, content (self-contained text), importance (1-10). Minimum 1 item."New value: +"Array of memory objects to store. Each must include: memoryId (unique UUID), sessionId, sourceAdapter, kind, content (self-contained text), importance (1-10). Minimum 1 item, maximum 100.\n\nPer-item results may include `warningCodes` (e.g. 'session_write_limit_warning', 'redaction_partial_failure') — advisory signals, not failures." - added
Input schema / properties / memories / items / properties / content / maxLengthAdded value: +10000 - added
Input schema / properties / memories / items / properties / kind / enumAdded value: +[ + "decision", + "fact", + "warning", + "preference", + "summary" +] - removed
Input schema / properties / memories / items / properties / kind / minLengthRemoved value: -1 - added
Input schema / properties / memories / items / properties / memoryId / maxLengthAdded value: +200 - added
Input schema / properties / memories / items / properties / sessionId / maxLengthAdded value: +200 - added
Input schema / properties / memories / items / properties / sourceAdapter / maxLengthAdded value: +100 - added
Input schema / properties / memories / items / properties / sourceAdapter / patternAdded value: +"^[^\\n\\r\\x00-\\x08\\x0e-\\x1f\\x7f]*$" - changed
Input schema / properties / memories / items / requiredPrevious value: -[ - "memoryId", - "sessionId", - "sourceAdapter", - "kind", - "content", - "importance" -]New value: +[ + "memoryId", + "sessionId", + "sourceAdapter", + "content", + "importance" +] - added
Input schema / properties / memories / maxItemsAdded value: +100
- Added
fetch_memories - Changed
forgetMemory1 field changed- added
Input schema / properties / memoryId / maxLengthAdded value: +200
- Changed
getMemory1 field changed- added
Input schema / properties / memoryId / maxLengthAdded value: +200
- Added
handleSessionEnd - Added
ingestSessionEvents - Changed
listMemories1 field changed- added
Input schema / properties / limitAdded value: +{ + "exclusiveMinimum": 0, + "maximum": 1000, + "type": "integer" +}
- Changed
retrieveMemories1 field changed- added
Input schema / properties / query / maxLengthAdded value: +1000
- Added
startup_inject_memories - Changed
storeMemory9 fields changed- added
Input schema / properties / content / maxLengthAdded value: +10000 - changed
Input schema / properties / kind / descriptionPrevious value: -"Category of this memory. Recommended values: 'decision', 'fact', 'summary', 'warning', 'architecture'. Any non-empty string is valid."New value: +"Category of this memory. One of: 'decision', 'fact', 'warning', 'preference', 'summary'. These are the only recognized kinds — others are rejected." - added
Input schema / properties / kind / enumAdded value: +[ + "decision", + "fact", + "warning", + "preference", + "summary" +] - removed
Input schema / properties / kind / minLengthRemoved value: -1 - added
Input schema / properties / memoryId / maxLengthAdded value: +200 - added
Input schema / properties / sessionId / maxLengthAdded value: +200 - added
Input schema / properties / sourceAdapter / maxLengthAdded value: +100 - added
Input schema / properties / sourceAdapter / patternAdded value: +"^[^\\n\\r\\x00-\\x08\\x0e-\\x1f\\x7f]*$" - changed
Input schema / requiredPrevious value: -[ - "memoryId", - "sessionId", - "sourceAdapter", - "kind", - "content", - "importance" -]New value: +[ + "memoryId", + "sessionId", + "sourceAdapter", + "content", + "importance" +]
- Added
summarizeSessionToMemory
6 tool updates
v1.0.6- Added
batchStoreMemory - Changed
forgetMemory1 field changed- added
Input schema / properties / memoryId / descriptionAdded value: +"Exact UUID of the memory to permanently delete. Obtain from a prior listMemories or retrieveMemories call. Deletion is immediate and irreversible."
- Changed
getMemory1 field changed- added
Input schema / properties / memoryId / descriptionAdded value: +"Exact UUID of the memory to fetch. Obtain from a prior retrieveMemories or listMemories result."
- Added
resetAccessCounts - Changed
retrieveMemories4 fields changed- added
Input schema / properties / depth / descriptionAdded value: +"'default' for standard semantic search. 'deep' for a broader sweep that surfaces less-similar memories — use when the topic is new or unfamiliar." - added
Input schema / properties / limit / descriptionAdded value: +"Maximum number of memories to return. Integer 1-100, default 20. Increase for broad topic sweeps; keep at default for focused lookups." - added
Input schema / properties / mode / descriptionAdded value: +"'auto' for the standard startup context-load path. 'on-demand' for an explicit mid-session retrieval triggered by a specific task or question." - added
Input schema / properties / query / descriptionAdded value: +"Natural-language description of what you need to recall. Phrase as a topic or question (e.g. 'database connection settings', 'auth flow decisions') — not an action ('store info about...')."
- Changed
storeMemory7 fields changed- added
Input schema / properties / content / descriptionAdded value: +"The memory text. Must be self-contained and specific — written so it is useful without surrounding conversation context. Avoid vague phrases like 'the user decided to...'." - added
Input schema / properties / importance / descriptionAdded value: +"Integer 1-10 indicating criticality (10 = most important). Directly affects ranking in future retrieveMemories calls. Use 8-10 for decisions that must not be forgotten; 3-5 for useful but non-critical facts." - added
Input schema / properties / kind / descriptionAdded value: +"Category of this memory. Recommended values: 'decision', 'fact', 'summary', 'warning', 'architecture'. Any non-empty string is valid." - added
Input schema / properties / memoryId / descriptionAdded value: +"Caller-supplied unique UUID for this memory (e.g. crypto.randomUUID()). Used for deduplication and for later retrieval by ID via getMemory." - added
Input schema / properties / redactionEnabled / descriptionAdded value: +"If true, PII is stripped from content before storage. Omit to use the project-level redaction setting from config.json." - added
Input schema / properties / sessionId / descriptionAdded value: +"Identifier for the current session. Used to group memories by session for diagnostics. Use a consistent ID within a single session." - added
Input schema / properties / sourceAdapter / descriptionAdded value: +"Name of the adapter or host creating this memory (e.g. 'claude-code', 'cursor', 'generic'). Used for provenance tracking."
6 tool updates
v1.0.0- First observed
forgetMemory - First observed
getMemory - First observed
listMemories - First observed
retrieveMemories - First observed
stats - First observed
storeMemory
TDQS
Scored across 15 tools
Four tools retrieve memories (retrieveMemories, fetch_memories, searchMemoryIndex, startup_inject_memories) and three browse the store (listMemories, memoryTimeline, searchMemoryIndex), creating real selection risk. Descriptions do explain the distinctions (host-capability fallback vs. ranked search vs. index scan), but an agent must read carefully to avoid duplication, and startup_inject_memories overlaps heavily with retrieveMemories at session start.
Most tools use camelCase verb_noun (storeMemory, getMemory, forgetMemory, batchStoreMemory), but two use snake_case (fetch_memories, startup_inject_memories). Also, for a memory domain, the noun is sometimes 'Memory' and sometimes omitted (stats, handleSessionEnd), which weakens the pattern.
15 tools sits at the upper bound for a memory server, and several earn their place only in niche host configurations (fetch_memories, startup_inject_memories, resetAccessCounts). The core lifecycle could be covered with roughly 10 tools; the extra fallback/administrative surface makes the set feel heavy.
Coverage is broad: create, batch create, semantic retrieve, index search, timeline browse, get, list, delete, session events, summaries, and stats. The notable gap is updating/editing an existing memory's content or importance — only summaries upsert, so corrections require forget + store.
Maintenance
Related MCP Connectors
Hosted MCP memory: save sessions/decisions once, search from Claude, Cursor, ChatGPT. EU-hosted FTS.
- mcpOAuthai.butlerbrain
Persistent memory for AI assistants. Save once; recall from Claude, ChatGPT, or any MCP client.
Give your AI agent persistent, governed memory for every project. At task start it recalls the approved decisions, conventions, risks and architecture (semantic search, ranked by importance); at close it proposes what was learned as typed memories that you review and approve — governance, not a notes dump. Agents propose, humans govern: edits go back to pending and deletion is human-only by design. Connect Claude Code, Cursor, Claude Desktop or any MCP client in two minutes with just your API key — hosted (nothing to install) or locally via `uvx solucortex-mcp`. Built by SoluAI and dogfooded daily: SoluCortex is developed using its own living memory.
Persistent memory and cross-session learning for AI coding assistants (hosted remote MCP).
Related MCP Servers
- AlicenseAqualityCmaintenancePersistent memory MCP server for Claude Code, Cursor, and GitHub Copilot. Semantic search, Git sync, project-based, Persistent memory MCP server for Claude Code, Cursor, and GitHub Copilot. Semantic search, Git sync, project-based organization, and team collaboration via Model Context Protocol.11415 npm2MIT
- AlicenseBqualityAmaintenancePersistent memory MCP server that captures coding session context and automatically injects relevant memories into prompts using hybrid search for OpenCode and Claude Code.1473MIT
- AlicenseBqualityCmaintenanceCross-tool AI memory MCP server for Claude Code, Cursor, Antigravity, Windsurf, and every MCP-compatible AI. 400 tokens not 4,000.34MIT
- AlicenseAqualityCmaintenanceLocal-first MCP server that gives any AI coding agent per-project memory, workflow intelligence, and always-on, lossless token & context optimization.3713 npm6MIT