Skip to main content
Glama

th-memory-mcp

npm version npm downloads License: MIT Node CI Version Sync Listed on mcpservers.org

th-memory-mcp MCP server

Status: v2.2.6 — a temporal, conflict-aware, hybrid-retrieval memory engine. 16 MCP tools, 25 passing test suites. Non-destructive schema migration from v1 (all v1 data preserved). New in v2.2: lifecycle states, temporal validity, conflict/dedup resolution with USER/SESSION/PROJECT/GLOBAL scope, hybrid FTS+vector retrieval (RRF), memory graph, get_context assembly, periodic consolidation, and link_memory / merge_memory / update_memory / import_memory / extract_memories. New in v2.2.3: scope-enforced retrieval, graph scope isolation, export/import round-trip, hardened import path (realpath), strict import validation, N+1 query elimination, cold/ablation benchmark, and MEMORY_RETRIEVAL_MODE switch.

Requirements

  • Node.js >= 20 — the server uses Node-only APIs (the better-sqlite3 native build and import.meta.url resolution) and the MCP SDK requires a modern runtime. CI tests on Node 20.x and 22.x.

  • npm — to install dependencies and run the build/test scripts (npm install, npm run build, npm test).

  • OpenCode — the host that loads this MCP server and the auto-capture plugin. Any build supporting MCP over stdio + plugins works; the plugin runs on OpenCode's bundled Bun runtime.

  • OS: Windows / macOS / Linux — the server is cross-platform (Node). The auto-capture plugin runs wherever OpenCode's Bun runtime runs. Windows note: MEMORY_DB_PATH is easiest to set with setx; on macOS/Linux use export in your shell profile.

No external services, accounts, or API keys are required — everything lives in a single local SQLite file.

Related MCP server: MCP Vector Memory

Quick Start

Fastest path: after cloning, run npm run quickstart — it builds, wires opencode.json, deploys the plugin, and sets MEMORY_DB_PATH for you in one command. The steps below show exactly what it does (use them if you prefer manual control).

Install via npm (alternative): install the server globally with npm install -g th-memory-mcp (or run it on demand with npx th-memory-mcp), then point the mcp command in opencode.json to th-memory-mcp instead of the built dist/index.js. The auto-capture plugin still comes from this repo (copy src/plugin/learning-capture.ts as described in step 4 below).

# 1. Clone and build
git clone https://github.com/worakorn-prince/th-memory-mcp.git
cd th-memory-mcp
npm install
npm run build

# 2. Share one DB between the server and the plugin
#    Windows (PowerShell):
setx MEMORY_DB_PATH "$PWD/data/memory.db"
#    macOS / Linux (add to your shell profile, e.g. ~/.zshrc):
# export MEMORY_DB_PATH="$PWD/data/memory.db"
  1. Merge this into your ~/.config/opencode/opencode.json (replace <REPO> with the absolute clone path):

{
  "instructions": ["<REPO>/AGENTS.memory.example.md"],
  "mcp": {
    "memory": {
      "type": "local",
      "command": ["node", "<REPO>/dist/index.js"],
      "enabled": true,
      "environment": { "MEMORY_DB_PATH": "<REPO>/data/memory.db" }
    }
  }
}
  1. (Optional) Auto-capture: copy src/plugin/learning-capture.ts~/.config/opencode/plugins/

  2. Restart OpenCode

  3. Try it: "Remember that I prefer pnpm" → new session → "What package manager do I prefer?"

Architecture

OpenCode ──┬─ Plugin learning-capture (Bun)  ── auto-captures prompts/tool/error into DB
            │                                   └─ injects profile back into context on compaction
             └─ MCP th-memory-mcp (Node.js stdio)  ── 16 tools read/write the same SQLite DB
                                                      ▲
                               Global instructions (memory-protocol.md) teach the AI to use the tools

See ARCHITECTURE_v2.md for the full architecture spec.

Why th-memory-mcp?

LLMs don't remember you between sessions — every new chat starts blank. th-memory-mcp gives your AI a private, local long-term memory:

  • Context-based learning, not fine-tuning — it captures your preferences, corrections, and habits, then recalls them into context next time. Same mechanism as the memory features of leading AI products, without sending any data off your machine.

  • 100% local & private — a single SQLite file, no cloud, no external API. Secrets are filtered before anything is stored.

  • Low overhead — each tool call is capped (latency < 10 ms, bounded output size) and the AI only queries memory when it's actually useful, so it never bloats your context.

  • Resilient — every tool degrades gracefully; if the DB is unavailable the AI keeps working instead of crashing.

  • Open & extensible — MIT licensed, 16 documented tools, a rule-based distill, and an auto-capture plugin you can adapt.

Works with other harnesses

th-memory-mcp is a standard MCP server, so the 9 tools run anywhere MCP-over-stdio is supported. Full auto-capture (background prompt/tool/error capture + profile injection) needs a hook runtime — OpenCode has it built in; Claude Code gets it via our hooks bridge; Codex and Cursor use the tools manually (no hook runtime yet).

Feature

OpenCode

Claude Code

Qwen Code

Codex

Cursor

16 MCP tools

Auto-capture (background)

✅ plugin

hooks

⚠️ adapter

❌ manual

❌ Rules

Profile injection

✅ compaction

✅ UserPromptSubmit

get_profile

get_profile

get_profile

Lexical fuzzy matching

✅ (v2.0)

✅ (v2.0)

✅ (v2.0)

✅ (v2.0)

✅ (v2.0)

  • Claude Code: see CLAUDE_CODE_HOOKS.md — drop-in hooks replicate the OpenCode plugin (capture + profile injection on UserPromptSubmit/PreCompact, rule-based distill on SessionEnd).

  • Qwen Code: see QWEN_SETUP.md — MCP works fully; hooks use the Gemini-CLI schema so auto-capture needs a small adapter.

  • Codex: see CODEX_SETUP.md

  • Cursor: see CURSOR_SETUP.md

All harnesses share one SQLite file via MEMORY_DB_PATH, so memory captured anywhere is readable everywhere.

Highlights

  • Structured memory — preferences with confidence scoring plus dedicated lesson records (situation → mistake → correction) for capturing corrections, not just flat facts.

  • Lifecycle & temporal — every memory has a lifecycle state (active/stale/superseded/archived), confidence/importance/salience scoring, per-type decay, and validity intervals so the AI can reason about point-in-time truth and supersession chains.

  • Conflict-aware — duplicate detection, contradiction detection, and update/supersession resolution preserve both sides of ambiguous evidence instead of silently overwriting.

  • Hybrid retrievalget_context blends FTS5 keyword search with a dependency-free lexical fuzzy matching (hashed n-gram similarity, 512-dim FNV-1a) (RRF fusion + scoring), then assembles a token-budgeted context with optional memory-graph expansion.

  • Consolidation — periodic clustering of similar memories into derived memories with full provenance (derived_from links).

  • First-class Thai / i18n — Thai-aware tokenization in distill; the AI accepts Thai and English interchangeably.

  • Private by default — a single local SQLite file, no cloud, no API keys, with secret lines (api_key=, password:, token) filtered before storage.

  • Cross-harness — runs on OpenCode, Claude Code, Codex, and Cursor sharing one DB; auto-capture + profile injection via OpenCode plugin or Claude hooks.

  • Lightweight & resilient — Node + better-sqlite3, no extra native extensions; every tool degrades gracefully so the AI keeps working if the DB is unavailable.

Scripts

Command

Description

npm run build

compile TypeScript → dist/

npm start

run the MCP server (stdio) from dist/index.js

npm run distill

rule-based distill: interactions → profile sections + prune old data (env RETENTION_DAYS default 30)

npm test

full suite: capture, distill, lifecycle, temporal, conflict, retrieval, graph, context, consolidation, benchmark, security, tools_v21, smoke, e2e_transport, retrieval_benchmark, recall_regression, scope, profile, entity_extraction, conflict_benchmark, security_regression, export_import_roundtrip

node test/capture.test.mjs

test capture-core (filter secrets, dedupe, truncate, insert SQL)

node test/distill.test.mjs

test distill-core (Thai tokenize, stats, profile sections, prune)

node test/lifecycle.test.mjs

test lifecycle engine (states, decay, supersession)

node test/temporal.test.mjs

test temporal model (validity, historical retrieval)

node test/conflict.test.mjs

test conflict & dedup resolution

node test/retrieval.test.mjs

test hybrid FTS+vector+RRF retrieval

node test/graph.test.mjs

test memory graph (entities, relations, traversal)

node test/context.test.mjs

test context assembly + token budgeting

node test/consolidation.test.mjs

test clustering + derived memories

node test/benchmark.test.mjs

latency benchmark over 300 memories

node test/security.test.mjs

injection / safety checks

node test/smoke.mjs

end-to-end smoke test over JSON-RPC (16 tools)

Tools (16)

Tool

Description

remember

upsert preference (category+key) — re-saving the same key increases confidence by 0.1 (cap 1.0)

recall

search preferences + lessons (FTS5) + recent matching interactions. Use before starting a new task

get_profile

user profile overview: profile sections + top preferences + 5 most recent lessons

save_lesson

record a lesson learned from a correction (situation / mistake / correction)

search_history

search past user prompts by keyword (200-char snippets per row)

forget

delete one memory row (preference/lesson/interaction) by id (+type prevents cross-table id clash)

memory_stats

memory statistics: counts by kind, DB size, oldest/newest interaction, profile sections

get_recent_interactions

list recent raw interactions (filter by kind) — feedstock for Smart Distill

export_memory

export memory to JSON under data/exports/ only (filename auto-sanitized)

get_context

assemble relevant memories for the current task via hybrid retrieval (+ optional graph expansion) with token budgeting

consolidate

cluster similar memories via embedding similarity; optionally create derived/consolidated memories linked via derived_from

link_memory

create a typed relationship between two memories in the graph (supports/contradicts/supersedes/derived_from/related_to/caused_by/depends_on)

merge_memory

merge a duplicate/near-duplicate into a canonical memory (source becomes superseded, provenance in metadata.merged_from)

update_memory

update mutable fields in place, or create a superseding memory when content changes (set supersede=false to edit in place)

import_memory

import memories from JSON (validates type, dedupes against existing, never overwrites blindly); dry-run by default, apply=true to insert

extract_memories

scan recent captured interactions for memory-intent phrases and propose memory candidates (deterministic, no LLM); dry-run by default, apply=true to create (source=captured)

Install with OpenCode

  1. Merge the mcp section from opencode.example.json into your opencode.json (global or project-level)

    • Important: set MEMORY_DB_PATH to the SAME database file for both the server and the plugin (the example uses <ABSOLUTE_PATH>/th-memory-mcp/data/memory.db), otherwise the auto-capture plugin writes to a different DB than the one the AI reads

    • How to set it (pick one):

      • define it in the mcp environment (see example) — covers the MCP server only

      • or set it as a system/user-level environment variable (e.g. setx MEMORY_DB_PATH "D:/path/to/memory.db" on Windows) — covers both server and plugin, since the plugin runs in the same process as OpenCode

  2. Attach the global memory rules — add to opencode.json:

    "instructions": ["C:/Users/<user>/.config/opencode/memory-protocol.md"]

    (example rule content is in AGENTS.memory.example.md — can be attached at project level instead)

  3. (Optional) Deploy the auto-capture plugin: copy src/plugin/learning-capture.ts~/.config/opencode/plugins/learning-capture.ts

  4. Restart OpenCode (config loads at startup only)

  5. Test: "Remember that I prefer pnpm" → open a new session and ask back

Daily usage

The AI accepts both Thai and English interchangeably — you can switch languages at any time without warning.

Example command

Tool / effect

"Remember that..."

remember — save a preference

"Summarize memory" / "distill memory"

Smart Distill — AI reads get_recent_interactions, finds patterns, and saves insights itself

"How is my memory?" / "memory status"

memory_stats

"Export memory" / "backup memory"

export_memory

"Search history..."

search_history

"Forget..."

forget

Long-term care: run npm run distill occasionally to summarize stats and prune interactions older than 30 days.

data/ structure

data/
├── memory.db          # SQLite (WAL mode) — main DB (+ .db-wal, .db-shm)
└── exports/           # JSON files from export_memory (writeable only in this dir)
  • DB path can be overridden via the MEMORY_DB_PATH env var

  • everything in data/ is git-ignored

Benchmark — internal self-reported (not third-party)

⚠️ Internal self-reported benchmark — not third-party benchmark

  • internal small-N: 180 records/30 topics (B.retrieval: 30 topics × 5 relevant + 30 distractors = 180; full run also uses small-N storage/temporal/context subsets)

  • single-machine self-run: single developer machine, single OS/Node/better-sqlite3 build — not cross-machine, not independently verified

  • not third-party benchmark: self-reported, not independently verified; do not compare as if from an external evaluator

  • Dataset and harness are in repro/ (commitable) and benchmark/ (full framework, see TH_MEMORY_MCP_BENCHMARK_SPEC.md and benchmark/README.md).

Two modes

Mode

Command

Data

Suites

Use case

Normal

npm run benchmark

180 records / 30 topics

retrieval

quick check (<5s)

Heavy

npm run benchmark:heavy

600 records / 100 topics + 2k scale

all (storage/retrieval/temporal/context/performance/scalability/cold/ablation)

stress / regression

Reproduce:

npm run build
# Normal — quick
npm run benchmark
npm run benchmark -- --k 10
npm run benchmark -- --out repro/results

# Heavy — full framework, more data
npm run benchmark:heavy
# or custom:
node benchmark/run.mjs --suite all --topics 100 --distractors 100 --scale 2000 --out benchmark/results

Viewer — compare last 3 versions (table + charts)

npm run benchmark:viewer
# or: npx serve . -l 3000
# open http://localhost:3000/benchmark/viewer/  or  http://localhost:3000/result/viewer.html

The viewer loads benchmark/results/history.jsonl, groups by version, takes the latest run of the 3 most recent versions (e.g. 2.2.2 / 2.2.3 / 2.2.4) and shows a highlighted table (1 row per version) + bar charts for Recall@5 / MRR / NDCG@5 and Latency p95. Results are also saved per version in result/v*_benchmark_result.md and benchmark/results/versions/<ver>/.

Last internal run (v2.2.4, warm, same dataset — not third-party): Recall@5=0.92, Precision@5=0.92, MRR=1.00, NDCG@5=0.94 over 30 topics/180 records. See result/v2.2.4_benchmark_result.md and repro/README.md for details and caveats (internal small-N, single-machine self-run).

Known Limitations

  • No encryption at rest (plaintext-at-rest)data/memory.db (WAL mode, better-sqlite3) is a plain, unencrypted SQLite file. 100% local & private means no cloud or network exfiltration — it does not mean encrypted at rest. Anyone with filesystem access (shared machine, backup, malware, stolen device) can read preferences/lessons/interactions in plaintext. For sensitive data, use OS-level full-disk encryption (BitLocker / FileVault / LUKS) or an opt-in SQLCipher build (requires native rebuild and key management). No SQLCipher/in-code encryption is applied by default and src/db/index.ts documents this explicitly.

License

MIT © 2026 worakorn-prince

This project is licensed under the MIT License — see the LICENSE file for the full text.

A
license - permissive license
A
quality
A
maintenance

Maintenance

Maintainers
Response time
0dRelease cycle
13Releases (12mo)
Commit activity

Related MCP Servers

  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    Provides persistent local memory functionality for AI assistants, enabling them to store, retrieve, and search contextual information across conversations with SQLite-based full-text search. All data stays private on your machine while dramatically improving context retention and personalized assistance.
    3
  • A
    license
    Not graded
    quality
    Not graded
    maintenance
    Provides AI coding agents with persistent, long-term memory through local semantic search and SQLite storage. It enables agents to save and retrieve architectural decisions or project context across different conversation sessions without requiring cloud services.
  • A
    license
    A
    quality
    B
    maintenance
    Provides persistent cross-session memory and full-text search for AI coding assistants, storing project context, decisions, and preferences while enabling searchable access to conversation history via local SQLite.
    8
    1
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Provides AI coding assistants with persistent memory storage using a local SQLite database. Enables tools to remember project details, notes, and relationships across sessions to maintain context and reduce repetitive explanations.
    17
    4
    MIT

View all related MCP servers

Related MCP Connectors

  • Persistent memory and cross-session learning for AI coding assistants (hosted remote MCP).

  • Persistent memory for AI agents. Search, store, and recall across sessions.

  • Persistent memory for AI agents — verbatim conversations, searchable by meaning.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/worakorn-prince/th-memory-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server