mcp-knowledge-graph: Persistent AI Memory as a Local JSONL Knowledge Graph
MCP server enabling persistent memory for Claude through a local knowledge graph - fork focused on local development
At a glance
- What is it?
- A fork of the MCP knowledge graph memory server that stores entities, relations and observations in local JSONL files, with project detection through a .aim directory and a file-level safety marker. The design favours plain files and explicit paths over a database, which makes it easy to inspect and easy to corrupt if you edit it by hand.
- Who is it for?
- Adopt it if you want Claude's memory to live in plain JSONL files you can read, diff and back up, and you are comfortable creating a .aim directory per project. Skip it if you need concurrent writers, a query language, or a hosted multi-user store.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 109 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem: Claude forgets everything between sessions
A chat session with Claude ends and the context goes with it. Anything you explained about your project, your colleagues, or your preferences has to be explained again next time. This server addresses that by exposing a set of memory tools over the Model Context Protocol, so the model can write facts into a store and read them back in a later conversation. The README frames the storage unit as a knowledge graph: entities with a name and an entityType, observations attached to those entities, and relations that link two entities together. That is a deliberately small data model. It is not a general graph database and it does not try to be. The intended user is someone running Claude Code or Claude Desktop locally who wants memory to persist on their own disk rather than in a vendor account. The fork's stated focus is local development, and the naming convention reflects the upstream concept: AIM stands for AI Memory, which is why directories are called .aim and tools carry an aim_ prefix.
How storage resolves: .aim directories, the master database and named contexts
The resolution order is explicit in the README. If you are inside a project that contains a .aim directory, memory operations use .aim/memory.jsonl. If there is no project or no .aim directory, they fall back to the configured global directory. When a context is supplied, the filename gains a suffix, so context work becomes memory-work.jsonl. The directory name is not configurable for project-local storage: the README states the directory MUST be named exactly .aim for project detection to work. Global storage is the opposite, and the --memory-path argument accepts any directory at all, including a Dropbox folder, which the README notes is how the author keeps his own memories. Layered on top is the concept of a master database, always named default in listings and always stored as memory.jsonl. Every operation hits the master database unless a context or location parameter says otherwise. The location parameter takes project or global and overrides auto-detection. So there are two independent axes: which database (master versus a named context) and where it lives (project versus global). Keeping those separate is the clearest part of the design, and the README's example calls show both in use.
The _aim marker is a write guard, not a format
The README spends unusual effort distinguishing .aim from _aim, and the distinction matters. The dot version is a directory name. The underscore version is a line written at the top of every memory file: {"type":"_aim","source":"mcp-knowledge-graph"}. Before writing, the system checks for that marker and refuses to write to a file that lacks it. The stated purpose is preventing accidental overwrite of unrelated JSONL files. This is a reasonable guard for a tool that appends to files chosen partly by convention, because JSONL is a common format and a stray path could otherwise clobber something else. It also has a consequence worth naming: if you create a memory file by hand, or restore one from a backup that stripped the first line, the server will decline to write to it. The README does not describe a repair command or a flag to bypass the check, so the fix in that situation is to restore the marker line yourself before the server will treat the file as its own. That is a small operational detail, but it is the kind of thing that turns into a confusing afternoon if you do not know it.
Getting it running: one JSON block and one mkdir
Installation is through npx, with no separate install step. The README gives two configuration shapes for claude_desktop_config.json or .claude.json. The first points --memory-path at a default .aim directory under your home folder. The second points it at a synced folder such as Dropbox for portability across machines. Both use the same command and differ only in the path argument. The server entry is named Aim-Memory-Bank in the examples, though nothing in the material suggests the name is load-bearing. For project-local memory the README gives a single shell command: mkdir .aim. Run from a project root, that is enough for subsequent memory operations to land in .aim/memory.jsonl instead of the global store. Named databases need no setup at all; the README states that new databases are created automatically when a context is first used. The tool surface is eleven functions: aim_memory_store, aim_memory_add_facts, aim_memory_link, aim_memory_search, aim_memory_get, aim_memory_read_all, aim_memory_list_stores, aim_memory_forget, aim_memory_remove_facts and aim_memory_unlink. Two parameters govern placement: context selects the named database and defaults to the master, while location forces project or global and defaults to auto-detection.
Where the file-based design runs out of road
JSONL append files are the whole storage layer here. That buys inspectability, since you can open memory.jsonl in any editor, and it buys portability, since a synced folder is a valid store. It also sets hard limits that the README does not paper over. Search is described as keyword search, not a query language, so retrieval quality depends on how the model phrased observations when it wrote them. There is no described locking, transaction, or conflict resolution mechanism. Two Claude instances writing to the same memory.jsonl at once, which is exactly what a Dropbox-synced store across two machines invites, has no documented answer in the material. Sync clients that resolve conflicts by producing duplicate or renamed files are not addressed either. The removal tools are similarly blunt: aim_memory_forget and aim_memory_remove_facts delete entries, and the README does not describe an undo, a tombstone, or a soft-delete. If the model stores a wrong fact and later forgets it, the history is gone unless you kept a copy. None of this makes the tool wrong. It makes it a small tool with small-tool boundaries, and anyone pointing it at a shared or synced location should treat those boundaries as real.
How it differs from a database-backed memory server
The obvious alternative class is an MCP memory server backed by SQLite or another embedded database, where the store is a single binary file and queries go through SQL. The difference is not performance, which this material does not measure. The difference is what you can do with the artifact. A SQLite memory store is opaque without a client, and merging two divergent copies means a real merge. The JSONL approach here means a memory file is a text file you can read, grep, hand-edit, and put in version control, and the README's cloud-sync guidance leans on exactly that property. The cost is that every guarantee a database would give you, atomic writes, concurrent access, indexed queries, is absent by construction. A second alternative is simply not using a memory server: keeping a notes file in the repository and pasting relevant context into the conversation. That is more manual but has no failure mode beyond your own discipline, and it never silently writes the wrong fact into a store the model later trusts. The honest comparison is between a small append-only text store with model-driven writes and either a heavier database or no store at all.
Maintenance, licence and what the release history suggests
The licence is MIT, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. That is a permissive arrangement, and it means a fork such as this one can exist and be redistributed without friction. Nothing here is legal advice; read the LICENSE file in the repository for the operative terms. On maintenance, the material shows three releases on 2025-12-22, v1.3.0 through v1.3.2, with the last push to the repository in May 2026. Three patch-level releases within roughly half an hour suggests a burst of small fixes rather than a long development arc, and the material does not include release notes explaining what changed. The default branch is main and the repository is not archived. Because installation runs through npx, an unpinned command pulls whatever version is current at launch, so a config that works today can change behaviour on the next run without any edit on your side. Pinning the version in the args array is the only lever the README's configuration shape gives you for that, and the material does not state which version is currently published.
Who should adopt this, and what to check first
This fits a single developer running Claude locally who wants memory to survive between sessions and wants to be able to look at it. The .aim convention makes the project-local case genuinely convenient: one mkdir and the store follows the repository. The failure modes are concentrated in shared and synced setups, where the absence of any documented concurrency handling is the thing most likely to bite. If you work across two machines on the same synced folder, the README offers no guidance on what happens when both write, and you should decide that question yourself before trusting the store. If you want typed queries, retention policies or multi-user access, this is the wrong tool and a database-backed server is the right shape. Two checks are worth doing before you commit: confirm the directory is spelled exactly .aim, since detection keys on that literal string, and confirm the first line of any file you want the server to write to is the _aim marker, because the write guard will reject it otherwise. Both are stated in the README and both are the kind of thing that is obvious only after it has failed once.
Editorial conclusion
Adopt it if you want Claude's memory to live in plain JSONL files you can read, diff and back up, and you are comfortable creating a .aim directory per project. Skip it if you need concurrent writers, a query language, or a hosted multi-user store. Before relying on it, verify two things from the README: that the directory is named exactly .aim, since detection depends on that string, and that your target file already carries the {"type":"_aim","source":"mcp-knowledge-graph"} first line, because the server refuses to write to files without it.
Community notes