Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, get in touch and we’ll put it right.

io.github.0Mattias/bettermemory

PYPI · BETTERMEMORY · SCANNED SEP 20

Memory for coding agents, checked against the filesystem and git before it is believed.

Available components

−2 this week 77 Trust /100
Trust breakdown (7 categories)

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →

Supply Chain Security100
  • No malware found by supply-chain analysis.Pass
  • No known CVEs affecting this package version or its production dependencies.Pass
  • Runs hatchling.build at install time, a recognised native-build step with no shell scripting around it. View diagnostics → Pass
  • 1 of 31 dependencies flagged as unhealthy. View diagnostics → Partial
Provenance & Transparency48
  • Source repository is publicly reachable at the declared URL. View diagnostics → Pass
  • Provenance check failed: no build-provenance attestation is published. See how to fix → View diagnostics → Fail
  • Clear OSI-approved license (MIT).Pass
  • Actively maintained (last published 3 days ago).Pass
  • Publishes a security disclosure policy (SECURITY.md).Pass
Schema Quality & AI Usability61
  • AI-judged instruction clarity (excellent).Pass
  • Context-footprint check failed: tool/resource definitions use about 6878 tokens (~382/item across 18 items; 18 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
  • Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management90
  • Stability observed for 27 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage71
  • 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
  • 0% of tool parameters carry a description.Fail
  • Structured output schemas are declared (100% of tools); any adoption earns full credit.Pass
Tool Safety75
  • No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
  • 0 of 1 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "memory_remove" implies "remove" and declares no destructiveHint at all, which the MCP spec reads as destructive by default. See how to fix → Fail
  • An AI judge read all 19 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
  • Implements a current MCP spec version (2026-07-28).Pass
Install

How do I install the io.github.0Mattias/bettermemory MCP server?

io.github.0Mattias/bettermemory runs locally as a PyPI package, launched with uvx bettermemory. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

pypi · bettermemory

# add to Claude Code
claude mcp add 0mattias-bettermemory -- uvx bettermemory
// .cursor/mcp.json
{
  "mcpServers": {
    "0mattias-bettermemory": {
      "command": "uvx",
      "args": [
        "bettermemory"
      ]
    }
  }
}
// .vscode/mcp.json
{
  "servers": {
    "0mattias-bettermemory": {
      "command": "uvx",
      "args": [
        "bettermemory"
      ]
    }
  }
}
# add to Codex CLI
codex mcp add 0mattias-bettermemory -- uvx bettermemory
// opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "0mattias-bettermemory": {
      "type": "local",
      "command": [
        "uvx",
        "bettermemory"
      ],
      "enabled": true
    }
  }
}
# add to OpenClaw
openclaw mcp add 0mattias-bettermemory --command uvx --arg bettermemory
# ~/.hermes/config.yaml
mcp_servers:
  0mattias-bettermemory:
    command: "uvx"
    args: ["bettermemory"]
// ~/.netclaw/config/netclaw.json
{
  "McpServers": {
    "0mattias-bettermemory": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "bettermemory"
      ]
    }
  }
}
# add to Vellum
assistant mcp add 0mattias-bettermemory -t stdio -c uvx -a bettermemory
// mcp.json
{
  "mcpServers": {
    "0mattias-bettermemory": {
      "command": "uvx",
      "args": [
        "bettermemory"
      ]
    }
  }
}
Changelog

Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.

  • 19 Sept 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 83 to 87. That category is still filling its 30-day observation window: 25 days of observed history at the previous scan, 26 at this one. The score rises as the window fills, whether or not the server changes.

  • 17 Sept 26 −3
    • Stability: pass → unverified security
    • Tool safety: pass → unverified security
    • Capabilities: pass → unverified functional
    • Tool coverage: 100 → unverified functional
    • Stability: pass → 0.80 functional
    • Package version: 7.18.0 → 7.19.1 functional
    • Package version: 7.18.0 → 7.19.0 functional
  • 16 Sept 26 +1
    • Stability: 0.97 → unverified security
    • Tool safety: pass → unverified security
    • Stability: 0.97 → pass security
    • Capabilities: pass → unverified functional
    • Tool coverage: 100 → unverified functional
    • Package version: 7.17.2 → 7.18.0 functional
  • 15 Sept 26 −1
    • Stability: pass → 0.97 functional
  • 13 Sept 26 +1
    • Stability: 0.97 → pass security
  • 12 Sept 26 −1
    • Stability: pass → unverified security
    • Tool safety: pass → unverified security
    • Malware scan: pass → unverified security
    • Capabilities: pass → unverified functional
    • Tool coverage: 100 → unverified functional
    • Stability: pass → 0.97 functional
    • Package version: 7.15.0 → 7.17.2 functional
    • Package version: 7.15.0 → 7.17.1 functional
    • Package version: 7.15.0 → 7.17.0 functional
    • Package version: 7.15.0 → 7.16.0 functional
    • Package version: 7.15.0 → 7.15.1 functional
  • 11 Sept 26 +15
    • Stability: pass → unverified security
    • Tool safety: pass → unverified security
    • Malware scan: unverified → pass security
    • Capabilities: pass → unverified functional
    • Tool coverage: 100 → unverified functional
    • Package version: 7.11.0 → 7.15.0 functional
    • Package version: 7.11.0 → 7.14.0 functional
    • Package version: 7.11.0 → 7.13.0 functional
    • Package version: 7.11.0 → 7.12.0 functional
  • 10 Sept 26 −15
    • Malware scan: pass → unverified security
    • Stability: pass → unverified security
    • Tool safety: pass → unverified security
    • Capabilities: pass → unverified functional
    • Tool coverage: 100 → unverified functional
    • Package version: 7.8.0 → 7.11.0 functional
    • Package version: 7.8.0 → 7.10.0 functional
    • Package version: 7.8.0 → 7.9.0 functional
Diagnostics

Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.

Captured 20 Sept 2026 · Analysed pypi/bettermemory@7.19.1

Provenance No attestation

The registry publishes no build provenance for this version, so there is nothing to verify.

Result No attestation
Ecosystem pypi

Background: How many MCP packages publish verified provenance →

Install scripts 1 script
Hook Tier Command
build_backend allowlisted hatchling.build

Background: Why install scripts are a supply-chain risk →

Dependencies 31 packages
Packages resolved 31
No linked repository 1
Tree resolution Complete

Background: SBOMs and build attestations, explained →

MCP tools · 18 exposed · ~6,540 tokens

The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →

Tool Tokens
episode_handoff ~397

Read the most-recent journal takeaways from a prior session in this worktree. Call this FIRST at a /loop iteration entry: it answers 'what did the last session conclude here?' without memory_search. Episodes are the sibling-to-memory primitive for journal-shaped writes (see episode_write). When `prior_session_id` is omitted the handler auto-resolves it from the event log under two implicit filters: caller-worktree strict equality (`None` matches only `None`) and the `disabled_scopes` cascade (a session whose only takeaways are scope-disabled is skipped; surviving episodes are scope-filtered). Pass it explicitly to override. Returns a dict: - `prior_session_id`: the resolved session id, or None when no prior session exists in the log. - `episodes`: list of {id, created, takeaway, scopes, provenance} dicts, oldest first, capped at `max_episodes` (default 5, cap 50). `provenance` is read from the event log: `local` (an episode_write event names the id), `untracked` (no event could have) or `unaccounted` (the file appeared with no event: the planted shape). `body` is present only with `include_bodies=True` (default False) and never for an unaccounted episode; episode_search(ids=[...]) is the explicit read for one body. - `note` (optional `str`): set ONLY when the immediately-prior worktree session left nothing visible; names the cause: floor-only, zero-episode, promoted-out, or all-scope-hidden. The last two DID journal, so a `note` never means 'wrote no journal'. `episodes` MAY be non-empty: the walk rewinds to an older takeaway.

NameTypeReqDescription
include_bodiesboolean
max_episodes
prior_session_id

Structured output declared, but exposes no named fields.

No examples provided.

episode_promote ~381

Promote a journal entry (episode) into a durable memory. Routes through memory_write — the durability gate, scope-mismatch detection, dedup, and user-inference confirmation flow all apply. Use this when an iteration's takeaway turns out to be a fact worth keeping across sessions, not just a run-state note. Loop/working state belongs in episodes; session close is when to promote the takeaways that hardened. On successful commit the source episode is deleted (its content has been distilled). On `pending` (user-inference category), the source episode is held for memory_write_confirm to delete — memory_write_cancel keeps the episode so you can retry. On any other non-committed status (duplicate, previously_removed, transient_warning, scope_mismatch, ungrounded) the source episode is left untouched so you can adjust and re-promote. Body default: when `use_body=False` (default), the durable memory's body is the episode's takeaway. Set `use_body=True` to use the full episode body. An episode with no takeaway requires use_body=True. Returns the `memory_write` response shape plus `promoted_from_episode_id`, on every outcome. Parameters: - `episode_id`: ULID of the source episode. - `scopes`: scopes for the durable memory. Required. - `category` (default 'fact'): memory category. user-inference still requires explicit user confirmation. - `confidence` (default 'medium'), `source` (default 'explicit-statement'): standard memory_write fields. - `use_body=False`: when True, use the episode's body instead of its takeaway.

NameTypeReqDescription
categorystring
confidencestring
episode_idstringyes
scopesarrayyes
sourcestring
use_bodyboolean

Structured output declared, but exposes no named fields.

No examples provided.

episode_search ~537

Cross-session lookup for journal-shaped entries (episodes). NOT ranked — episodes are chronological and the filter set (scope / since / session_id) is the discovery surface. For the loop-iteration-entry case prefer `episode_handoff`, which auto-resolves the prior session and caps the surface. Rows are oldest-first INSIDE the most-recent-`max_results` window: over the cap it keeps the MOST-RECENT N, so 'what did I conclude lately?' reads the tail, not the head. WORKTREE SCOPING: by default (`auto_scope=True`) the bare discovery walk (no `swarm_id` / `parent_session_id`) drops episodes whose captured git worktree differs from yours. PERMISSIVE, not a boundary, and weaker than the strict equality episode_handoff applies — it passes an episode through when there is nothing to compare (none captured, or you outside any git checkout), when the recorded worktree is gone from disk, and when you are in a LINKED worktree of the checkout that wrote it, so under agent fan-out the primary checkout's episodes stay visible. An EXPLICIT `swarm_id` / `parent_session_id` / `ids` is never worktree-filtered: naming a cohort or session is deliberate cross-worktree intent. Parameters (full reference in docs/api.md): - `scopes` (optional): keep only episodes whose scope list intersects this filter. - `parent_session_id` (optional): restrict to one session's directory. Composes with `swarm_id` to narrow a fan-in. - `swarm_id` (optional): fan-in filter — episodes tagged with this cohort id, across all sessions. - `since` (optional ISO-8601): created at-or-after this instant. - `auto_scope` (default True): worktree-scope the bare walk (see WORKTREE SCOPING). False sweeps every worktree sharing the root. - `max_results` (default 20, cap 200): surfaces the most-recent N. - `ids` (optional): only these episode ULIDs — explicit selector, never worktree-filtered; unknown ids are absent, not an error. - `include_bodies` (default True): False OMITS `body` — takeaway-only rows. Scan, then re-rea…

NameTypeReqDescription
auto_scopeboolean
ids
include_bodiesboolean
max_results
parent_session_id
scopes
since
swarm_id
NameTypeReqDescription
resultarrayyes

No examples provided.

episode_write ~472

Append a journal-shaped entry for the current session — for run-state, iteration takeaways, 'what we tried'. Episodes are NOT durable facts; the durability gate that rejects transient memory_write content (TRANSIENT_PHRASE_MARKERS) does not apply here. Stored at <root>/episodes/<session_id>/<ulid>.md with a default 30-day TTL. Use this for content memory_write would reject as transient: - 'iteration N tried X, fell over at step 3' - 'currently blocked on Y; next step is Z' - 'this branch's release plan' (state that changes weekly) Episodes are invisible to memory_search / memory_health / memory_list — they are a sibling tier, not a memory category. Surface them via episode_handoff at iteration entry or episode_search for cross-session lookup. Promote a takeaway to durable memory via episode_promote (routes through memory_write, durability gate fires as normal). Parameters: - `body`: free-form markdown. Required, non-empty. Capped by `max_content_bytes` (default 1 MB). - `swarm_id` (optional): cohort id for multi-agent fan-in — a sub-agent passes the coordinator's session id so the coordinator can gather every sub-agent's takeaways via `episode_search(swarm_id=…)`. A cross-cutting label, not a move: the episode still lives under this writer's own session, and it is distinct from `episode_handoff`'s predecessor link. - `takeaway` (optional): one-sentence summary. Surfaced preferentially at episode_handoff; when None, handoff falls back to the first line of body. Capped by `max_takeaway_bytes` (default 4 KB). - `scopes` (optional): list of scope tags. Empty list is valid (handoff keys on session_id, not scope). Capped by `max_scopes_per_write` (default 64). Both caps guard one thing: takeaway and scopes serialise into the YAML frontmatter (64 KB ceiling), so an over-cap value corrupts the file and the episode vanishes from every read surface despite the write returning `committed`.

NameTypeReqDescription
bodystringyes
scopes
swarm_id
takeaway

Structured output declared, but exposes no named fields.

No examples provided.

memory_audit_turn ~226

Not for in-conversation use. This tool is dispatched by the client's end-of-turn Stop hook; the model should never call this directly. Silent-miss telemetry (full reference in docs/api.md). Runs the search probe `memory_search` would have run for `user_message` (`assistant_response` optional), then checks whether a `memory_search`, `memory_show`, `memory_list`, or hook-injected `prompt_recall` event fired in the same session within `lookback_seconds` (default 60). A high-relevance probe hit with no retrieval in that window is a miss. Auto-scopes to the caller's repo so the probe matches the model's view; honours session-disabled scopes. Returns a `MissReport` with `verdict` in {'miss', 'ok', 'no_signal'} plus the top probe hits. Side-effects: emits `turn_audited` always, plus `search_miss` when the verdict is `miss`.

NameTypeReqDescription
assistant_response
lookback_seconds
user_messagestringyes

Structured output declared, but exposes no named fields.

No examples provided.

memory_list ~226

List active memories. By default returns one-line summaries (IDs, scopes, summary, no body) — cheap triage. Pass `with_bodies=True` to inline full bodies in one call; useful for small stores where N round trips of `list -> show -> show` would be wasteful. Don't reach for `with_bodies` casually — it pulls every memory in scope into your context, which is the failure mode this project exists to avoid. Filter by `scopes` if you only care about a subset, or by `client` / `model` — each row's DECLARED actor, exact. A row's `staleness_verdict` is CALENDAR-ONLY — no path, claim or commit drift — so a row can read `fresh` while `memory_show` on it returns `spot_check_required`. Read a non-`fresh` row as a signal to look, never a `fresh` one as a clearance.

NameTypeReqDescription
client
model
scopes
with_bodiesboolean
NameTypeReqDescription
resultarrayyes

No examples provided.

memory_record_use ~413

Override the auto-`applied` outcome. Default behavior: every memory_search hit settles as `applied` at turn end (excerpts when the reply used it, `auto=true` otherwise). The common case handles itself — only call this tool when the model needs to record one of the three actionable outcomes below. | Outcome | When | What it does | |---|---|---| | `ignored` | retrieved but off-topic | annotates later hits; under `outcome_demotion`, mild 30d demotion (applied/update/verify clears) | | `contradicted` | stored fact disagreed AND not yet fixed | raises the unresolved-contradiction flag until a later memory_update or memory_verify clears it; demotes 2x under the same flag | | `corrected` | drifted and you fixed it inline (memory_update and/or memory_verify already called) | audit-only; does NOT raise the flag, never demotes | `applied` is also accepted explicitly (rarely needed — auto handles it; call only to force-commit early). Parameters: - `memory_ids`: list (1+). - `outcome`: see table above. - `note` (optional, ≤800 chars): free-form context. - `claim_excerpts` (optional): list parallel to `memory_ids` (same length, `None` slots OK) carrying the load-bearing phrase that shaped the response. ≤500 chars per excerpt. Pass `None` for 'no specific claim' — empty strings are rejected (they're ambiguous: missing claim vs. zero-length claim). Especially useful on `contradicted` / `corrected` so the audit log records WHICH claim was wrong, not just that the memory drifted. Surfaces back in `recent_negative_outcomes` on later search hits.

NameTypeReqDescription
claim_excerpts
memory_idsarrayyes
note
outcomestringyes

Structured output declared, but exposes no named fields.

No examples provided.

memory_remove ~120

Tombstone a memory. The file is moved to .tombstones/ with a removal reason and the originating session id — never hard-deleted. Use when a stored fact is wrong or no longer relevant. Tombstones remain searchable via memory_list_tombstones and are surfaced as `removed_matches` on memory_write when a new body looks similar to a previously-removed fact, so the lesson encoded in the removal reason isn't lost. Use memory_restore(id) to undo an accidental removal.

NameTypeReqDescription
idstringyes
reasonstringyes

Structured output declared, but exposes no named fields.

No examples provided.

memory_scope_disable ~63

Disable a scope for the rest of this session. Subsequent memory_search and memory_list calls will exclude memories tagged with this scope. Useful when the user says 'this is unrelated to project X'. Resets when the server restarts.

NameTypeReqDescription
scopestringyes

Structured output declared, but exposes no named fields.

No examples provided.

memory_scope_enable ~26

Re-enable a previously disabled scope for this session.

NameTypeReqDescription
scopestringyes

Structured output declared, but exposes no named fields.

No examples provided.

memory_scope_overview ~493

Cheap session-start hint: per-scope counts, no bodies / ids / summaries. Call once at the start of a conversation; if `total` is 0, skip memory_search for the rest of the session unless explicitly asked. `proposals_pending` is the count of write-reflex proposals the Stop hook has captured awaiting review via `memory_proposals` (0 unless the opt-in [proposals] auto_propose is on). `pending_writes` is this session's staged writes awaiting memory_write_confirm/cancel — a dangling confirmation (silent 1h expiry). `curation_pending` is an integer-count rollup the model should branch on; the response names its legs. `conflicts` = contradiction pairs awaiting a memory_conflicts verdict. `unaccounted` = memories that entered outside every recorded path. `curation_unmeasured` names legs whose 0 is not a measurement (git or the index did not answer); never read a listed leg's 0 as clean. Non-zero `dead` or `drifted` is a cue to suggest a curation pass when there is time; non-zero `silent_misses` / `cold_endorsement_memories` is actionable audit backlog. A memory retrieved many times with zero explicit applies is weakly endorsed — worth a look, not a verdict. Non-zero `recently_removed_in_worktree` is a 'where did X go?' signal — material was deliberately trimmed here recently; don't blindly re-suggest it. `curation_pending_new_since_last_session` is the same shape, filtered to events emitted and memories *created* since the previous session ended (not memories that aged into a bucket; an older record aging into `stale` between sessions stays visible only in the absolute `curation_pending` view — note this is distinct from the separate `drifted` bucket, which tracks working-tree drift). Branch on it when deciding whether to *prompt* about curation — non-zero means new rot since the last session, vs. the absolute view which persists until resolved. `null` on the very first session — fall back to `curation_pending`. Default-scoped to the caller's current repository; memorie…

NameTypeReqDescription
auto_scopeboolean

Structured output declared, but exposes no named fields.

No examples provided.

memory_search ~897

Search stored memories. Default: do NOT call — reach for it only when the user references shared context you lack ("my project", "the script we wrote") or a request is ambiguous in a way stored preferences could resolve. When a hit shapes your reply, announce it ("Using your stored preference for…") — non-negotiable. (Full policy: the server `instructions` block.) Returns ranked hits with snippets. Per-hit fields the model should branch on: - `relevance` (high/medium/low) — how much of your query wording the hit literally contains, not how good it is. Weak hits: re-query with different nouns. - `staleness_verdict` (fresh / spot_check_recommended / spot_check_required) — rolled-up signal; != fresh, act on `path_drift` below. - `match_terms` — which query words actually hit. - `path_drift_missing` (int) + `path_drift` ({checked, missing, verified} when drift detected) — body-cited paths gone. `claim_anchored_missing` (added when non-empty) is the escalating subset: memory_update those, memory_verify the rest. Prose-scraped `missing` rides `fresh` — evidence, not a tier. - `commit_drift_count` (int, when applicable) — commits since last_verified_at on the memory's origin repo. Non-zero means the project moved even if calendar-fresh. - `depends_on_resolved` (when present) — bounded auto-pull of `depends_on` link targets (max 3 per hit, max 10 per call). Each entry: `{id, scopes, summary, link_note}`. Surfaces context the query wouldn't on its own; saves a memory_show round-trip. OMITTED when the hit has no `depends_on` links. - `recent_negative_outcomes` (when present) — list of recent ignored/contradicted events for this memory (max two, one per outcome). The user already rejected this; don't re-surface unless you have new reason. OMITTED when none. Parameters: - `query`: nouns a memory would contain (tool, file, error names) — vocabulary is the lever, not question phrasing. Weak hits: re-query, different nouns. - `scopes` (optional): filter to scope union. - `clien…

NameTypeReqDescription
auto_scopeboolean
client
expand_topboolean
max_results
mode
model
querystringyes
scopes
since_prior_sessionboolean
NameTypeReqDescription
resultarrayyes

No examples provided.

memory_show ~220

Fetch a single memory's full content by id. Typically used after a memory_search snippet looks relevant. The response carries the same staleness signals as a search hit: - `verification.status` ('never' / 'stale' / 'fresh') with an actionable `recommendation` when not fresh. - `staleness_verdict` (fresh / spot_check_recommended / spot_check_required) — rolled-up signal across calendar, path and commit drift. - `path_drift` (the full report; missing-on-disk paths listed). - `commit_drift` (when caller is inside the memory's origin repo) — `status: 'clean' | 'drift'` + `commits_since_verify`. - Forward `links` and `reverse_links` for navigation. When the verdict isn't fresh, spot-check one claim before relying. memory_verify(id, …) if it holds; memory_update if drifted (content updates reset last_verified_at, so verify again after the fix).

NameTypeReqDescription
idstringyes

Structured output declared, but exposes no named fields.

No examples provided.

memory_update ~481

Body edits clear `last_verified_at`; scope-only edits preserve it. Bundling a scope rename with a body edit clears verification. Refine an existing memory in place. Preferred over memory_remove + memory_write when correcting a stored fact — preserves `id`, `created`, and `source`; bumps `updated`. Parameters (pass at least one): - `id`: required. - `content`: new body. Replacing the body clears `last_verified_at`, the verified-* attestations, and `claims` (the prior verification was for prose that no longer exists; call memory_verify again after, re-declaring claims). A body that reads as a claim ABOUT THE USER returns `user_claim_warning` unless the record is already `user-inference`; pass `acknowledge_user_claim=True` if the subject is someone else. A transient-state body returns `transient_warning`; `acknowledge_transient=True` overrides. An edit that SHRINKS the body and leaves it ending mid-sentence returns `truncation_warning`; pass `acknowledge_truncation=True` when the cut is deliberate. - `scopes` / `links`: REPLACE semantics — pass the full new list, or `[]` to clear. - `confidence`: low / medium / high. - `category`: accepts `fact` and `ambient`. `user-inference` is REJECTED here — that category exists to gate WRITES through the pending-confirm flow; updates have no equivalent gate. Returns `status="stale"` when another agent updated the memory first; the `hint` says to re-fetch and retry. Each `links` entry is `{type, target_id (a ULID), note?}`. The types: `supersedes` (prefer this over the target), `contradicts` (both cannot be true), `extends` (adds nuance to it), `depends_on` (only makes sense in its context). docs/api.md carries the rest.

NameTypeReqDescription
acknowledge_credentialboolean
acknowledge_transientboolean
acknowledge_truncationboolean
acknowledge_user_claimboolean
category
confidence
content
idstringyes
links
scopes

Structured output declared, but exposes no named fields.

No examples provided.

memory_verify ~543

Bump `last_verified_at` to now after spot-checking that a memory's claims still match reality (file paths exist, version still matches, configuration still what it says). Orthogonal to content edits: this tool does NOT bump `updated`; memory_update does NOT bump `last_verified_at`. A typo fix bumps `updated` only; a verify call bumps `last_verified_at` only. Idempotent — calling twice slides the timestamp forward. Parameters: - `id`: memory id. - `note` (optional, ≤800 chars): what was checked, for the event log. - `verified_paths` (optional list of strings): the ONLY attestation the drift legs read — checked against the memory's own worktree, and the anchor narrowing commit drift. Prefer it when the memory cites paths. Paths absent here are REFUSED. Stored entries re-check when `None` preserves them — a vanished one blocks the stamp; pass a corrected list. - `verified_commits` / `verified_versions` (optional lists): audit trail only; nothing on the read path resolves them. - `verified_absent_paths` (optional): attest paths INTENTIONALLY absent here (remote host, other platform, not-the-location) — reported under `expected_absent`, not `missing`. Never for real drift. - `claims` (optional): memory_write's claim syntax; checked NOW, false ⇒ refused. Stored claims re-check on every verify — a false one blocks the stamp; memory_update first. All five lists are REPLACE, not append — `None` preserves the prior attestation, `[]` clears it, a populated list supersedes it. Attest the full set each time. A verify attesting nothing on a memory whose cited paths resolve is refused; the error lists them as the paths to attest. The stamp records the origin checkout's HEAD as `verified_head`; commit drift then counts the commits reachable since it (`basis: reachability`), which sees a branch merged after the stamp. After memory_update on a memory you later spot-check, verify again — memory_update clears `last_verified_at` because the prior verification was for prose that no…

NameTypeReqDescription
claims
idstringyes
note
verified_absent_paths
verified_commits
verified_paths
verified_versions

Structured output declared, but exposes no named fields.

No examples provided.

memory_write ~855

Create a new memory. Call PROACTIVELY when something durable enters the conversation — aggressive writing is safe; the gates below catch bad writes. Parameters: - `content`: the memory body. - `scopes`: non-empty list. Avoid the catch-all 'general'; prefer narrow tags like `tools`, `infrastructure`, `projects:<name>`. - `category` (default 'fact'): one of `fact`, `user-inference`, `ambient`. - `fact`: project / infra / reference / tooling. Commits immediately (unless `require_write_confirmation`). - `user-inference`: claims ABOUT THE USER. Always returns {status:'pending', pending_id} regardless of config — ask the user in plain language, then memory_write_confirm or memory_write_cancel. Misattribution sticks; user gets the veto. - `ambient`: context that shapes replies without being cited. Commits like fact, excluded from dead-weight curation; a body over 500 words gets a non-blocking `ambient_body_long` warning. - `confidence` ('low' / 'medium' / 'high'), `source` ('explicit-statement' / 'inferred'). - `claims` (optional): claims the body makes about this repo — `path`, `path::symbol`, `path::NAME=literal`, `!path` (absent). Checked against the worktree NOW (false ⇒ refused); drift watches the claimed bindings, not whole files. Declare when citing code. - `groundedness_check=True` + `source_transcript`: optional gate. Sentences with <30% token overlap to the transcript return {status:'ungrounded', claims:[…]}. Override via `acknowledge_ungrounded=True` when grounding came from outside the transcript (file reads, tool results). - `supersedes` (optional): ids of active memories this write replaces (each gets a `supersedes` link, `superseded_by` on the stale hit). Also set unasked when a claim-sized body updates a stored claim — a change cue plus a diverging value; with no cue the pair is filed for memory_conflicts. Return statuses: - `committed` — write succeeded; payload carries the new id, `related` matches, and any `supersedes` / `conflicts_filed` rows.…

NameTypeReqDescription
acknowledge_credentialboolean
acknowledge_scope_mismatchboolean
acknowledge_transientboolean
acknowledge_ungroundedboolean
acknowledge_user_claimboolean
categorystring
claims
confidencestring
contentstringyes
forceboolean
groundedness_checkboolean
scopesarrayyes
sourcestring
source_transcript
supersedes

Structured output declared, but exposes no named fields.

No examples provided.

memory_write_cancel ~62

Drop a pending memory_write without committing. Pass the pending_id from the original write response. Pending writes expire after 1 hour; if the TTL elapsed (or the id never existed) the call returns `existed=False`.

NameTypeReqDescription
pending_idstringyes

Structured output declared, but exposes no named fields.

No examples provided.

memory_write_confirm ~128

Commit a memory_write that returned status='pending'. Pass the pending_id from that response. Pending writes expire after 1 hour; the confirm call will tell you which case fired (expired vs. never-existed). Re-gated at commit: `duplicate` / `previously_removed` / `credential_warning` can return instead of `committed` when the store changed during the wait. The staged write survives (`pending_retained: true`, same pending_id) — memory_write_cancel or resolve the match. The original write's overrides carry over.

NameTypeReqDescription
pending_idstringyes

Structured output declared, but exposes no named fields.

No examples provided.

Common questions

What is the io.github.0Mattias/bettermemory MCP server?

io.github.0Mattias/bettermemory is an MCP server listed in the public MCP registry as io.github.0Mattias/bettermemory. Memory for coding agents, checked against the filesystem and git before it is believed. This page covers its PyPI package (bettermemory).

Is the io.github.0Mattias/bettermemory MCP server safe to use?

io.github.0Mattias/bettermemory scores 77 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 20 September 2026. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

What tools does the io.github.0Mattias/bettermemory MCP server expose?

io.github.0Mattias/bettermemory exposes 18 tools: memory_search, memory_show, memory_list, memory_scope_overview, memory_write, and 13 more. Their descriptions and schemas cost roughly 6,540 tokens of context every time the server is loaded.

Is the io.github.0Mattias/bettermemory MCP server still maintained?

io.github.0Mattias/bettermemory is still listed as active in the MCP registry. We last reached this channel on 20 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

What licence is the io.github.0Mattias/bettermemory MCP server under?

io.github.0Mattias/bettermemory declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.