<p align="center">
  <img src="images/banner.svg?v=2.0.0" alt="MCP Engram Memory" width="900"/>
</p>

<p align="center">
  <a href="https://dotnet.microsoft.com/"><img src="https://img.shields.io/badge/.NET-8%20%7C%209%20%7C%2010-512BD4" alt=".NET"/></a>
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"/></a>
  <a href="https://www.nuget.org/packages/McpEngramMemory.Core"><img src="https://img.shields.io/nuget/v/McpEngramMemory.Core" alt="NuGet"/></a>
  <img src="https://img.shields.io/badge/tests-multi--target-brightgreen" alt="Tests: .NET 8, 9, and 10"/>
  <img src="https://img.shields.io/badge/release-2.0-blueviolet" alt="Release: 2.0"/>
</p>

# The governed, local-first cognitive memory kernel for AI agents

**Memory physics, not just storage.** Most agent memory systems store context. **Engram evolves context** — topology-driven decay, consolidation, and contradiction detection, all running locally with zero external API.

**2.0 makes the boundary explicit.** Tenant scope stops being a defaulted argument: 55 Core retrieval and scoping APIs now require `tenantId` with no default, positioned so that pre-2.0 positional calls fail to compile rather than silently rebinding. The compiler makes you *state* the scope — it does not choose one for you, and `tenantId: ""` still selects the legacy partition.

- **Tenant-Partitioned Throughout** — partitioning runs through storage, graph, clusters, lifecycle, diffusion, synthesis, and visualization. Edges never cross tenants; cross-namespace association *within* a tenant is preserved.
- **Context Control** — graph-Laplacian diffusion decays trivial chats so your context window doesn't choke on noise. Important, well-connected knowledge stays sharp; transient chatter fades.
- **Contradiction Detection** — `find_contradictions` surfaces conflicting goals or architecture decisions on demand, so you can review and retire logic you've already reversed instead of letting the agent keep acting on it.
- **Governed Core** — a deterministic Root Constitution, versioned knowledge and provenance, Teacher/Verifier promotion, authorization-first retrieval planning, and citation-aware context manifests are available to embedding hosts.
- **100% Privacy-First** — local ONNX embeddings + local SQLite. Your memory never leaves your machine. No telemetry, no analytics, no phone-home: the server makes no outbound network call at all in its default configuration. (The optional synthesis backend talks to a local Ollama daemon, and `OLLAMA_URL` can be pointed elsewhere if you choose to.)

→ [See the cold-start scorecard](docs/why-engram.md#the-proof) · [Get started in 5 minutes](docs/first-5-minutes.md) · [What's new in 2.0](#whats-new-in-20)

## What's New in 2.0

2.0 is a **breaking release for hosts embedding `McpEngramMemory.Core`**. MCP clients and stdio
deployments are unaffected — tool names, arguments, and on-disk data are unchanged, and legacy
empty-tenant deployments still behave byte-for-byte as before.

| Change | What it means |
|--------|---------------|
| **`tenantId` is required** on 55 Core retrieval/scoping APIs | The old `tenantId = ""` default wasn't a sentinel — `""` is the legacy partition, a real readable dataset, so a forgotten argument compiled clean and silently degraded to cross-tenant scope. It did, twice. The compiler now finds every omission. |
| **Parameter placement is anti-rebinding** | `tenantId` only moved into slots previously held by an `int`/`float`/`bool`, so pre-2.0 positional calls fail to compile rather than binding a relation or query string into the tenant slot. |
| **Topology reads are revision-consistent** | Graph and cluster projections publish only if the tenant's attribution revision held through the whole projection; continuous churn fails closed. |
| **Auto-link accounting is exact** | Pair walks report completed comparison slots once per anchor, so cancellation no longer over- or under-states progress. |
| **`AutoLinkResult` reshaped** | Four new trailing members; `PairsExamined` is now `long` and reports completed comparison slots. Use `PairSlotsPlanned` for the window budget, `PairsAboveThreshold` for the find count. |

2.0 supersedes 1.6.0, which is where the underlying features landed: **full multi-tenant graph,
clusters, lifecycle, diffusion, intelligence, synthesis and snapshots** (with no storage migration —
tenant travels inside the existing JSON blobs), and the **governed cognitive constitution**
(deterministic Root Constitution, audited pre/post MCP filter, versioned Knowledge, append-only
Provenance, `promote_knowledge` on the full profile). 2.0 is what makes that boundary mandatory
instead of optional.

**Upgrading:** recompile, and at each error pass the tenant the call site already holds —
`tenantId: myTenant`, or `tenantId: ""` where legacy scope is the deliberate meaning. Treat every
`tenantId: ""` you add as a claim, not a fix. Full detail in the
[2.0.0 release notes](docs/release-notes-2.0.0.md) and
[Tenant Isolation Design](docs/tenant-isolation-design.md).

## How It Works

Engram sits between your AI assistant and a local store. Every memory is embedded, indexed for hybrid search, woven into a knowledge graph, and then left to *evolve* on its own — background workers decay noise, consolidate what matters, and densify the graph while you're away.

<p align="center">
  <img src="images/how-it-works.svg?v=1.2.0" alt="How It Works — store, search, link, route, with automatic diffusion subsystem and lifecycle transitions" width="900"/>
</p>

The loop, end to end:

1. **Store** — `remember` embeds text with a local ONNX model (bge-micro-v2, 384-dim), detects near-duplicates, and auto-links the new memory to related ones in the graph.
2. **Search** — `recall` runs hybrid retrieval (BM25 keyword + vector similarity, fused with RRF), expands synonyms, and re-ranks through the graph's spectral structure. (Opt-in MMR diversity reranking is available on `search_memory` and `cross_search`.)
3. **Route** — with the namespace omitted, `recall` auto-routes across expert namespaces to find knowledge you didn't know where to look for.
4. **Evolve** — background services run the *physics*: spectral decay fades weakly-connected memories (archiving the weakest), sleep consolidation promotes well-connected STM to LTM, and auto-link densifies the graph.

Retrieval itself is a nine-stage pipeline — candidate generation, keyword rescue, fusion, diversity, and spectral re-ranking:

<p align="center">
  <img src="images/retrieval-pipeline.svg?v=2.0.0" alt="9-stage retrieval pipeline including v0.9.0 spectral re-ranking" width="900"/>
</p>

## See It in Action

<p align="center">
  <!--
    Animated hero GIF of the live memory graph.
    Generated headlessly from real snapshot data — see tools/graph-gif/ (run
    `node prep-snapshot.js && node capture.js`). It drives visualization/memory-graph.html
    in headless Chromium and shows STM (amber) → LTM (blue) clustering during a
    consolidation cycle plus a pulse-highlight on retrieval. ~900px wide, < 3 MB.
    Regenerate whenever the visualizer or palette changes.
  -->
  <img src="images/memory-graph.gif" alt="Engram memory graph clustering during a consolidation cycle: STM (amber) nodes migrating into LTM (blue) clusters, with pulse-highlight on retrieval" width="900"/>
</p>

<p align="center"><em>The memory graph consolidating in real time — short-term (amber) memories cluster and promote to long-term (blue) during a sleep cycle.</em></p>

The built-in D3.js graph viewer lets you explore your own memory graph interactively. Generate a snapshot from any AI assistant, then open the viewer:

```
get_graph_snapshot   →   save the JSON   →   open visualization/memory-graph.html
```

<p align="center">
  <img src="images/graph-overview.png" alt="Memory graph overview — 1,207 nodes, 375 edges, 178 clusters" width="860"/>
</p>

<p align="center">
  <img src="images/graph-detail.png" alt="Memory graph connected-only detail view" width="860"/>
</p>

**Viewer features:**
- **Force-directed layout** — related memories cluster together, typed edges (elaborates, contradicts, depends_on, …) shown in distinct neon colors
- **Lifecycle colors** — STM nodes amber, LTM nodes blue; cluster summaries marked with a dashed ring
- **Convex-hull cluster overlays** — cluster membership visible at a glance
- **Search & highlight** — type in the search bar to instantly dim non-matching nodes and pulse-highlight matches in gold; `‹ ›` buttons or `Enter / Shift+Enter` to cycle through results
- **Zoom / pan / rotate** — `+` / `−` / `⊡` buttons; scroll to zoom; right-click drag to rotate the whole graph
- **Fractal density overlay** — zooms out reveal a quadtree density map color-coded by lifecycle state
- **Connected-only filter** — hide isolated nodes to focus on the linked knowledge graph
- **Drag-and-drop JSON loading** — drop a snapshot file directly onto the viewer

The snapshot file is not committed (it's personal memory data). Generate a fresh one any time with `get_graph_snapshot`.

## Quickstart

```powershell
# Windows — clones, builds, and wires up your AI assistant automatically
irm https://raw.githubusercontent.com/wyckit/mcp-engram-memory/main/setup.ps1 | iex
```

```bash
# macOS / Linux
curl -fsSL https://raw.githubusercontent.com/wyckit/mcp-engram-memory/main/setup.sh | bash
```

> The embedding model (bge-micro-v2) ships inside the package — it is fetched from Hugging Face at
> build time, checksum-verified, and bundled, so installing the tool needs no model download and the
> server makes no network call to start.

<details>
<summary>Other install options (manual clone · Docker · NuGet)</summary>

**Manual clone**

```bash
git clone https://github.com/wyckit/mcp-engram-memory.git
cd mcp-engram-memory && dotnet restore
```

Add to your MCP client config:

```json
{
  "mcpServers": {
    "engram-memory": {
      "command": "dotnet",
      "args": ["run", "--project", "/path/to/mcp-engram-memory/src/McpEngramMemory"],
      "env": { "MEMORY_TOOL_PROFILE": "minimal" }
    }
  }
}
```

**Docker**

```bash
docker build -t mcp-engram-memory .
docker run -i -v memory-data:/app/data mcp-engram-memory
```

**NuGet library** (embed the engine in your own .NET app)

```bash
dotnet add package McpEngramMemory.Core --version 2.0.0
```

See [`examples/`](examples/) for ready-to-use config files.

</details>

## At a Glance

| Metric | Value |
|--------|-------|
| Version | 2.0.0 (breaking for Core library hosts; MCP surface unchanged) |
| MCP tools | 63 (profiles: 17 / 39 / 63) |
| Isolation | Tenant-partitioned across storage, graph, clusters, lifecycle, diffusion, synthesis, and snapshots |
| Retrieval | Hybrid BM25 + vector with synonym expansion, cascade retrieval, MMR diversity, auto-PRF |
| Embedding | bge-micro-v2 (384-dim, ONNX, MIT license, runs locally, concurrent inference) |
| Best recall | **0.792** realworld dataset, **0.771** scale dataset (hybrid mode) |
| Search latency | ~2.7 ms production, ~0.04 ms benchmark |
| Storage | JSON (default) or SQLite (WAL mode) |
| Frameworks | net8.0, net9.0, net10.0 |
| Tests | Multi-target xUnit suite across net8.0, net9.0, and net10.0 |
| CI/CD | GitHub Actions: build + test on push, nightly MSA benchmarks |

## Tool Profiles

Engram exposes a tunable tool surface. Start on `minimal` — three headline verbs (`remember`, `recall`, `reflect`) plus admin and multi-agent — and widen only if you need the advanced subsystems. Control it with `MEMORY_TOOL_PROFILE`:

| Profile | Tools | What's included |
|---------|-------|-----------------|
| `minimal` | 17 | Core CRUD + composite + admin + multi-agent — recommended starting point **(default)** |
| `standard` | 39 | Adds graph (+auto-link), lifecycle (+consolidation), clustering, intelligence, memory-diffusion kernel, spectral retrieval |
| `full` | 63 | Everything including governed knowledge promotion, expert routing, debate, synthesis, benchmarks |

### MCP Tools (63)

| Group | Tools | Description |
|-------|-------|-------------|
| Core Memory | `store_memory`, `store_batch`, `search_memory`, `delete_memory` | Vector CRUD with namespace isolation, batch import, and lifecycle-aware search |
| Composite | `remember`, `recall` (with `spectralMode`), `reflect`, `get_context_block` | High-level wrappers with auto-dedup, auto-linking, expert routing, context assembly, and graph-aware spectral re-ranking on `recall` (default `auto`) |
| Knowledge Graph | `link_memories`, `unlink_memories`, `get_neighbors`, `traverse_graph` | Directed graph with 7 relation types and multi-hop BFS; similarity-based auto-link densification runs as a 6-hour background sweep |
| Clustering | `create_cluster`, `update_cluster`, `store_cluster_summary`, `get_cluster`, `list_clusters` | Semantic grouping with auto-computed centroids |
| Lifecycle | `promote_memory`, `memory_feedback`, `deep_recall`, `configure_decay` | State transitions (STM/LTM/archived) and per-namespace decay configuration; spectral decay diffusion and sleep consolidation run automatically as background services |
| Memory Diffusion | `compute_diffusion_basis`, `diffusion_stats`, `invalidate_diffusion`, `spectral_recall` | Graph-Laplacian eigenbasis primitive shared by decay, consolidation, and retrieval; standalone graph-aware retrieval |
| Intelligence | `detect_duplicates`, `find_contradictions`, `merge_memories`, `uncollapse_cluster`, `list_collapse_history` | Dedup, contradiction detection, merge, collapse reversal |
| Expert Routing | `dispatch_task`, `create_expert`, `get_domain_tree`, `link_to_parent` | HMoE semantic routing with 3-level domain tree |
| Multi-Agent | `cross_search`, `share_namespace`, `unshare_namespace`, `list_shared`, `whoami` | Namespace sharing, permissions, cross-namespace RRF search |
| Debate | `consult_expert_panel`, `map_debate_graph`, `resolve_debate` | Multi-perspective analysis with debate tracking |
| Synthesis | `synthesize_memories` | Map-reduce synthesis via a local SLM served by Ollama. For fully in-process generation, embed `McpEngramMemory.Core` and add the optional [`McpEngramMemory.Synthesis.Onnx`](#optional-in-process-synthesis) package |
| Accretion | `get_pending_collapses`, `collapse_cluster`, `dismiss_collapse` | DBSCAN cluster detection and two-phase summarization (the density scan runs as a 30-min background sweep) |
| Governed Learning | `promote_knowledge` | Full-profile adapter for the Teacher → deterministic Verifier → Constitution receipt → atomic governed-store promotion path |
| Admin | `get_memory`, `cognitive_stats`, `engram_status`, `purge_debates` | Inspection, system-wide statistics, background-worker health, and stale debate-namespace cleanup |
| Maintenance | `rebuild_embeddings`, `compression_stats` | Re-embed entries and storage diagnostics |
| Benchmarks | `run_benchmark`, `run_agent_outcome_benchmark`, `run_live_agent_outcome_benchmark`, `compare_live_agent_outcome_artifacts`, `check_for_regression`, `get_metrics`, `reset_metrics`, `run_mrcr_benchmark`, `compare_mrcr_artifacts` | IR quality validation, proxy and live memory-condition benchmarking, artifact diffing, CI regression gating, latency/throughput metrics, and MRCR v2 long-context A/B |
| Visualization | `get_graph_snapshot` | Memory-graph JSON snapshot (nodes, typed edges, clusters) for the built-in D3 viewer (`visualization/memory-graph.html`) |

Full tool documentation: [MCP Tools Reference](docs/mcp-tools-reference.md)

The server uses the `ModelContextProtocol` 2.2.0 SDK with negotiated protocol handling, a global
request-filter pipeline, and explicit read-only/destructive/idempotent/open-world tool metadata.
SDK package version and negotiated MCP protocol revision are not the same thing.

## Architecture

| Layer | Stability | Components |
|-------|-----------|------------|
| **Core** | Stable | Storage, Embeddings, Retrieval, Lifecycle, Graph |
| **Advanced** | Stable | Clustering, Multi-Agent Sharing, Intelligence |
| **Governed Core** | Maturing | Constitution, Knowledge, Provenance, Learning, Planning, Semantic Assets |
| **Orchestration** | Maturing | Expert Routing (HMoE), Debate, Benchmarks |

### Governed Core vs. MCP tools

The governed substrate lives in `McpEngramMemory.Core`: immutable Root/overlay Constitutions,
versioned Knowledge and append-only Provenance, quarantined Teacher proposals, deterministic-first
verification, atomic reference promotion, authorization-first retrieval planning, context manifests,
profiles/loadouts, and Skill/Documentation/CodeGraph/Curriculum contracts.

The 63 MCP tools include the full-profile `promote_knowledge` adapter, which executes the
Teacher → deterministic Verifier → Constitution receipt → atomic governed-store path. Context and
other asset-management tools remain Core APIs for embedded hosts. Every tool call also passes through
the global Constitution pre/post filter. Skill execution is
delegated to a host-provided `ISkillSandbox`; Engram does not run arbitrary Skill code.

Identity is also host-owned. `IPrincipalContext` carries tenant and principal claims. The stdio
server bootstraps it from `MEMORY_TENANT_ID` and `AGENT_ID`, which are process configuration rather
than authentication. Empty tenant + default agent is explicit legacy-unisolated mode.

Multi-tenancy is complete and, as of 2.0, mandatory at the API boundary. Memory CRUD and search,
the cognitive graph, clusters, lifecycle, collapse history, diffusion/spectral retrieval,
intelligence, maintenance, synthesis, and visualization are all tenant-partitioned: a tenant sees
and mutates only its own data, and graph edges never cross tenants (cross-namespace association
within a tenant is preserved). Core's retrieval and scoping APIs take `tenantId` as a required
argument, so scope is a decision the compiler makes you state rather than a default you can forget —
`""` remains a valid answer, and the legacy partition it names is a real dataset, so state it
deliberately. Legacy empty-tenant deployments are byte-for-byte unchanged. See
[Cognitive Constitution and Governed Core](docs/cognitive-constitution.md) and [Security](SECURITY.md).

## AI Assistant Setup

Model execution belongs to the host harness, not the Engram server: expert profiles route to persona-backed memory namespaces, while the host model reasons over the retrieved evidence. See [Model and Reasoning Routing](docs/model-routing.md) for canonical task tiers, the current Codex model mapping, reasoning escalation rules, and ready-to-use profiles.

Copy the reference harness for your tool — each includes recall/store/routing patterns:

| Tool | Harness File | MCP Config |
|------|-------------|------------|
| Claude Code | [`examples/CLAUDE.md`](examples/CLAUDE.md) → `~/.claude/CLAUDE.md` | [`examples/claude-code.json`](examples/claude-code.json) |
| GitHub Copilot | [`examples/copilot-instructions.md`](examples/copilot-instructions.md) → `.github/` | [`examples/vscode-copilot.json`](examples/vscode-copilot.json) |
| Google Gemini | [`GEMINI.md`](GEMINI.md) → workspace root | [Gemini CLI config](https://github.com/google/gemini-cli) |
| OpenAI Codex | [`examples/AGENTS.md`](examples/AGENTS.md) → project root | [Codex config](https://github.com/openai/codex) |

> **Claude Code users**: Route memory sub-agents to Sonnet (`model: "sonnet"`) and utility sub-agents to Haiku (`model: "haiku"`) to maximize your subscription. See the [harness](examples/CLAUDE.md) for details.

For step-by-step setup prompts, see [AI Assistant Setup](docs/ai-assistant-setup.md).

### Cost-Optimized Usage (Claude Code)

| Tier | Model | What runs here |
|------|-------|----------------|
| **Main thread** | Opus | Coding, architecture, reasoning, decisions |
| **Memory sub-agents** | Sonnet (`model: "sonnet"`) | All engram MCP tool calls: search, store, dispatch, link, merge |
| **Utility sub-agents** | Haiku (`model: "haiku"`) | Codebase exploration, file searches, grep research, simple lookups |

Opus thinks, Sonnet remembers, Haiku explores.

## Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `MEMORY_TOOL_PROFILE` | `minimal` | Tool profile: `minimal` (17), `standard` (39), `full` (63) |
| `AGENT_ID` | `default` | Host-supplied agent identity for namespace sharing. The default is explicit legacy-unisolated compatibility mode, not authentication. |
| `MEMORY_TENANT_ID` | empty | Host-supplied tenant partition. Do not accept this value from model/tool arguments. Empty selects the legacy partition. |
| `MEMORY_STORAGE` | `json` | Storage backend: `json`, `sqlite`, or `sqlserver` |
| `MEMORY_SQLITE_PATH` | `data/memory.db` | SQLite database path (when `MEMORY_STORAGE=sqlite`) |
| `MEMORY_SQLSERVER_CONNECTION` | _required_ | SQL Server connection string (when `MEMORY_STORAGE=sqlserver`) |
| `MEMORY_SQLSERVER_SCHEMA` | `dbo` | SQL Server schema name (when `MEMORY_STORAGE=sqlserver`) |
| `MEMORY_MAX_NAMESPACE_SIZE` | unlimited | Max entries per namespace |
| `MEMORY_MAX_TOTAL_COUNT` | unlimited | Max total entries across all namespaces |

## NuGet / GitHub Packages

The server ships as a `dotnet` global tool, and the core engine as a library you can embed in your
own .NET applications.

**Server (global tool)**

```bash
dotnet tool install --global McpEngramMemory --version 2.0.0
engram-memory
```

**Core engine (library)**

```bash
# nuget.org
dotnet add package McpEngramMemory.Core --version 2.0.0

# GitHub Packages
dotnet add package McpEngramMemory.Core --version 2.0.0 \
  --source https://nuget.pkg.github.com/wyckit/index.json
```

#### Optional: in-process synthesis

`synthesize_memories` generates through an `ITextGenerator`. The server ships one implementation —
`OllamaClient`, talking to a local Ollama daemon. If you want generation fully in-process with no
daemon, add the optional ONNX backend when embedding the library:

```bash
dotnet add package McpEngramMemory.Synthesis.Onnx --version 2.0.0
```

```csharp
using McpEngramMemory.Core.Services.Synthesis;

ITextGenerator generator = new OnnxGenAiTextGenerator(modelDir); // stage a model first
```

It lives in its own package because ONNX Runtime GenAI ships native binaries for every platform it
supports — roughly 500 MB. Keeping it separate means neither the `McpEngramMemory` tool nor a plain
`McpEngramMemory.Core` install pays that cost. Stage a model with
`scripts/fetch-synthesis-model.ps1`.

> The `McpEngramMemory` **server** does not support `SYNTHESIS_BACKEND=onnx`; it fails at startup
> with a pointer to this package. In-process synthesis is for hosts embedding the Core library.

```csharp
using McpEngramMemory.Core.Models;
using McpEngramMemory.Core.Services;
using McpEngramMemory.Core.Services.Storage;

var persistence = new PersistenceManager();
var embedding = new OnnxEmbeddingService();
var index = new CognitiveIndex(persistence);

// "" is the legacy (single-tenant) partition. Pass a real tenant id to isolate.
const string tenant = "";

// Store
var vector = embedding.Embed("The capital of France is Paris");
var entry = new CognitiveEntry(
    "fact-1", vector, "default", "The capital of France is Paris", "facts", tenantId: tenant);
index.Upsert(entry);

// Search — tenantId is required as of 2.0
var results = index.Search(embedding.Embed("French capital"), "default", tenant, k: 5);
```

## Documentation

| Doc | Description |
|-----|-------------|
| [First 5 Minutes](docs/first-5-minutes.md) | Store, close, recall — the whole loop |
| [Cheat Sheet](docs/cheat-sheet.md) | One-page quick reference |
| [MCP Tools Reference](docs/mcp-tools-reference.md) | Full documentation for all 63 tools |
| [Architecture](docs/architecture.md) | System design, retrieval pipeline, data flow |
| [Cognitive Constitution](docs/cognitive-constitution.md) | Governed Core boundary, knowledge/provenance, learning, planning, assets, persistence, and current tenant limits |
| [Services](docs/services.md) | All services with descriptions |
| [Internals](docs/internals.md) | Retrieval, quantization, persistence deep dive |
| [Project Structure](docs/project-structure.md) | File tree and module organization |
| [AI Assistant Setup](docs/ai-assistant-setup.md) | Step-by-step setup prompts for each tool |
| [Sample Prompts](docs/prompts.md) | Power prompts and usage patterns |
| [Benchmarks](docs/benchmarks.md) | IR quality results and mode selection guide |
| [MRCR v2 Benchmark](docs/benchmarks-mrcr.md) | Long-context A/B (full context vs. hybrid retrieval) via Claude CLI subscription |
| [Testing](docs/testing.md) | Test coverage breakdown and current CI coverage |
| [2.0.0 Release Notes](docs/release-notes-2.0.0.md) | What changed in 2.0, why it is major, and how to migrate an embedding host |
| [Tenant Isolation Design](docs/tenant-isolation-design.md) | Partitioning model, guarantees, and the 2.0 required-`tenantId` boundary |
| [Changelog](CHANGELOG.md) | Full release history |

## Build & Test

```bash
cd mcp-engram-memory
dotnet build
dotnet test    # full suite, including slower MSA benchmark cases
```

## Tech Stack

- .NET 8/9/10, C#
- [ModelContextProtocol](https://www.nuget.org/packages/ModelContextProtocol) 2.2.0
- [FastBertTokenizer](https://www.nuget.org/packages/FastBertTokenizer) 1.0.28
- [Microsoft.ML.OnnxRuntime](https://www.nuget.org/packages/Microsoft.ML.OnnxRuntime) 1.29.0
- [bge-micro-v2](https://huggingface.co/TaylorAI/bge-micro-v2) ONNX (384-dim, MIT license)
- [Microsoft.Data.Sqlite](https://www.nuget.org/packages/Microsoft.Data.Sqlite) 10.0.11
- xUnit v3 (tests)

## License

MIT
