Smriti MCP

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 Logo

Smriti MCP

Go Version License: MPL 2.0 MCP Docker Hub CodeQL

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 Toolssmriti_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:

  1. Cue Extraction — LLM extracts entities and keywords from the query
  2. Cue-Based Graph Traversal — Follows EncodedBy edges to find engrams linked to matching cues
  3. Vector Similarity Search — Cosine similarity against all engram embeddings (HNSW index when available, fallback to brute-force)
  4. Multi-Hop Expansion — Follows AssociatedWith edges to discover related memories
  5. 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)
  6. 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 AssociatedWith edges 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_id to each engram, stored persistently in the database
  • New engrams inherit the cluster_id of 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:

  1. Exponential Decay — Reduces decay_factor based on time since last access
  2. Weak Memory Pruning — Removes engrams below minimum decay threshold
  3. Frequency Strengthening — Boosts decay factor for frequently accessed memories
  4. Orphaned Cue Cleanup — Removes cues no longer linked to any engram
  5. Leiden Clustering — Re-clusters the memory graph (smart-cached, skips if graph hasn't changed significantly)
  6. 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
  • liblbug (LadybugDB shared library) — Runtime dependency, downloaded automatically by go-ladybug during build. If building manually, grab the latest release from LadybugDB/ladybug:

    PlatformAssetLibrary
    macOSliblbug-osx-universal.tar.gzliblbug.dylib
    Linuxliblbug-linux-{arch}.tar.gzliblbug.so
    Windowsliblbug-windows-x86_64.zipliblbug.dll

    The shared library must be on the system library path at runtime (e.g., DYLD_LIBRARY_PATH on macOS, LD_LIBRARY_PATH on 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/yourname with your actual home directory path
  • MCP clients do not expand $HOME or ~ in JSON configs — use absolute paths
  • The .smriti volume 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:

PlatformArchitectureCGO
Linuxamd64Enabled (native)
macOSarm64 (Apple Silicon)Enabled (native)
Windowsamd64Enabled (native)

Each release includes a checksums-sha256.txt for verification.

Environment Variables

Core

VariableDefaultDescription
ACCESSING_USEROS usernameUser identifier (separate DB per user)
STORAGE_LOCATION~/.smritiRoot storage directory

LLM

VariableDefaultDescription
LLM_BASE_URLhttps://api.openai.com/v1LLM API endpoint (OpenAI-compatible)
LLM_API_KEY(required)LLM API key
LLM_MODELgpt-4o-miniLLM model name

Embedding

VariableDefaultDescription
EMBEDDING_BASE_URLhttps://api.openai.com/v1Embedding API endpoint
EMBEDDING_API_KEY(falls back to LLM_API_KEY)Embedding API key
EMBEDDING_MODELtext-embedding-3-smallEmbedding model name
EMBEDDING_DIMS1536Embedding vector dimensions

Backup

VariableDefaultDescription
BACKUP_TYPEnonenone, github, or s3
BACKUP_SYNC_INTERVAL60Seconds 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

VariableDefaultDescription
CONSOLIDATION_INTERVAL3600Seconds 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"
}
ParameterTypeRequiredDescription
contentstringyesMemory content
importancenumbernoPriority 0.0–1.0 (default: 0.5)
tagsstringnoComma-separated tags
sourcestringnoSource/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"
}
ParameterTypeRequiredDescription
querystringnoNatural language query (omit for list mode)
limitnumbernoMax results (default: 5)
modestringnorecall (deep multi-hop), search (fast vector-only), or list (browse)
memory_typestringnoFilter: episodic, semantic, procedural

Modes explained:

  • recall (default) — Full pipeline: cue extraction → graph traversal → vector search → multi-hop → cluster-aware composite scoring
  • search — 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"
}
ParameterTypeRequiredDescription
actionstringyesforget (delete memory) or sync (push backup)
memory_idstringif forgetEngram 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.

Máy chủ liên quan