Skip to main content
Glama

ai-memory-mcp

English | 繁體中文

Local, Markdown-first shared memory for AI coding agents, served over MCP.

Every session of every tool (Claude Code, Codex CLI, Copilot CLI, ...) starts with amnesia. This gives them one shared place to record decisions, dead ends and handoffs, and to look them up next time, so you stop re-explaining your project.

Status: feature-complete, provided as-is. This is a small tool I use myself. I do not offer support and I am not taking feature requests. Bug reports may go unanswered. Fork it freely (MIT).

Why this one

  • Plain Markdown is the source of truth. One .md file per memory: readable, greppable, diffable, committable.

  • The index is disposable. SQLite only accelerates search. Delete index.db and it is rebuilt from your notes.

  • Local and private. No cloud, no account. Optional semantic search uses a local Ollama model.

  • Any language. Substring search works for Chinese/Japanese/Korean text, not just space-separated words.

  • Auditable. Every read is logged (who, when, what query; never the results).

Related MCP server: mcp-chest-memory

Install

Requires Python 3.10+.

git clone https://github.com/bargisula/ai-memory-mcp.git
cd ai-memory-mcp
pipx install .          # or: pip install .
ai-memory doctor        # checks your setup

Then register the server with your MCP client. The command is ai-memory-mcp (stdio transport):

# Claude Code
claude mcp add -s user ai-memory -- ai-memory-mcp

# Codex CLI
codex mcp add ai-memory -- ai-memory-mcp

Any client that takes a JSON config (for example ~/.copilot/mcp-config.json):

{ "mcpServers": { "ai-memory": { "command": "ai-memory-mcp" } } }

If you use uv, you can skip the install and point the client at uvx --from git+https://github.com/bargisula/ai-memory-mcp ai-memory-mcp instead.

The server ships usage instructions to the client automatically (check the handoff first, record decisions and failures as you go), so no extra prompt file is required.

Tools

Tool

What it does

record_memory(project, type, title, content, llm, tags)

Save a note. type is decision, progress, failure or handoff.

search_memory(query, project, type, limit)

Substring search; every word must match. Returns short snippets.

search_memory_semantic(query, project, limit)

Meaning-based search (needs Ollama, see below).

read_memory(path)

Full text of one note.

get_handoff(project, limit)

Newest handoff notes with full text. Call first when resuming work.

recent(project, limit)

Latest notes of any type.

list_projects()

Projects that have notes.

audit_usage(tool, llm, project, limit)

Read audit log.

Pass your own name in llm (for example "Claude") so entries and reads can be attributed.

Where your data lives

Default: ~/.ai-memory/ (override with AI_MEMORY_HOME).

~/.ai-memory/
  notes/<project>/2026-01-05-choose-database.md   <- the truth. Back this up / put it in git.
  index.db                                        <- disposable search index + audit log

A note looks like this, and you can write or edit them by hand:

---
project: my-app
type: decision
llm: Claude
tags: database
ts: 2026-01-05T10:20:00+08:00
---

# Use SQLite

Single file, zero setup. Rejected Postgres: no concurrent writers needed.

After hand edits, deletions or copying notes from another machine, run ai-memory reindex. (A missing index.db is rebuilt automatically the first time the server starts.)

Configuration

All optional, all environment variables:

Variable

Default

Meaning

AI_MEMORY_HOME

~/.ai-memory

Data directory

AI_MEMORY_TYPES

decision,progress,failure,handoff

Allowed note types, comma separated

AI_MEMORY_EMBEDDINGS

on

off disables semantic search entirely

AI_MEMORY_EMBED_URL

http://localhost:11434/api/embeddings

Ollama embeddings endpoint

AI_MEMORY_EMBED_MODEL

nomic-embed-text

Embedding model

AI_MEMORY_GUARD

on

off disables the write guard (see Security notes)

Semantic search (optional)

ollama pull nomic-embed-text
ai-memory reindex --embed     # embed notes written before Ollama was available

Without Ollama everything else works; search_memory_semantic simply reports that it is unavailable. Vectors are compared by brute force in Python, which is fine up to a few thousand notes.

Command line

ai-memory doctor                  check the installation
ai-memory reindex [--embed]       rebuild the index from notes/
ai-memory handoff <project>       print the newest handoff (see hook below)
ai-memory search "<words>"        keyword search, JSON output
ai-memory audit                   read audit log, JSON output
ai-memory web [--port N]          open the read-only audit page in your browser

Audit page

ai-memory web serves a small page at http://127.0.0.1:8765 showing who read what and when, with filters for caller, project, tool, status and query text. It is read-only, listens on 127.0.0.1 only, refuses requests whose Host header is not loopback (DNS-rebinding protection), and follows your browser language (English or 繁體中文).

Make handoffs load automatically (Claude Code)

Relying on the model to remember to call get_handoff is fragile. A SessionStart hook guarantees it. In .claude/settings.json of your project:

{
  "hooks": {
    "SessionStart": [
      { "hooks": [ { "type": "command", "command": "ai-memory handoff my-app" } ] }
    ]
  }
}

Security notes

  • Project names are restricted to letters, digits, _, -, .; anything path-like is rejected, so a prompt-injected agent cannot write outside notes/. read_memory is likewise confined to notes/*.md.

  • Notes are plain text on disk. Do not store secrets in memories. A write guard enforces this: record_memory refuses (and writes nothing) when title, content or tags contain a token or API key (Telegram, sk-, GitHub, AWS, Google, Slack, JWT, private-key blocks, password=...-style assignments), a Taiwan mobile number, a checksum-valid Taiwan national ID, or a Luhn-valid card number. The refusal names the category, never the matched text. Add your own rules, one regex per line, to <data dir>/guard-block.txt (# starts a comment); every LLM sharing the data directory is covered. Set AI_MEMORY_GUARD=off to disable.

  • The audit log stores tool, caller, project and the query text (first 500 characters), never result contents.

Limits (by design)

  • Single user, single machine. Concurrent writers are safe (files are created exclusively, SQLite runs in WAL mode), but there is no access control and no built-in sync. To sync, keep notes/ in a git repository.

  • No edit or delete tool. Edit or delete the Markdown file, then ai-memory reindex.

  • Search is substring matching, not fuzzy or ranked by meaning (use the semantic tool for that).

Coming from a private predecessor?

The note format is unchanged: copy your old notes/ folder into AI_MEMORY_HOME and start the server. The index builds itself.

Development

pip install -e ".[dev]"
pytest

License

MIT. See LICENSE.

Available Tools

8 tools
audit_usageB

Who read what and when (newest first). Search result contents are not logged.

Inputs: llm, tool, limit, project. Returns: result

get_handoffA

Newest handoff summaries for a project, with full content. Call this first when resuming work.

project: project name limit: max summaries (default 3, newest first) llm: your name, for the usage audit log

Inputs: project (required), llm, limit. Returns: result

list_projectsB

List every project that has at least one memory.

Inputs: llm. Returns: result

read_memoryA

Read one memory in full. path is the value returned by other tools, e.g. "my-app/2026-01-05-choose-db.md".

Inputs: path (required), llm.

recentA

Latest memories of any type, newest first.

project: restrict to one project; empty means all limit: max results (default 10) llm: your name, for the usage audit log

Inputs: llm, limit, project. Returns: result

record_memoryA

Save one memory: a decision, progress update, failure, or handoff summary.

project: project name; letters, digits, '_', '-', '.' only (e.g. "my-app") type: one of decision / progress / failure / handoff (configurable via AI_MEMORY_TYPES) title: one-line title content: the details; multi-paragraph Markdown is fine llm: who is writing this (e.g. "Claude", "Codex"); strongly recommended tags: comma-separated keywords, optional

Inputs: type (required), title (required), content (required), project (required), +2 more.

search_memoryA

Keyword search over titles, content and tags. Every space-separated word must appear. Works for any language, including Chinese/Japanese substrings. Not FTS syntax: quotes and operators are treated as plain text.

query: words to look for project: restrict to one project; empty searches all type: restrict to decision/progress/failure/handoff; empty searches all limit: max results (default 10, capped at 100) llm: your name, for the usage audit log

Inputs: query (required), llm, type, limit, +1 more. Returns: result

search_memory_semanticA

Meaning-based search using local Ollama embeddings; finds related notes that share no keywords. Requires Ollama running with the nomic-embed-text model (see README); otherwise returns an error and you should use search_memory instead.

query: a natural-language description project: restrict to one project; empty searches all limit: max results (default 5) llm: your name, for the usage audit log

Inputs: query (required), llm, limit, project. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.8/5.0

    Scored across 8 tools

    Disambiguation4/5

    The retrieval tools (search_memory, search_memory_semantic, get_handoff, recent) overlap in that they all return memories, but each has a clearly described purpose: keyword search, semantic search, handoff-specific retrieval, and recency-based listing. read_memory is distinct because it loads one exact memory by path. Some confusion is possible between the two search tools, but the descriptions draw a clear boundary.

    Naming Consistency4/5

    Most tools follow a verb_object pattern: record_memory, read_memory, search_memory, get_handoff, list_projects, audit_usage. search_memory_semantic adds a modifier and 'recent' breaks the pattern by being a bare adjective rather than verb_noun. Overall the convention is consistent enough to be predictable.

    Tool Count5/5

    Eight tools is well-scoped for a personal/agent memory server. Each tool covers a distinct aspect: writing, reading, searching, semantic search, handoff retrieval, recent activity, project listing, and audit. No tool feels redundant or bloated.

    Completeness4/5

    The server covers the core memory lifecycle well: recording, reading, searching, retrieving handoffs, and auditing usage. The main gaps are the lack of update/delete operations and no way to browse tags, though these may be intentional for an append-only memory store. Agents can complete typical workflows without hitting dead ends.

    Maintenance

    ActivitySlowing
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      Provides a persistent, local-first memory for coding agents over MCP, enabling automatic recall and recording of past work, failures, and decisions to reduce repetition and token usage.
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Provides persistent, local-first memory for coding agents with Markdown as the source of truth, exposed via CLI, loopback API, MCP, and Codex hooks for context retrieval and durable writes.
      MIT