- Smriti Mcp
Smriti Mcp
Smriti MCP
Graph-Based AI Memory System with EcphoryRAG Retrieval and Leiden Clustering
Smriti is a Model Context Protocol (MCP) server that provides persistent, graph-based memory for LLM applications. Built on LadybugDB (embedded property graph database), it uses EcphoryRAG-inspired multi-stage retrieval — combining cue extraction, graph traversal, vector similarity, and multi-hop association — to deliver human-like memory recall. Smriti uses the Leiden algorithm for automatic community detection, enabling cluster-aware retrieval that scales beyond thousands of memories.
Features
- Graph-Based Memory — Engrams (memories) linked via Cues and Associations in a property graph
- EcphoryRAG Retrieval — Multi-hop associative recall with cue extraction, vector similarity, and composite scoring
- Leiden Community Detection — Automatic clustering of related memories using the Leiden algorithm with smart-cached resolution tuning, enabling cluster-aware scoring for efficient retrieval at scale
- Multi-User Support — Separate LadybugDB per user, scales to thousands of isolated memory stores
- Automatic Consolidation — Exponential decay, pruning of weak memories, strengthening of frequently accessed ones, and periodic Leiden re-clustering
- Flexible Backup — GitHub (system git) or S3 (AWS SDK) sync, plus noop for local-only
- Lazy HNSW Indexing — Vector and FTS indexes created on-demand when dataset exceeds threshold
- OpenAI-Compatible APIs — Works with any OpenAI-compatible LLM and embedding provider
- 3 MCP Tools —
smriti_store,smriti_recall,smriti_manage
Architecture
graph TD
Client["MCP Client<br/>(Cursor / Claude / Windsurf / etc.)"]
Client -->|stdio| Server
subgraph Server["Smriti MCP Server"]
direction TB
subgraph Tools["MCP Tools"]
Store["smriti_store"]
Recall["smriti_recall"]
Manage["smriti_manage"]
end
subgraph Engine["Memory Engine"]
Encoding["Encoding<br/>LLM + Embed + Link"]
Retrieval["Retrieval<br/>Cue Match + Vector + Multi-hop<br/>+ Cluster-Aware Scoring"]
Consolidation["Consolidation<br/>Decay + Prune + Leiden Clustering"]
end
subgraph DB["LadybugDB (Property Graph)"]
Graph["(Engram)──[:EncodedBy]──▶(Cue)<br/>(Engram)──[:AssociatedWith]──▶(Engram)<br/>(Cue)──[:CoOccurs]──▶(Cue)"]
end
subgraph Backup["Backup Provider (optional)"]
Git["GitHub (git)"]
S3["S3 (AWS SDK)"]
Noop["Noop"]
end
Store & Recall & Manage --> Engine
Encoding & Retrieval & Consolidation --> DB
DB --> Backup
end
LLM["LLM / Embedding API<br/>(OpenAI-compatible)"]
Engine --> LLM
Recall Pipeline
The default recall mode performs multi-stage retrieval:
- Cue Extraction — LLM extracts entities and keywords from the query
- Cue-Based Graph Traversal — Follows
EncodedByedges to find engrams linked to matching cues - Vector Similarity Search — Cosine similarity against all engram embeddings (HNSW index when available, fallback to brute-force)
- Multi-Hop Expansion — Follows
AssociatedWithedges to discover related memories - Cluster-Aware Composite Scoring — Blends vector similarity (40%), recency (20%), importance (20%), and decay (20%), with hop-depth penalty and soft-bounded cross-cluster penalty (0.5x for hop results outside the seed cluster)
- Access Strengthening — Recalled engrams get their access count and decay factor bumped (reinforcement)
Leiden Clustering
Smriti uses the Leiden algorithm — an improvement over Louvain that guarantees well-connected communities — to automatically detect clusters of related memories in the graph.
How it works:
- Runs automatically during each consolidation cycle
- Builds a weighted undirected graph from
AssociatedWithedges between engrams - Auto-tunes the resolution parameter using community profiling on the first run
- Uses a smart cache: the tuned resolution is reused across runs and only re-tuned when the graph grows by more than 10%
- Assigns a
cluster_idto each engram, stored persistently in the database - New engrams inherit the
cluster_idof their strongest neighbor at encode time
How it improves retrieval:
- The recall pipeline determines a seed cluster (most common cluster among direct-match results)
- Multi-hop results that cross into a different cluster receive a 0.5x score penalty (soft-bounded: they are penalized, not dropped)
- This keeps retrieval focused within the most relevant topic cluster while still allowing cross-topic discovery
Performance characteristics:
- Gracefully skips on small graphs (< 3 nodes or 0 edges)
- Clustering 60 nodes: ~40ms (first run with auto-tune), ~14ms (cached resolution)
- Per-user: each Engine instance maintains its own independent cache
Consolidation Pipeline
Consolidation runs periodically (default: every 3600 seconds) and performs:
- Exponential Decay — Reduces
decay_factorbased on time since last access - Weak Memory Pruning — Removes engrams below minimum decay threshold
- Frequency Strengthening — Boosts decay factor for frequently accessed memories
- Orphaned Cue Cleanup — Removes cues no longer linked to any engram
- Leiden Clustering — Re-clusters the memory graph (smart-cached, skips if graph hasn't changed significantly)
- Index Management — Creates HNSW vector and FTS indexes when engram count exceeds threshold (50)
Requirements
-
Go 1.25+ — For building from source
-
Git 2.x+ — Required for GitHub backup provider (must be in PATH)
-
GCC/Build Tools — Required for CGO (LadybugDB)
- macOS:
xcode-select --install - Linux:
sudo apt install build-essential - Windows: Use Docker (recommended) or MinGW
- macOS:
-
liblbug (LadybugDB shared library) — Runtime dependency, downloaded automatically by
go-ladybugduring build. If building manually, grab the latest release from LadybugDB/ladybug:Platform Asset Library macOS liblbug-osx-universal.tar.gzliblbug.dylibLinux liblbug-linux-{arch}.tar.gzliblbug.soWindows liblbug-windows-x86_64.zipliblbug.dllThe shared library must be on the system library path at runtime (e.g.,
DYLD_LIBRARY_PATHon macOS,LD_LIBRARY_PATHon Linux, or alongside the binary on Windows). Docker and release binaries bundle this automatically.
Quick Start
1. Build
# Build
CGO_ENABLED=1 go build -o smriti-mcp .
# Run (minimal config)
export LLM_API_KEY=your-api-key
export ACCESSING_USER=alice
./smriti-mcp
2. MCP Client Integration
Option 1: Native Binary
Cursor (~/.cursor/mcp_settings.json):
{
"mcpServers": {
"smriti": {
"command": "/path/to/smriti-mcp",
"env": {
"LLM_API_KEY": "your-api-key",
"EMBEDDING_API_KEY": "your-embedding-key"
}
}
}
}
Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"smriti": {
"command": "/path/to/smriti-mcp",
"args": [],
"env": {
"LLM_API_KEY": "your-api-key",
"EMBEDDING_API_KEY": "your-embedding-key"
}
}
}
}
Windsurf (~/.codeium/windsurf/mcp_config.json):
{
"mcpServers": {
"smriti": {
"command": "/path/to/smriti-mcp",
"env": {
"LLM_API_KEY": "your-api-key",
"EMBEDDING_API_KEY": "your-embedding-key"
}
}
}
}
Option 2: Go Run
Run directly without installing — similar to npx for Node.js:
{
"mcpServers": {
"smriti": {
"command": "go",
"args": ["run", "github.com/tejzpr/smriti-mcp@latest"],
"env": {
"LLM_API_KEY": "your-api-key",
"EMBEDDING_API_KEY": "your-embedding-key"
}
}
}
}
Option 3: Docker Container
Simple mode (single user):
{
"mcpServers": {
"smriti": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-v", "/Users/yourname/.smriti:/home/smriti/.smriti",
"-e", "LLM_API_KEY=your-api-key",
"-e", "EMBEDDING_API_KEY=your-embedding-key",
"tejzpr/smriti-mcp"
]
}
}
}
Multi-user mode:
{
"mcpServers": {
"smriti": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-v", "/Users/yourname/.smriti:/home/smriti/.smriti",
"-e", "LLM_API_KEY=your-api-key",
"-e", "EMBEDDING_API_KEY=your-embedding-key",
"-e", "ACCESSING_USER=yourname",
"tejzpr/smriti-mcp"
]
}
}
}
Note:
- Replace
/Users/yournamewith your actual home directory path- MCP clients do not expand
$HOMEor~in JSON configs — use absolute paths- The
.smritivolume mount persists your memory database- The container runs as non-root user
smriti
Build locally (optional):
docker build -t smriti-mcp .
Then use smriti-mcp instead of tejzpr/smriti-mcp in your config.
Option 4: GitHub Release Binary
Download pre-built binaries from the Releases page. Binaries are available for:
| Platform | Architecture | CGO |
|---|---|---|
| Linux | amd64 | Enabled (native) |
| macOS | arm64 (Apple Silicon) | Enabled (native) |
| Windows | amd64 | Enabled (native) |
Each release includes a checksums-sha256.txt for verification.
Environment Variables
Core
| Variable | Default | Description |
|---|---|---|
ACCESSING_USER | OS username | User identifier (separate DB per user) |
STORAGE_LOCATION | ~/.smriti | Root storage directory |
LLM
| Variable | Default | Description |
|---|---|---|
LLM_BASE_URL | https://api.openai.com/v1 | LLM API endpoint (OpenAI-compatible) |
LLM_API_KEY | (required) | LLM API key |
LLM_MODEL | gpt-4o-mini | LLM model name |
Embedding
| Variable | Default | Description |
|---|---|---|
EMBEDDING_BASE_URL | https://api.openai.com/v1 | Embedding API endpoint |
EMBEDDING_API_KEY | (falls back to LLM_API_KEY) | Embedding API key |
EMBEDDING_MODEL | text-embedding-3-small | Embedding model name |
EMBEDDING_DIMS | 1536 | Embedding vector dimensions |
Backup
| Variable | Default | Description |
|---|---|---|
BACKUP_TYPE | none | none, github, or s3 |
BACKUP_SYNC_INTERVAL | 60 | Seconds between backup syncs (0 = disabled) |
GIT_BASE_URL | (empty) | Git remote base URL (required if github) |
S3_ENDPOINT | (empty) | S3 endpoint (for non-AWS providers) |
S3_REGION | (empty) | S3 region (required if s3) |
S3_ACCESS_KEY | (empty) | S3 access key (required if s3) |
S3_SECRET_KEY | (empty) | S3 secret key (required if s3) |
Consolidation
| Variable | Default | Description |
|---|---|---|
CONSOLIDATION_INTERVAL | 3600 | Seconds between consolidation runs (0 = disabled) |
MCP Tools
smriti_store
"Remember this" — Store a new memory. Content is automatically analyzed by the LLM, embedded, and woven into the memory graph. New engrams inherit the cluster_id of their most similar existing neighbor.
{
"content": "Kubernetes uses etcd as its backing store for all cluster data",
"importance": 0.8,
"tags": "kubernetes,etcd,infrastructure",
"source": "meeting-notes"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
content | string | yes | Memory content |
importance | number | no | Priority 0.0–1.0 (default: 0.5) |
tags | string | no | Comma-separated tags |
source | string | no | Source/origin label |
smriti_recall
"What do I know about X?" — Retrieve memories using multi-stage EcphoryRAG retrieval with cluster-aware scoring.
{
"query": "container orchestration tools",
"limit": 5,
"mode": "recall"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
query | string | no | Natural language query (omit for list mode) |
limit | number | no | Max results (default: 5) |
mode | string | no | recall (deep multi-hop), search (fast vector-only), or list (browse) |
memory_type | string | no | Filter: episodic, semantic, procedural |
Modes explained:
recall(default) — Full pipeline: cue extraction → graph traversal → vector search → multi-hop → cluster-aware composite scoringsearch— Vector-only cosine similarity. Faster but shallower.list— No search. Returns recent memories ordered by last access time.
smriti_manage
"Forget this / sync now" — Administrative operations.
{
"action": "forget",
"memory_id": "abc-123-def"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
action | string | yes | forget (delete memory) or sync (push backup) |
memory_id | string | if forget | Engram ID to delete |
Graph Schema
Smriti stores memories in a property graph with the following structure:
Node Tables:
Engram — id, content, summary, memory_type, importance, access_count,
created_at, last_accessed_at, decay_factor, embedding, source,
tags, cluster_id
Cue — id, name, cue_type, embedding
Relationship Tables:
EncodedBy — (Engram) → (Cue)
AssociatedWith — (Engram) → (Engram) [strength, relation_type, created_at]
CoOccurs — (Cue) → (Cue) [strength]
The cluster_id field on Engram nodes is managed by the Leiden algorithm. A value of -1 indicates the engram has not yet been assigned to a cluster (e.g., the graph is too small, or the engram has no associations).
Storage
Each user gets an isolated LadybugDB file:
~/.smriti/
└── {username}/
└── memory.lbug # LadybugDB property graph database
The STORAGE_LOCATION env var controls the root. The ACCESSING_USER env var selects which user's DB to open. Backup providers sync the user directory to remote storage.
Schema migrations (e.g., adding cluster_id to existing databases) run automatically on startup.
Project Structure
smriti-mcp/
├── main.go # Entry point, server setup, signal handling
├── config/ # Environment variable parsing
├── llm/ # OpenAI-compatible HTTP client (LLM + embeddings)
├── db/ # LadybugDB Store wrapper, schema, indexes, migrations
├── memory/
│ ├── engine.go # Engine struct, consolidation loop
│ ├── types.go # Engram, Cue, Association, SearchResult structs
│ ├── encoding.go # Store pipeline: LLM extraction → embed → link → cluster inherit
│ ├── retrieval.go # Recall pipeline: cue search → vector → multi-hop → cluster scoring
│ ├── search.go # Search modes: list, vector-only, FTS, hybrid
│ ├── consolidation.go # Decay, prune, strengthen, orphan cleanup
│ └── leiden.go # Leiden clustering: graph build, auto-tune, smart cache, batch write
├── backup/ # Backup providers: noop, github (git), s3 (AWS SDK)
├── tools/ # MCP tool definitions: store, recall, manage
└── testutil/ # Shared test helpers
Testing
# Run all tests
CGO_ENABLED=1 go test ./...
# Verbose with all output
CGO_ENABLED=1 go test -v ./...
# Specific package
CGO_ENABLED=1 go test -v ./memory/...
CGO_ENABLED=1 go test -v ./tools/...
# Leiden clustering tests only
CGO_ENABLED=1 go test -v -run "TestRunLeiden|TestNeedsRetune|TestDetermineSeedCluster" ./memory/
Contributing
Contributions are welcome! Please ensure:
- All tests pass (
CGO_ENABLED=1 go test ./...) - Code is properly formatted (
go fmt ./...) - New code includes the SPDX license header
See CONTRIBUTORS.md for the contributor list.
License
This project is licensed under the Mozilla Public License 2.0.
Server Config
{
"mcpServers": {
"smriti": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-v",
"/Users/yourname/.smriti:/home/smriti/.smriti",
"-e",
"LLM_API_KEY=your-api-key",
"-e",
"EMBEDDING_API_KEY=your-embedding-key",
"tejzpr/smriti-mcp"
]
}
}
}