Project Memory Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Project Memory Mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A small, local MCP server that gives AI agents (Claude Code, Cursor, VS Code / GitHub Copilot, …) a shared, persistent memory of the projects in a code folder — what each project is, decisions made, and every bug/issue faced during development.
It is stateless: every tool reads/writes plain files on disk, so multiple clients (and multiple machines) share one source of truth.
| Layer | Lives in | Auto-loaded into context? | For |
|---|---|---|---|
| Project memory | <project>/AGENTS.md | ✅ yes (via CLAUDE.md → @AGENTS.md) | identity, stack, run cmds, concise decisions/learnings — keep lean |
| Issue log | <project>/issues.jsonl | ❌ no | high-volume bug/issue history — fetched on demand |
Design rule: durable, low-volume facts go in AGENTS.md (auto-loaded). High-volume history (bugs) goes in issues.jsonl (queried via search_issues). This keeps the always-loaded context small while keeping everything searchable.
Some orgs disable third-party MCP servers via policy (e.g. GitHub Copilot's MCP allowlist enforcement). Because the memory is plain files, not a service, the core value survives that:
AGENTS.md is auto-loaded by the editor reading it —no MCP call involved — so a project's identity, decisions, learnings, and preferences still land in the agent's context.
Claude Code or Cursor, and orgs running allowlist / registry-only mode can permit it — this server is published to the official MCP Registry (io.github.kaaustubh/project-memory-mcp).
Only the interactive tools (log_issue, search_issues, …) go over the MCP channel; the file-based memory keeps working without it.
list_projects, get_project, search_memory — read project memoryappend_decision, append_learning — append a dated bullet to AGENTS.mdremember_preference — turn a correction / stated habit into a remembered pattern (## Preferences in the root AGENTS.md for a global habit, or a project's for a local one); rides the auto-load, so it comes back next sessionlog_issue — record a bug/problem → issues.jsonlsearch_issues — "have we hit this before?" across all projects (field-scoped; optional tags filter)list_open_issues, resolve_issue — track / close bugssync_registry — reconcile the root AGENTS.md projects table with what's on disk (adds rows for new projects, flags stale ones)find_by_file — given a file path, surface the issues + decisions/learnings that touch it ("why is this code like this?")start_initiative, get_initiative, list_initiatives, update_initiative — track a named, multi-session effort (a codename, a plan, an evolving todo list) so it's resumable from any future session by name, not just within the one that started it; see Initiatives belowcheck_in, check_out — stamp the start/end of the working day and record a standup summary composed from evidence harvested off disk (git commits across every repo, uncommitted WIP, memory writes, initiative progress); the next morning's check_in hands the summary back — that's your standup. Print it any time, no agent needed: npx -y @kaaustubh/project-memory-mcp standupYou don't call these directly — you talk to your agent in natural language and it picks the tool. See Using it day to day below for what to actually say.
Most of it runs itself: opening a project auto-loads its AGENTS.md (the agent already knows the project), and capture is proactive (plus the optional Stop hook). Your job is mainly to pull memory at the right moments. Just talk to your agent:
| When | Say something like | What fires |
|---|---|---|
| Before debugging anything | "Have we hit this before? `<paste error>`" | search_issues across all projects |
| Starting something you've done elsewhere | "How did I do Stripe webhook verification in any project?" | search_memory (cross-project) |
| Landing on confusing code | "Why is `index.js` like this? Check the memory." | find_by_file |
| You made a real decision / fixed a real bug | (nothing — it logs on its own and tells you) | append_decision / log_issue |
| You correct how the agent works | "No, always run the typecheck before committing — remember that." | remember_preference (global or per-project) |
| Triage | "What's still open across my projects?" | list_open_issues |
| A bug is fixed | "Resolve pulse_stripe-004 — fixed by …" | resolve_issue |
| Added a new project | "Sync the registry." | sync_registry |
The one habit that matters: make "have we hit this before?" reflexive before every debugging session. That's where a memory tool earns its keep; the rest the system handles.
Capture is confirming, not silent — when the agent logs something it tells you in one line. Correct it freely: "don't log that", or "actually, log this too."
Escape hatches: PROJECT_MEMORY_HOOK=off silences the Stop hook for one session; uninstall-hook removes it entirely.
From your code/projects folder, run:
cd ~/code # the folder that holds your projects
npx -y @kaaustubh/project-memory-mcp installThat registers the server, using the current directory as your projects root, with every client that has an MCP config location on this machine:
| Client | Config written |
|---|---|
| Claude Code | user scope, via claude mcp add |
| Cursor | ~/.cursor/mcp.json |
| VS Code / GitHub Copilot Chat | user-profile mcp.json (applies to every workspace) |
| GitHub Copilot CLI | ~/.copilot/mcp-config.json (or $COPILOT_HOME) |
| JetBrains Copilot plugin (IntelliJ, PyCharm, WebStorm, …) | ~/.config/github-copilot/intellij/mcp.json |
| Visual Studio (Windows) | %USERPROFILE%\.mcp.json — global, all solutions |
| Kimi Code CLI | ~/.kimi-code/mcp.json (or $KIMI_CODE_HOME) |
| Gemini CLI | ~/.gemini/settings.json |
| OpenAI Codex CLI | ~/.codex/config.toml (the only non-JSON client — merged as TOML) |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
Each write merges into the existing file (other MCP servers you've already configured are left alone) and is independently best-effort — a client that isn't installed on this machine is silently skipped, the rest still get registered. Restart whichever app(s) you use, then ask your agent "set up project memory for this folder" to scaffold AGENTS.md for each project.
Copilot surfaces (VS Code, CLI, JetBrains, Visual Studio): tools only run in Agent mode, and config changes need a restart to take effect.
No clone, no global install — the MCP config just runs npx, which fetches and runs the latest version on demand.Team memory (beta signup): want this memory shared across your team instead of just your machine? Register your interest: https://github.com/kaaustubh/project-memory-mcp/issues/1
git clone https://github.com/kaaustubh/project-memory-mcp.git ~/code/.memory-server
cd ~/code/.memory-server && ./install.shA common question: "once I install it, does it just start doing things?" Not quite — the server is passive. Here's the actual flow:
becomes available the next time you launch Claude Code / Cursor / VS Code.
AGENTS.md (via CLAUDE.md → @AGENTS.md) into the model's context for you. This is why the agent "just knows" what your project is — it's a built-in editor feature.
waits. It does nothing on its own. The agent calls a tool only when it's relevant — e.g. you say "log this bug" or "have we hit this before?", or the model decides a tool is useful. There's no background process or scanning.
Day one is empty. A fresh setup has noAGENTS.mdfiles yet, so the auto-load has nothing to load andlog_issuewill refuse until a project's memory exists. Bootstrap once by asking your agent: "set up project memory for this folder" — it creates theAGENTS.mdfiles. After that, everything works.
In short: a convention (auto-loaded files) + a tool the agent chooses to use + a one-time setup. No magic, no daemon.
The server ships a standing capture policy (sent to the client on connect, plus directive tool descriptions), so the agent records things on its own instead of waiting for you to ask:
search_issues for a prior fix.log_issue.append_decision / append_learning.remember_preference, so the one-time correction becomes a pattern it brings back next session.It's proactive but not silent: the agent tells you in one line what it recorded, asks when unsure rather than logging noise, and skips trivia and secrets. You can always override — "log this", or "don't bother". The standing policy is best-effort (it depends on the model following it); for a hard guarantee, add the opt-in Stop hook below.
The standing policy can be forgotten mid-session. The Stop hook makes capture non-optional: when the agent tries to end a turn, it runs once and blocks the stop to ask for one capture pass when either (a) real work happened (file edits or a commit) and nothing was written to project memory, or (b) you corrected how it works and no preference was saved. If memory was already written, or nothing changed and you didn't correct it, the hook stays silent and lets the turn end.
npx -y @kaaustubh/project-memory-mcp install-hook # turn it on (then restart Claude Code)
npx -y @kaaustubh/project-memory-mcp uninstall-hook # turn it offinstall does not add it; you enable it explicitly.stop_hook_active), then letsthe agent stop.
PROJECT_MEMORY_HOOK=off to disable without uninstalling.nothing, or where you corrected the agent and no preference was saved; silent otherwise.
Capture is only half the loop — the other half is remembering to look. The recall hook closes it: every time you submit a prompt, it matches your request against your issue history and decisions/learnings/preferences, and silently injects the strongest hits as context. So a prior fix or decision surfaces without you (or the agent) remembering to search — the "have we hit this before?" habit becomes automatic.
npx -y @kaaustubh/project-memory-mcp install-recall # turn it on (then restart Claude Code)
npx -y @kaaustubh/project-memory-mcp uninstall-recall # turn it off(@xenova/transformers) is installed, recall matches by meaning, so "the build is broken" still surfaces an issue logged as "compile failure" even with no shared words. Runs fully offline (the model is fetched once, then cached). Without it, recall falls back to keyword matching automatically — no configuration, nothing breaks.
install addsneither hook.
PROJECT_MEMORY_RECALL=off to disable without uninstalling.Warm the cache: after a big logging session (or once, after enabling recall) runnpx -y @kaaustubh/project-memory-mcp reindexto pre-embed everything, so the first recall isn't the one that pays for it. Vectors are cached per project in a derived.embeddings.json(safe to delete / git-ignore — the.jsonl+AGENTS.mdstay the source of truth).
Pair it with the Stop hook and the loop runs itself: the Stop hook guarantees things get saved, the recall hook guarantees they come back at the right moment.
Decisions/Learnings capture finished facts, and issues.jsonl captures bug history — neither has a home for a named, in-flight, multi-session effort: "give this a codename, track the plan and todos, and let me resume it by name even in a session that's never seen it before." That's what start_initiative / get_initiative / list_initiatives / update_initiative are for.
you: "Let's call this HashGate. Track the plan and todos under that name."
→ start_initiative(project, codename: "HashGate", plan: "...", todos: [...])
(new session, days later)
you: "Where did we leave off on HashGate?"
→ get_initiative(project, codename: "hash gate") # case/spacing-insensitive match
you: "Continue where I left off" (no codename given)
→ list_initiatives(project) # or omit project to search everywhereEach initiative lives in its own file, <project>/initiatives/<slug>.md — a plan, a checkbox todo list, and a dated progress log, all editable in place. A one-line pointer to every active initiative is kept in sync under ## Active Initiatives in the project's AGENTS.md, so a brand-new session sees what's in flight in its auto-loaded context, with zero tool calls. Marking one done removes the pointer; the file itself stays as history, still reachable by name.
The tool and your memory content sync separately:
npx always pulls the published version (or git pullif you installed from source).
AGENTS.md + issues.jsonl live inside that project'sown git repo, so cloning your projects brings their memory along. Nothing to copy.
issues.jsonl holds real bug details — only commit it into private repos.For a new project under the root, create <project>/CLAUDE.md containing @AGENTS.md and a <project>/AGENTS.md with ## What this is, ## Stack & layout, ## Run / build / test, ## Decisions, ## Learnings sections.
package-lock.json — it still declared 1.8.3 while package.jsonhad moved through 1.9.0/1.10.0/1.11.0, because the release convention bumped the version in package.json + the McpServer({version}) string but never refreshed the lock. Not fatal to npm ci (verified on npm 10/11/12), but it's the same drift class that hard-broke CI in v1.8.3.
scripts/ is now in the files whitelist, so npm test works from an installedpackage. Previously the smoke test wasn't in the published tarball, so a container build spec doing npm install && npm test died with MODULE_NOT_FOUND — it only worked from a repo clone.
start script (node index.js), so a build/deploy spec whose CMD isnpm start no longer fails on a missing script.
image), use `npm ci --omit=optional`. A full npm ci pulls 276 MB of node_modules for a 36 KB server — almost all of it the optional embeddings chain (onnxruntime-node, onnxruntime-web, @xenova/transformers, sharp), which also downloads prebuilt binaries during install and dies on a disk/time-capped or network-restricted builder. --omit=optional gives 25 MB and all 18 tools still register; semantic recall simply falls back to keyword recall, as designed in v1.6.0. Recommended spec: Node 20 · npm ci --omit=optional · CMD node index.js.
"check in" at the start of your day and "checkout" at the end. Checkout harvests the day's EVIDENCE from disk — git commits across every repo under the root (with or without an AGENTS.md; .memory-server itself included), uncommitted WIP per repo, memory writes (issues/decisions/learnings/preferences) dated that day, and initiative files touched in the window — then the agent composes a 3–6 bullet standup summary strictly from that evidence and stores it (a two-pass tool protocol that works in any MCP client, since the day usually spans sessions the closing agent never saw). The next morning's check_in returns the LAST WORKING day's summary (Friday's, on a Monday) plus loose threads (active initiatives with open todos, open issues), and npx -y @kaaustubh/project-memory-mcp standup [YYYY-MM-DD] prints it straight to the terminal with no agent at all. Days live in ROOT/.worklog/YYYY-MM-DD.json — local-time stamps with offset, multiple check-in/checkout segments per day (lunch breaks), and a forgotten checkout is auto-closed and reconstructed from timestamps at the next check-in. Entries are pruned after WORKLOG_KEEP_DAYS (default 10): deliberately ephemeral, unlike the append-only memory files.
install now also registers Kimi Code CLI (~/.kimi-code/mcp.json, or$KIMI_CODE_HOME — not to be confused with the separate "Kimi CLI" product, which uses ~/.kimi/mcp.json), Gemini CLI (~/.gemini/settings.json), and Windsurf (~/.codeium/windsurf/mcp_config.json) — all three match the existing mcpServers/no- type schema registerMcp already handles for Cursor, so each was a one-line addition. OpenAI Codex CLI (~/.codex/config.toml) needed real work: it's the first non-JSON client, configured via TOML [mcp_servers.<name>] tables. Added registerMcpToml, a text-based find-the-table/replace-or-append merge (same spirit as appendBulletToFile's heading match) rather than a TOML parser dependency — keeps the zero-hard-dependency posture. Caught and fixed a real bug in it before shipping: the first version matched a table's body as "everything up to the next literal [," which truncates mid-table because args = [...] arrays use [ too — fixed to match "up to the next line that starts with [" instead, verified idempotent across repeated install runs against a pre-seeded config.toml with an unrelated table.
start_initiative, get_initiative,list_initiatives, update_initiative — track a named, multi-session effort (a codename, a plan, an evolving todo list) so it's resumable by name from ANY future session, not just the one that started it. Motivated by a real failure mode reported using another agent's session-local "codename" convention: no persistent registry mapping name → session, todos scoped to one session's private store, and discovery requiring an exact-string match across raw transcripts. Fixed here by storing one markdown file per initiative (<project>/initiatives/<slug>.md — mutable, so todo checkboxes toggle in place) plus a synced pointer under a new ## Active Initiatives heading in the project's auto-loaded AGENTS.md, so a brand-new session sees what's in flight with zero tool calls. Codename matching is case/spacing-insensitive (slugify splits camelCase boundaries first, so "HashGate" and "hash gate" resolve to the same initiative). list_initiatives searches across all projects when none is given, so "what was I working on?" doesn't require remembering which repo it was in either.
.github/workflows/ci.yml, Node 18/20/22 matrix)backed by a new stdio smoke test (scripts/smoke-test.mjs — spawns the server, does the initialize → tools/list handshake, asserts all 12 tools register), plus a CodeQL workflow. Both were previously entirely absent, which is why Glama's quality page showed "CI status not available" and "No code scanning findings" — those weren't clean bills of health, they meant "never measured."
package-lock.json — it predated @xenova/transformers ever beingresolved with optional deps included, so npm ci failed on a clean CI runner. Also ran npm audit fix (non-breaking), which cleared the @modelcontextprotocol/sdk-transitive hono/body-parser/fast-uri advisories. Known issue: @xenova/transformers (optional, powers semantic recall) still pulls in a critical + 4 high severity CVEs via its onnxruntime-web/protobufjs/sharp chain; the only fix is a breaking downgrade to 1.4.2, deliberately not done yet — tracked as a follow-up.
glama.json (declares maintainers) to fix Glama's "No glama.json"profile-completion check. Paired with cutting an actual GitHub Release for this version (previously we only pushed git tags, which Glama's "Has a release" check doesn't see — it reads the Releases API, not tags).
awesome-mcp-servers's listing requirement. Uses /badges/score.svg (a real SVG), not the plain /badge path — the latter 200s but serves a 0-byte image/png, i.e. broken.
install now also registers GitHub Copilot CLI (~/.copilot/mcp-config.json,or $COPILOT_HOME), the JetBrains Copilot plugin (IntelliJ/PyCharm/WebStorm/…), and Visual Studio on Windows (global .mcp.json) — rounding out every Copilot surface alongside the VS Code registration added in 1.7.0. Each target merges into its existing config (other servers are preserved) and is independently best-effort, so a client that isn't installed is silently skipped rather than failing the whole install. Schemas differ per client (mcpServers vs servers top-level key; type: "local" for the Copilot CLI vs type: "stdio" for the IDE-embedded ones) — verified against each client's current docs before implementing. The merge logic for all five targets was consolidated into one registerMcp() helper.
install now also registers the server with VS Code / GitHub Copilot(user-profile mcp.json, so it applies to every workspace), alongside the existing Claude Code and Cursor registration. Schema differs from Claude/Cursor (servers key, type: "stdio" per entry) and Copilot tools only run in Chat's Agent mode.
installsubcommand's console output) — https://github.com/kaaustubh/project-memory-mcp/issues/1
(AGENTS.md auto-load) keeps working even where an org disables third-party MCP servers (e.g. GitHub Copilot's MCP allowlist), since only the interactive tools use the MCP channel.
against memory by meaning, not shared substrings — "the build is broken" surfaces an issue logged as "compile failure". Powered by a local, offline embedding model (Xenova/all-MiniLM-L6-v2 via the optional @xenova/transformers dependency); vectors are cached per project in a derived .embeddings.json, keyed by content hash so edited/removed items self-invalidate. If the model isn't installed it falls back to the previous keyword matching automatically — nothing to configure, nothing breaks. New reindex subcommand pre-embeds all memory so the first recall isn't slow. This completes the long-deferred "semantic retrieval" lever behind both recall and search_issues; keyword remains the zero-dependency floor.
install-recall / uninstall-recallsubcommands register a hook that keyword-matches every prompt against your issue history and decisions/learnings/preferences and silently injects the strongest hits as context — so prior fixes and decisions surface without anyone remembering to search. Closes the other half of the capture↔recall loop. Silent on trivial/no-match prompts (generic filler words ignored), current-project hits ranked highest, at most 4 lines injected. Off by default; per-session kill switch PROJECT_MEMORY_RECALL=off.
mcpName field (io.github.kaaustubh/project-memory-mcp) required to listthe server in the official MCP Registry. No functional change.
dated bullet under ## Preferences, either in the root AGENTS.md (scope global — applies to every project) or a single project's. Because preferences live in the auto-loaded AGENTS.md, recall is free: a one-time correction ("never add a co-author trailer", "always typecheck before committing") comes back next session and is applied instead of re-corrected. Closes the cross-session loop for how you like to work, not just project facts.
remember_preference after a correction, and the opt-in Stop hook scans the session for behavioural-correction phrases ("from now on…", "no, don't…", "always use…"): if you corrected the agent and no preference was saved, it blocks the stop once to ask — a second, independent reason alongside the existing "code changed but nothing logged" check.
each tool, the one habit that matters ("have we hit this before?"), and the escape hatches. Clarifies that you talk to the agent rather than calling tools directly.
mcp__project-memory__* tool calls, so editing AGENTS.md / issues.jsonl directly (an endorsed capture path) still triggered the nag. It now also treats an Edit/Write to a file ending in AGENTS.md or issues.jsonl as captured — eliminating the false positive.
whole-line (^## Learnings$), so a heading with trailing text (## Learnings (gotchas …)) wasn't found and a duplicate section got appended. Now matches the heading's leading word.
install-hook / uninstall-hooksubcommands register a Claude Code Stop hook that forces a single capture pass when a session changed code but recorded nothing to memory — turning the best-effort policy into a hard guarantee. Off by default, fires at most once per turn (no loops), silent when nothing changed or memory was already written, and disablable per-session via PROJECT_MEMORY_HOOK=off.
search_issues now matches only the text fields(symptom/cause/fix/id/tags) instead of the raw JSON, so queries no longer get false hits on field names. Added an optional tags filter; query is now optional (search by tags alone).
AGENTS.md projects table with the projects ondisk — adds stub rows for projects missing from the table, flags rows whose directory is gone, and reports live open-issue counts. Automates the previously manual "new project → add a row" step. Hand-curated columns are preserved; apply=false reports drift only.
filesfield) and the decisions/learnings (via AGENTS.md bullets that mention it) touching that file — code↔memory linking for "why is this code the way it is?".
"log this": a standing capture policy is sent on initialize and the write/search tool descriptions are directive. It stays confirming (tells you what it logged), asks when unsure, and skips trivia/secrets. Explicit calls still work as an override.
npx … install failing with "command not found" — the bin is renamed toproject-memory-mcp to match the unscoped package name (npx resolution rule).
AGENTS.md + issues.jsonl, 9 tools(project memory + issue tracking), npx … install for Claude Code and Cursor, and the push/pull memory model.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.