MCP Memory Server

stonemem Documentation

Institutional memory for AI agents. FTS5 search, entity graphs, temporal scoring, supersession chains. Your agents remember everything — and know what matters now.

1. Overview

stonemem is a compiled Rust binary that runs as a local MCP (Model Context Protocol) server, providing persistent, searchable memory to any AI agent platform. It stores structured entries in a SQLite database with WAL mode, offering full-text search via FTS5, automatic entity extraction, temporal relevance scoring, and supersession chains that keep knowledge current.

Key Capabilities

  • Full-text search (FTS5) — BM25-ranked retrieval across all stored entries. Finds what your agent wrote three weeks ago in under 1ms.
  • Entity extraction — Automatically identifies people, projects, technologies, URLs, and other entities from stored content. Builds a queryable relationship graph.
  • Temporal scoring — Recent knowledge ranks higher. An entry from yesterday outweighs one from last month on the same topic, unless the older one is pinned.
  • Supersession chains — When facts change, new entries supersede old ones. Your agent always gets the current state, not the historical noise.
  • Namespace isolation — Each agent can write to its own namespace for private storage, or use shared namespaces for cross-agent knowledge.
  • Auto-deduplication — Duplicate or near-duplicate entries are detected and merged on save.
  • Agent registry — Track which agents are active, their roles, and session IDs.

Architecture

stonemem runs as a single-process HTTP server on port 3391 (configurable). All data is stored locally in a SQLite database — nothing leaves your machine. The MCP transport layer allows any MCP-compatible agent framework to connect directly via stdio or HTTP.

Data locality guarantee: stonemem never phones home, never uploads data, and never requires an internet connection to function. Your agent's memory stays on your infrastructure.

2. Installation

macOS (Homebrew)

brew install keystoneproject/tap/stonemem

macOS (Direct Download)

# Apple Silicon (M1/M2/M3/M4)
curl -L https://keystoneproject.dev/releases/stonemem/darwin-aarch64/stonemem-v1.1.0-darwin-aarch64.tar.gz | tar xz
sudo mv stonemem /usr/local/bin/

# Intel
curl -L https://keystoneproject.dev/releases/stonemem/darwin-x86_64/stonemem-v1.1.0-darwin-x86_64.tar.gz | tar xz
sudo mv stonemem /usr/local/bin/

Linux

# x86_64
curl -L https://keystoneproject.dev/releases/stonemem/linux-x86_64/stonemem-v1.1.0-linux-x86_64.tar.gz | tar xz
sudo mv stonemem /usr/local/bin/

# ARM64 (aarch64)
curl -L https://keystoneproject.dev/releases/stonemem/linux-aarch64/stonemem-v1.1.0-linux-aarch64.tar.gz | tar xz
sudo mv stonemem /usr/local/bin/

Verify Installation

stonemem --version
# stonemem 1.1.0

3. Quick Start

Step 1: Activate your license

Every installation requires a license key, including the free tier. You receive your key via email after checkout.

# Activate with your license key
stonemem activate --key SM-XXXX-XXXX-XXXX-XXXX

# Verify activation
stonemem status

Step 2: Start the server

# Start with default settings (port 3391, data in ~/.stonemem/)
stonemem serve

# Or specify a custom data directory
stonemem serve --data-dir /path/to/data --port 3391

Step 3: Connect your agent

Add stonemem to your agent's MCP configuration:

{
  "mcpServers": {
    "stonemem": {
      "command": "stonemem",
      "args": ["serve"],
      "transport": "stdio"
    }
  }
}

Or connect via HTTP:

{
  "mcpServers": {
    "stonemem": {
      "url": "http://localhost:3391",
      "transport": "http"
    }
  }
}

Step 4: Test it

# Save an entry
curl -X POST http://localhost:3391/save \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "test-agent", "content": "The database migration runs at 3am UTC every Tuesday.", "tags": ["operations", "database"]}'

# Search for it
curl -X POST http://localhost:3391/search \
  -H "Content-Type: application/json" \
  -d '{"query": "database migration schedule"}'

4. Configuration

Configuration File

stonemem reads configuration from ~/.stonemem/config.toml (or the path specified by --config):

[server]
host = "127.0.0.1"
port = 3391
data_dir = "~/.stonemem"

[license]
key_file = "~/.stonemem/license.key"
license_server = "https://license.keystoneproject.dev"

[engine]
max_entry_size = 65536        # Maximum content size per entry (bytes)
dedup_threshold = 0.85        # Similarity threshold for deduplication (0.0-1.0)
entity_extraction = true      # Enable automatic entity extraction
temporal_decay_days = 90      # Days after which temporal score begins decaying

[logging]
level = "info"                # trace, debug, info, warn, error
format = "json"               # json or text

Environment Variables

All configuration can be overridden via environment variables with the STONEMEM_ prefix:

STONEMEM_PORT=3391
STONEMEM_DATA_DIR=/var/lib/stonemem
STONEMEM_LOG_LEVEL=debug

Command Line Options

stonemem serve [OPTIONS]

OPTIONS:
    --port           Server port [default: 3391]
    --host           Bind address [default: 127.0.0.1]
    --data-dir       Data directory [default: ~/.stonemem]
    --config         Config file path
    --log-level     Log level (trace/debug/info/warn/error)

5. API Reference

All endpoints accept and return JSON. The server listens on http://localhost:3391 by default.

POST /save

Save an entry to memory. Automatically extracts entities, checks for duplicates, and assigns temporal scores.

Request Body

{
  "agent_id": "string",           // Required. Agent identifier.
  "content": "string",            // Required. The content to store.
  "namespace": "string",          // Optional. Default: "default".
  "tags": ["string"],             // Optional. Metadata tags for filtering.
  "supersedes": 123               // Optional. ID of entry this replaces.
}

Response

{
  "id": 42,
  "status": "saved",
  "entities_extracted": ["PostgreSQL", "migration", "UTC"],
  "deduplicated": false
}

Tier Limits

  • Free: 10,000 entries, 1 namespace
  • Pro: Unlimited entries, unlimited namespaces
  • Enterprise: Same as Pro + shared memory features
POST /search

Full-text search across stored entries using FTS5 with BM25 ranking.

Request Body

{
  "query": "string",              // Required. FTS5 search query.
  "agent_id": "string",           // Optional. Filter by agent.
  "namespace": "string",          // Optional. Default: "default".
  "limit": 10,                    // Optional. Max results. Default: 10.
  "tags": ["string"],             // Optional. Filter by tags.
  "time_range": {                 // Optional. Filter by time window.
    "start": "2026-01-01T00:00:00Z",
    "end": "2026-06-01T00:00:00Z"
  }
}

Response

{
  "results": [
    {
      "id": 42,
      "content": "The database migration runs at 3am UTC...",
      "agent_id": "ops-agent",
      "namespace": "default",
      "tags": ["operations", "database"],
      "score": 12.45,
      "created_at": "2026-06-01T12:00:00Z"
    }
  ],
  "total": 1
}
POST /recall

Temporal recall — retrieves the most relevant recent entries for a query, weighted by recency.

Request Body

{
  "query": "string",              // Required. What to recall.
  "agent_id": "string",           // Optional. Filter by agent.
  "namespace": "string",          // Optional. Default: "default".
  "limit": 5,                     // Optional. Max results. Default: 5.
  "time_window": "7d"             // Optional. Look back period (e.g., "7d", "30d", "1h").
}

Response

{
  "results": [
    {
      "id": 42,
      "content": "...",
      "temporal_score": 0.95,
      "relevance_score": 8.2,
      "combined_score": 14.6
    }
  ]
}
POST /entity/query

Query the entity graph — find people, projects, technologies mentioned across entries.

Request Body

{
  "query": "string",              // Required. Entity name or partial match.
  "entity_type": "string",        // Optional. Filter: "person", "project", "technology", etc.
  "limit": 10                     // Optional. Max results. Default: 10.
}

Response

{
  "entities": [
    {
      "id": 7,
      "name": "PostgreSQL",
      "entity_type": "technology",
      "mention_count": 34,
      "first_seen": "2026-03-15T09:00:00Z",
      "last_seen": "2026-06-10T04:00:00Z"
    }
  ],
  "total": 1
}

Pro/Enterprise only. Entity queries require a Pro or Enterprise license. Free tier returns a 402 response.

POST /agent/register

Register an agent with the memory server. Tracks active agents, their roles, and session IDs.

Request Body

{
  "agent_id": "string",           // Required. Unique agent identifier.
  "role": "string",               // Optional. Agent role description.
  "session_id": "string"          // Optional. Current session ID.
}
POST /agent/deregister

Deregister an agent from the memory server.

Request Body

{
  "agent_id": "string"            // Required.
}
GET /agents

List all registered agents with their status, roles, and last-seen timestamps.

Response

{
  "agents": [
    {
      "id": "research-agent",
      "role": "Research and analysis",
      "session_id": "sess-abc123",
      "registered_at": "2026-06-10T02:00:00Z",
      "last_seen": "2026-06-10T04:30:00Z",
      "status": "active"
    }
  ]
}
GET /stats

Server statistics — entry counts, namespace counts, database size, daily usage.

Response

{
  "entry_count": 15234,
  "namespace_count": 8,
  "agent_count": 3,
  "entity_count": 1204,
  "db_size": 45678912,
  "today_saves": 127,
  "today_recalls": 342,
  "today_searches": 89
}
GET /health

Health check endpoint. Returns server status, version, and license tier.

Response

{
  "status": "ok",
  "version": "1.1.0",
  "tier": "pro",
  "uptime_seconds": 86400
}

6. MCP Tool Reference

When connected as an MCP server, stonemem exposes the following tools to your agent:

mem_save

Save structured content to memory with automatic entity extraction and deduplication.

Tool: mem_save
Parameters:
  - content (string, required): Content to store
  - namespace (string, optional): Namespace for isolation. Default: "default"
  - tags (array of strings, optional): Metadata tags
  - supersedes (integer, optional): ID of entry to replace

Example:
  mem_save({
    content: "Sprint 14 shipped the auth middleware rewrite. Uses ed25519 now.",
    namespace: "engineering",
    tags: ["sprint-14", "auth", "security"]
  })

Full-text search with BM25 ranking, tag filtering, and time range support.

Tool: mem_search
Parameters:
  - query (string, required): Search query
  - namespace (string, optional): Namespace to search
  - limit (integer, optional): Max results (default 10)
  - tags (array of strings, optional): Filter by tags
  - time_range (object, optional): { start, end } ISO timestamps

Example:
  mem_search({ query: "auth middleware ed25519", limit: 5 })

mem_recall

Temporal recall — combines relevance and recency for the most useful results.

Tool: mem_recall
Parameters:
  - query (string, required): What to recall
  - namespace (string, optional): Namespace
  - limit (integer, optional): Max results (default 5)
  - time_window (string, optional): Look back period (e.g., "7d")

Example:
  mem_recall({ query: "deployment schedule", time_window: "30d" })

mem_entity_query

Query the entity graph for people, projects, technologies, and their relationships.

Tool: mem_entity_query
Parameters:
  - query (string, required): Entity name or partial
  - entity_type (string, optional): Filter type
  - limit (integer, optional): Max results (default 10)

Example:
  mem_entity_query({ query: "PostgreSQL", entity_type: "technology" })

7. Use Cases by Platform

Claude Code / Hermes

Session Continuity Across Conversations

Claude Code sessions lose context when the conversation ends. With stonemem, critical decisions, architectural choices, and debugging findings persist across sessions.

// Agent saves a decision
mem_save({
  content: "Decided to use ed25519 for license keys instead of RSA. Reason: faster signing, smaller keys, no padding oracle attacks.",
  namespace: "architecture",
  tags: ["decision", "cryptography"]
})

// Three days later, a new session recalls it
mem_recall({ query: "license key signing algorithm decision" })
// Returns: "Decided to use ed25519 for license keys..."

Result: New sessions start warm, not cold. The agent doesn't re-derive decisions already made.

CrewAI

Shared Knowledge Across Crew Members

In a CrewAI crew with a Researcher, Writer, and Editor, all three agents share knowledge through stonemem's shared namespaces.

// Researcher agent stores findings
mem_save({
  content: "Market analysis: AI agent infrastructure growing 340% YoY. Key players: LangChain, CrewAI, Haystack.",
  namespace: "shared-research",
  tags: ["market", "competitive-intel"]
})

// Writer agent recalls research without re-searching
mem_recall({ query: "AI agent market growth", namespace: "shared-research" })

Result: Crew members build on each other's work instead of repeating research.

LangGraph

State Persistence Across Graph Executions

LangGraph workflows can checkpoint state into stonemem, enabling recovery and cross-run learning.

// Save workflow state at a checkpoint
mem_save({
  content: JSON.stringify({ step: "validation", results: validationResults }),
  namespace: "workflow-runs",
  tags: ["workflow-id-abc123", "checkpoint"]
})

// On retry or next run, recall previous state
mem_search({
  query: "workflow validation results",
  namespace: "workflow-runs",
  tags: ["workflow-id-abc123"]
})

Result: Failed workflows resume from the last checkpoint instead of starting over.

OpenHands

Codebase Knowledge Accumulation

OpenHands agents exploring a large codebase store architectural insights for future reference.

// Agent discovers something non-obvious about the codebase
mem_save({
  content: "The auth module at src/auth/ uses a custom JWT implementation (not a library) because of FIPS compliance requirements. Do not replace with jsonwebtoken crate.",
  namespace: "codebase-knowledge",
  tags: ["auth", "constraint", "compliance"],
  supersedes: 12  // Replaces an earlier, less accurate understanding
})

Result: Future agents don't waste time trying to "fix" intentional design decisions.

Google ADK

Multi-Agent Memory Federation

Google ADK agents running across different services share institutional knowledge through stonemem's namespace federation (Enterprise tier).

// Customer service agent logs a product issue pattern
mem_save({
  content: "3 customers this week reported timeout errors on the /api/export endpoint when exporting > 10k rows. Engineering aware, fix in sprint 22.",
  namespace: "customer-issues",
  tags: ["export", "performance", "sprint-22"]
})

// Product team agent reviews customer pain points
mem_search({
  query: "customer reported issues performance",
  namespace: "customer-issues",
  time_window: "30d"
})
Haystack

RAG Pipeline Enhancement

Enhance Haystack RAG pipelines by caching retrieval results and user feedback in stonemem.

// Cache a successful retrieval pattern
mem_save({
  content: "Query 'quarterly revenue' maps best to documents in the finance/reports/ collection, not the general knowledge base.",
  namespace: "rag-patterns",
  tags: ["routing", "finance"]
})

// Use cached patterns to improve routing
mem_recall({ query: "quarterly revenue document routing", namespace: "rag-patterns" })
Microsoft Agent Framework

Enterprise Agent Fleet Coordination

In large enterprise deployments with hundreds of agents, stonemem provides the shared memory layer that prevents duplicated work and conflicting actions.

// Compliance agent records an audit finding
mem_save({
  content: "PCI DSS audit finding: S3 bucket acme-prod-logs has public read ACL. Ticket JIRA-4521 created. Deadline: 2026-06-30.",
  namespace: "compliance",
  tags: ["pci-dss", "s3", "critical"]
})

// Security agent checks for open findings before its scan
mem_search({
  query: "open compliance findings s3",
  namespace: "compliance",
  tags: ["critical"]
})
// Avoids duplicating the ticket
All Platforms

Entity Graph for Organizational Knowledge

Over time, stonemem builds an entity graph that maps the relationships between people, projects, technologies, and decisions in your organization.

// After months of agent activity, query the entity graph
mem_entity_query({ query: "PostgreSQL" })
// Returns: mentioned 34 times, first seen March 2026, linked to:
//   - "migration" (co-occurrence: 28 times)
//   - "performance" (co-occurrence: 12 times)
//   - "Alice Chen" (person, 8 co-occurrences — she's the DBA)

mem_entity_query({ query: "Alice Chen", entity_type: "person" })
// Returns: mentioned 45 times, linked to PostgreSQL, infrastructure, on-call

8. Tier Comparison

FeatureFreePro ($9/mo)Enterprise ($49/mo)
Entries10,000UnlimitedUnlimited
Namespaces1 ("default")UnlimitedUnlimited
Full-text search (FTS5)YesYesYes
Basic recallYesYesYes
Entity graphNoYesYes
Temporal scoringNoYesYes
Supersession chainsNoYesYes
Multi-agent shared memoryNoNoYes
Team namespace federationNoNoYes
Usage analyticsNoNoYes
Daily heartbeatYesYesYes
SupportCommunityPriority emailPriority email

All tiers require license registration. There is no anonymous usage. Free keys are issued instantly via Stripe checkout ($0).

9. License Management

Activation

# Activate with your key (received via email after checkout)
stonemem activate --key SM-XXXX-XXXX-XXXX-XXXX

# Check license status
stonemem status

# Output:
# License: Active
# Tier: Pro
# Key: SM-XXXX-****-****-XXXX
# Activated: 2026-06-10T04:00:00Z
# Next heartbeat: 2026-06-11T04:00:00Z

Heartbeat

stonemem sends a daily heartbeat to the license server. This is telemetry only — a missing heartbeat does not disable your software. The heartbeat reports:

  • License key hash (not the full key)
  • Current tier
  • Entry count
  • Version

No content, no queries, no agent data. The heartbeat response may carry a SIGIL die command if the key has been revoked.

Upgrading

# Upgrade from Free to Pro
# 1. Purchase Pro license at https://keystoneproject.dev/#pricing
# 2. You'll receive a new key via email
# 3. Activate the new key
stonemem activate --key SM-YYYY-YYYY-YYYY-YYYY

# Your data is preserved — only the tier changes

Key Revocation (SIGIL)

If a key is revoked (e.g., due to fraud or chargeback), the license server sends a SIGIL die command via the heartbeat response. The binary will gracefully shut down and require reactivation with a valid key.

10. Troubleshooting

Common Issues

Port already in use

# Check what's using port 3391
lsof -i :3391

# Use a different port
stonemem serve --port 3392

License activation fails

# Verify internet connectivity to license server
curl https://license.keystoneproject.dev/health

# Check key format (should be SM-XXXX-XXXX-XXXX-XXXX)
stonemem activate --key SM-XXXX-XXXX-XXXX-XXXX --verbose

Database locked errors

stonemem uses WAL mode, which supports concurrent reads. If you see lock errors, ensure only one stonemem process is writing to the same data directory.

# Check for multiple processes
ps aux | grep stonemem

# If stuck, the WAL can be checkpointed manually
sqlite3 ~/.stonemem/stonemem.db "PRAGMA wal_checkpoint(TRUNCATE);"

Free tier limit reached

# Check current usage
curl http://localhost:3391/stats

# If entry_count is near 10,000, upgrade to Pro
# Or delete old entries:
# (Note: stonemem does not expose a delete endpoint —
#  supersede old entries or upgrade to Pro for unlimited storage)

MCP connection issues

# Test HTTP connectivity
curl http://localhost:3391/health

# For stdio transport, verify the binary is in PATH
which stonemem

# Check logs for connection errors
stonemem serve --log-level debug

Getting Help