The Problem

AI agents (LangGraph, CrewAI, AutoGen, Claude) lack persistent memory across runs. Each conversation starts from zero—no shared context, no accumulated decisions, no causal knowledge graph. Teams end up gluing together Redis, Pinecone, and custom code to give agents continuity.

What This Does

mcp-memory-service is a self-hosted memory backend for AI agent pipelines. It exposes a REST API, MCP transport, OAuth 2.0 auth, CLI, and a web dashboard. Agents store decisions, share causal knowledge graphs, and retrieve context in ~5ms. The service supports remote MCP for browser-based claude.ai integration.

The repo is a portfolio of 8 self-contained projects, not a single codebase. The substantial ones: src/ (Python core service), claude-hooks/ (Claude Desktop integration hooks), scripts/ (operational tooling), and video/ (demo content).

How It Is Wired

Execution starts in claude-hooks/core/auto-capture-hook.js at main (reaches 69 functions). The traced path: mainloadConfigfs.readFile — the hook reads config from the filesystem, then captures conversation transcripts via parseTranscript, extractTextContent, and storeMemory.

The Python server entry points are src/mcp_memory_service/server/__main__.py and src/mcp_memory_service/cli/main.py. main calls runTest 37 times, and runAllTests calls runTest 15 times — the test harness is a first-class citizen.

Highest-blast-radius modules:

  • src/mcp_memory_service/config.py — 42 modules import it; it's in an import cycle. Changing config ripples everywhere.
  • src/mcp_memory_service/models/memory.py — 41 importers, 0 imports. Pure data model, stable.
  • src/mcp_memory_service/web/app.py — imports 31 modules (instability 0.94); the web layer is a thin adapter over everything else.

Import cycles exist in config.py, storage/base.py, and storage/sqlite_vec.py. Breaking them requires extracting shared types or deferring imports. The cost: any change to these files risks circular-import failures at runtime.

File map:

  • src/mcp_memory_service/web/static/app.js — 204 functions; the dashboard frontend
  • claude-hooks/core/auto-capture-hook.js — 6 functions; captures Claude transcripts, writes files
  • claude-hooks/utilities/session-tracker.js — 20 functions; session lifecycle, generates secrets, writes files
  • claude-hooks/utilities/memory-client.js — 19 functions; connects via MCP or HTTP

The 21 filesystem-touching functions and 1 network call are the only external effects; the rest is internal computation.

How To Use It

Setup (from pyproject.toml):

pip install mcp-memory-service
# or
uv pip install mcp-memory-service

Run the server (from README):

MCP_STREAMABLE_HTTP_MODE=1 \
MCP_SSE_HOST=0.0.0.0 \
MCP_SSE_PORT=8765 \
MCP_OAUTH_ENABLED=true \
python -m mcp_memory_service.server

Configuration: copy .env.example to .env and set storage backend, OAuth credentials, and MCP mode. The service supports SQLite (with vector search) and other backends.

Real-World Use

A LangGraph pipeline where agents share memory:

from mcp_memory_service.client import MemoryClient

client = MemoryClient(base_url="http://localhost:8000")
client.store("user-preferences", {"theme": "dark", "timezone": "UTC"})
context = client.retrieve("user-preferences")
# Pass context into the next agent run

Code Health & Issues

Static analysis found 316 findings (69 high, 245 medium, 2 low) across 7 kinds:

  • High — Import cycle members (9): config.py, storage/base.py, storage/sqlite_vec.py. Circular imports can break at runtime.
  • High — Deep nesting (28): models/memory.py, storage/base.py, storage/sqlite_vec.py — max depth 6.
  • High — Oversized files (8): config.py at 782 lines; storage/sqlite_vec.py and storage/base.py similar. High change-ripple.
  • High — Hub modules (4): config.py (42 dependents), models/memory.py (41), storage/base.py (21). Churn here is wide-blast-radius.
  • Medium — Broad exception handling (9): bare except in storage/base.py, storage/sqlite_vec.py, __init__.py.
  • Medium — High branching density: claude-hooks/utilities/context-formatter.js — 371 branch points / 954 lines.
  • Medium — File without context manager: web/oauth/registration.pyopen() not wrapped in with.

SDLC observations from the file structure:

  • High — Unpinned GitHub Actions: .github/workflows uses @v4/@v6 tags, not commit SHAs. Tag-move attacks leak secrets.
  • High — Committed .env: archive/configs/.env.sqlite.backup is tracked. Rotate anything it holds.
  • High — continue-on-error on correctness gates: .github/workflows/docker-publish.yml line 141 — failing tests report green.
  • Medium — No dependency vulnerability scan in CI; npm install instead of npm ci; mutable base image python:3.12-slim; no permissions declaration; no non-root USER in Dockerfile.

The Bottom Line

The core service is well-structured (tests, CI, lockfile, license all present) but the codebase carries real maintenance debt: import cycles, oversized modules, and a 782-line config file. The claude-hooks layer is the most polished part. Use it if you need self-hosted agent memory without cloud lock-in — but budget time for the refactoring flagged above before scaling it.