Skip to content

Latest commit

 

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Session Memory MCP Server

Crates.io License ADK-Rust Enterprise Registry Ready

A Model Context Protocol (MCP) server that gives AI agents memory that lasts. Built in Rust with rmcp for the protocol layer and SQLite for storage — no database server to run.

14 tools covering semantic recall, embedding disclosure, provenance-tracked writes, confirmation of inferred facts, temporal supersession, PII redaction, typed session state, replay snapshots, and resumable human-in-the-loop workflows.

Install

cargo install --git https://github.com/zavora-ai/mcp-session-memory --tag v1.3.0

The tagged GitHub install provides the trained local model in this release immediately. The unqualified cargo install mcp-session-memory command may resolve to an older crates.io release.

This compiles and installs the binary to ~/.cargo/bin/mcp-session-memory.

Requires Rust 1.94.1 or newer. The default embedding model downloads once on first start and then runs locally from cache.

Quick start

# Remember across restarts. Without MEMORY_DB, memory lasts only for this run.
export MEMORY_DB=~/.agent-memory.db
mcp-session-memory

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "session-memory": {
      "command": "mcp-session-memory",
      "env": { "MEMORY_DB": "/Users/you/.agent-memory.db" }
    }
  }
}

Kiro / Cursor

Same shape, in .kiro/settings/mcp.json or .cursor/mcp.json:

{
  "mcpServers": {
    "session-memory": {
      "command": "mcp-session-memory",
      "env": { "MEMORY_DB": "${HOME}/.agent-memory.db" }
    }
  }
}

Features

  • SQLite persistence included by default — set MEMORY_DB to keep memories, sessions, events and snapshots in one file; without it the server explicitly uses run-local storage
  • Workflows survive restarts — a run paused for a human approval is still paused tomorrow
  • Semantic recall — "how should invoicing be handled" finds "always send invoices as a PDF"
  • Trained local embeddings — quantized all-MiniLM-L6-v2 runs in process and recovers synonymy; model files download once and are then reusable offline
  • Runtime disclosureget_embedding_status reports the active backend, dimensions, locality, synonym support, and fallback limitation
  • Provenance on every writetold, observed, corrected or imported, so you can audit why an agent believes something
  • Confirmation gate — anything inferred is held as proposed and cannot influence the agent until confirmed
  • Temporal supersession — a memory that stops being true is superseded and linked, not erased
  • Automatic deduplication — the same fact told twice reinforces one memory instead of creating two
  • Settledness ranking — repeatedly confirmed memories are recalled first
  • Subject scoping — memory is partitioned by subject; one user's facts never reach another's
  • Five memory types — turn, session state, profile, project, artifact
  • Data classification — public, internal, PII, financial, health, legal-sensitive
  • PII redactionredact_memory scrubs sensitive spans in place
  • Replay snapshots — freeze session state for deterministic replay
  • Resumable HITL — pause for approval, resume where you left off
  • MCP 2025 + 2026 — stdio compatibility for both revisions, with Tasks, structured results, annotations, cache metadata, and sealed MRTR approvals

Configuration

Variable Default Purpose
MEMORY_DB (none) Path to the SQLite file holding memories, sessions, events and snapshots. Unset means everything lasts only for this run, the server warns you at startup, and a worked example is seeded so you can try the tools
MCP_MEMORY_EMBEDDER local-model local-model uses quantized MiniLM. Set lexical only when a trained model cannot be used; the tool surface then discloses that synonyms are not reliable
FASTEMBED_CACHE_DIR .fastembed_cache Model cache location; HF_HOME takes precedence
HF_ENDPOINT Hugging Face Optional model mirror for restricted networks
MCP_REQUEST_STATE_KEY (none) At least 32 high-entropy bytes, required for protected MCP 2026 writes
RUST_LOG info Tracing filter, e.g. mcp_session_memory=debug

Cargo features: sqlite and local-model are enabled by default. all-backends is retained as an alias for both supported components; this release does not claim unimplemented Redis or Postgres storage.

Architecture

Session Memory MCP Server architecture

A request arrives over stdio and lands on one of 14 tools. Reads go through the recall path, which embeds the query and ranks stored memories by similarity. Writes go through the confirmation gate, which decides whether a memory acts immediately or waits to be agreed to. Both then reach the store traits, and whichever backend is configured behind them.

Everything durable lives in one file: memories with their vectors, session state, the event trail, and replay snapshots. One artefact to back up, move or delete, and no daemon to run.

src/
├── main.rs             Entry point — transport, backend selection, MEMORY_DB
├── server.rs           MCP tool router — 14 tools registered
├── lib.rs              Crate root
├── error.rs            Error types
├── types.rs            Session, MemoryEntry, Provenance, MemoryStatus, DataClass
├── store.rs            MemoryStore and SessionStore traits
├── semantic.rs         Embedder trait, trained MiniLM default, explicit lexical fallback
├── memory_store.rs     In-memory backend — this run only
├── sqlite_store.rs     Memories and vectors in one file
└── sqlite_sessions.rs  Sessions, events and snapshots in the same file

Where the design decisions live

Decision File Why
Recall by meaning semantic.rs Quantized all-MiniLM-L6-v2 sentence vectors recover rewording and synonyms
Local by default semantic.rs Model inference remains in process; only model files are downloaded on first use
Backend disclosure server.rs get_embedding_status makes semantic capability and fallback limits visible to the agent
Vector migration sqlite_store.rs Stored memories are re-embedded transactionally when the model identity changes
Confirmation gate types.rs, server.rs Provenance::acts_immediately is the single place that decides
Supersession types.rs MemoryStatus::Superseded plus superseded_by, so history stays answerable
One durable file sqlite_store.rs, sqlite_sessions.rs A paused workflow and what the agent learned must survive together

How memory works

Three design choices are worth knowing about, because they change how you use the tools.

Recall is by meaning

retrieve_memory embeds your query and ranks stored memories by cosine similarity, so a question worded differently still finds the right fact.

The default embedder is the quantized sentence-transformers/all-MiniLM-L6-v2 model through FastEmbed and ONNX. Model files download on first use, are cached locally, and inference never sends memory text to a hosted embedding API. A real inference smoke test verifies that a query using cheap ranks a memory using inexpensive above an unrelated sentence.

MCP_MEMORY_EMBEDDER=lexical selects the legacy hashed word/trigram implementation explicitly. It is deterministic and needs no model file, but it cannot reliably recover synonyms. That limitation appears in the retrieve_memory tool description and in get_embedding_status, not only in this README.

When a query matches nothing above the active model's relevance floor, recall returns an empty list. It never presents an unrelated memory as a semantic hit. Omit query when the intended operation is to list what is known about the subject, most settled first.

Inferred facts wait for confirmation

Every write carries a provenance:

Provenance Meaning Takes effect
told The subject said it themselves Immediately
observed Inferred from what they did After confirm_memory
corrected Learned from a correction After confirm_memory
imported Came from another system After confirm_memory

Anything but told is stored as proposed, and proposed memories are never returned by recall. So an agent cannot quietly acquire beliefs its user never gave it — and a stray instruction inside a document cannot install itself as a permanent preference.

One file holds everything durable

MEMORY_DB covers memories and session state, events and replay snapshots. That matters most for human-in-the-loop work: a workflow paused for an approval is still paused after a restart, at the state version it reached, with its typed state intact — which is what makes resume_session mean anything.

It also means an operator has one artefact to back up, move, or delete.

Nothing true is thrown away

When a fact changes, use supersede_memory rather than delete_memory. It writes the replacement, marks the old entry superseded, and links the two. The old memory stops being recalled but stays on the record, so an agent asked why did you do that? can still answer. delete_memory is there for when erasure is genuinely what you want.

Tools (14)

Tool Purpose Risk Class
get_session_state Read current typed session state Read-only
list_session_events Inspect operational events Read-only
retrieve_memory Recall scoped memory by meaning Read-only
get_embedding_status Disclose the active model and semantic limitations Read-only
store_memory Remember something, with its provenance Internal write
confirm_memory Agree to a memory that was inferred Internal write
supersede_memory Record that a memory is no longer true Internal write
update_memory Correct existing memory (new version) Internal write
delete_memory Remove sensitive/incorrect entries Identity/Security
redact_memory Redact PII from memory Internal write
list_memory_refs List memory that influenced a session Read-only
create_replay_snapshot Freeze session state for replay Internal write
resume_session Resume paused HITL workflow External write
terminate_session Stop session with audit reason External write

Examples

Get session state

Prompt: "What's the current state of the refund session?"

{
  "session_id": "ses_demo_001",
  "agent_id": "support_agent",
  "status": "paused",
  "current_node": "manager_approval_gate",
  "state_version": 3,
  "workflow_state": {
    "refund_amount": 89.99,
    "eligibility": "approved",
    "approval_required": true
  },
  "memory_refs": ["mem_demo_001"],
  "data_classes": ["financial"]
}

Recall by meaning

Prompt: "How does this customer like to be contacted?"

Tool call: retrieve_memory

{
  "subject_type": "customer",
  "subject_id": "cust_1187",
  "query": "how does this customer like to be contacted"
}

The stored memory says "prefers email follow-up" — no word in common with the question except "customer", and it still comes back first. Omit query to get everything known about the subject, most settled first.

Output:

[
  {
    "memory_id": "mem_demo_001",
    "memory_type": "profile_memory",
    "content": "Customer prefers email follow-up. Previous refund approved in March 2026.",
    "data_class": "pii",
    "confidence": 0.91,
    "version": 1,
    "status": "active"
  }
]

Store a new memory

Prompt: "Remember that this customer's preferred language is Swahili"

{
  "memory_type": "profile_memory",
  "subject_type": "customer",
  "subject_id": "cust_1187",
  "content": "Preferred language: Swahili",
  "data_class": "pii",
  "provenance": "told",
  "confidence": 0.95
}

Output:

{ "memory_id": "mem_a1b2c3d4...", "status": "stored", "message": "Stored." }

Told the same thing again, it reinforces rather than duplicating:

{
  "memory_id": "mem_a1b2c3d4...",
  "status": "already_known",
  "reinforcements": 1,
  "message": "A memory this close already exists; it has been reinforced rather than duplicated."
}

Store something you inferred

Prompt: "They've shortened my summaries three times — remember they like them brief"

{
  "memory_type": "profile_memory",
  "subject_type": "user",
  "subject_id": "u_42",
  "content": "Prefers summaries under 150 words",
  "provenance": "observed"
}

Output:

{
  "memory_id": "mem_9f8e7d6c...",
  "status": "awaiting_confirmation",
  "message": "Held until someone confirms it. It will not influence anything yet."
}

Call confirm_memory with that id and it starts being recalled.

Record that something changed

Prompt: "Payment terms moved from net 30 to net 60"

{
  "memory_id": "mem_terms_001",
  "content": "Net 60 terms for all customers",
  "reason": "policy changed Q3"
}

Output:

{
  "superseded": "mem_terms_001",
  "replaced_by": "mem_terms_002",
  "reason": "policy changed Q3",
  "status": "superseded"
}

Resume a paused workflow

Prompt: "The manager approved the refund, resume the session"

{
  "session_id": "ses_demo_001",
  "resume_payload": { "approval_decision": "approved", "approver": "manager_jane" },
  "reason": "Manager approved refund"
}

Output:

{ "session_id": "ses_demo_001", "status": "active", "resumed": true }

Create replay snapshot

Prompt: "Freeze this session state for replay testing"

{ "session_id": "ses_demo_001" }

Output:

{
  "snapshot_id": "snap_f7a2b1c4...",
  "session_id": "ses_demo_001",
  "state_version": 3
}

Terminate with audit reason

Prompt: "Stop this session — suspected policy violation"

{
  "session_id": "ses_demo_001",
  "reason": "Suspected policy violation during refund flow",
  "reason_code": "policy_violation"
}

Output:

{ "session_id": "ses_demo_001", "status": "terminated", "reason": "Suspected policy violation..." }

Memory Types

Type Description Mutability
turn_memory Recent conversational context Mutable during session
session_state Typed workflow state Versioned
profile_memory User/customer facts across sessions Policy-governed
project_memory Workspace decisions and preferences Policy-governed
artifact_memory References to artifacts (not content) References only

Build from source

git clone https://github.com/zavora-ai/mcp-session-memory
cd mcp-session-memory
cargo build --release
cargo test

Contributors


James Karanja Maina

License

Apache-2.0 — see LICENSE for details.


Part of the ADK-Rust Enterprise MCP server ecosystem.

Built with ❤️ by Zavora AI

Registry Compliance

This server implements the ADK MCP SDK contract:

  • HealthCheck — async health probe for registry monitoring
  • mcp-server.toml — manifest declaring tools, risk classes, and credentials
  • Structured tracingRUST_LOG env-filter for observability

rmcp and MCP compatibility

This server is built with rmcp 3.1.2 and requires Rust 1.94.1 or newer. The rmcp 3 rollout retains legacy MCP initialization compatibility and targets MCP protocol revisions 2025-11-25 and 2026-07-28.

MCP 2026-07-28 rollout (P4 workflow/business)

This server uses exact rmcp 3.1.2 and adk-mcp-sdk 0.3 with a minimum supported Rust version of 1.94.1. It accepts stateless MCP 2026 requests with per-request protocol, client identity, and capability metadata while retaining the legacy MCP 2025-11-25 initialize flow for ordinary tools.

  • Structured results: all 14 tools advertise output schemas and annotations; MCP 2026 clients receive parsed structuredContent, and { "ok": false } responses are marked as errors.
  • Tasks: retrieve_memory, store_memory, supersede_memory, update_memory, and redact_memory, each with a 10-minute TTL and progress status.
  • MRTR approvals: delete_memory, redact_memory, resume_session, terminate_session
  • Discovery and routing: rmcp serves on-demand discovery and validates the per-request protocol envelope; HTTP deployments can route with Mcp-Method and Mcp-Name. The packaged binary currently uses stdio.
  • Caching: tools/list returns a public ttlMs of 86,400,000 for MCP 2026; rmcp omits the cache fields for legacy clients.
  • Deprecated extensions: this server does not add new Roots, Sampling, or dynamic client-registration dependencies.

Protected tools require MCP_REQUEST_STATE_KEY with at least 32 high-entropy bytes. All replicas must share that key so sealed approval state can resume on another instance. Approval state is bound to the client identity, tool, and arguments and expires after two minutes. Missing identity, invalid state, rejection, or legacy protocol use fails closed. Task records are process-local for the current stdio runtime; use a durable task store before deploying the server behind scale-to-zero HTTP infrastructure.

About

Session Memory MCP server for ADK-Rust Enterprise — typed session state, scoped memory, replay snapshots, resumable workflows

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages