Skip to main content
Glama
fortytwo-guide

fortytwo-guide

by justfortytwo

@justfortytwo/memory

A standalone semantic-memory MCP server. It stores text "memories" with free-form provenance and recalls them by meaning (vector search), by keyword (FTS5), or by structured filter. Backed by SQLite + sqlite-vec, embeddings from a local Ollama model (or an opt-in remote provider).

It is persona-agnostic: no journal/persona/approval coupling, just a generic memory store and tool surface. Use it on its own, or through @justfortytwo/installer, which registers it in your project's .mcp.json.

What it stores

A memory is content plus provenance:

field

meaning

content

the text (embedded for recall)

source

where it came from — free-form (owner, web, tool:foo)

observed

how it was observed — free-form (stated, inferred, imported)

date

ISO date the memory pertains to (defaults to today, UTC)

tags

free-form tags for filtering

supersedes

id of a prior memory this one replaces (history is kept)

Recall is hybrid: recall (semantic), lexical (FTS5 keyword), and query (structured). reindex + recall_docs index/search a directory of markdown documents separately from the memory store.

Related MCP server: Cognio

MCP tools

The server registers under the id fortytwo-memory, so a consumer calls the tools as mcp__fortytwo-memory__<tool>:

tool

description

store

store a memory (+ provenance); set supersedes to replace one

query

structured query (source/observed/tag/time; live rows by default)

recall

semantic top-k recall by meaning

recall_docs

semantic recall over reindexed markdown

lexical

full-text keyword search (FTS5)

reindex

self-heal the doc index from a markdown directory

export_range

render a date range of memories to markdown

On connect, the server also sends usage instructions in the MCP initialize result: when to search vs. store, which search tool fits, how to correct a memory with supersedes, and reindex caveats. Hosts such as Claude Code add them to the model's context. The text lives in src/server.ts; update it when the tool surface changes.

Contract version

Consumers depend on the tool surface, not the internals. The contract is versioned:

import { MEMORY_TOOL_CONTRACT_VERSION, memoryToolContract } from '@justfortytwo/memory/contract';
  • A major change to a tool name, its required inputs, or its result shape is a contract break → bump MEMORY_TOOL_CONTRACT_VERSION. Siblings pin a caret range on @justfortytwo/memory, so a major bump forces an explicit opt-in.

  • Additive changes (new optional inputs, new tools) do not bump it.

memoryToolContract is the authoritative human-readable list of tools and their guarantees, kept in sync with the wire schema in src/tools.ts.

Embedder

The default embedder is OllamaEmbedder, which calls a local Ollama /api/embeddings endpoint.

OLLAMA_BASE_URL=http://localhost:11434   # default
EMBED_MODEL=qwen3-embedding:0.6b         # default model (1024-dim)

Pull the model once:

ollama pull qwen3-embedding:0.6b

If EMBED_MODEL is unset, the server falls back to a deterministic, dependency-free FakeEmbedder — useful for tests, CI, and first-run smoke checks with zero infra. (The vector tables are fixed at 1024-dim; a model with a different dimensionality requires a schema change.)

Other remote providers (opt-in)

Ollama stays the default. To use a remote OpenAI-compatible provider instead, set EMBED_PROVIDER=openai:

EMBED_PROVIDER=openai
EMBED_MODEL=text-embedding-3-small       # must be in the allowlist below
EMBED_API_KEY=sk-...                     # optional for self-hosted servers
EMBED_BASE_URL=https://api.openai.com/v1 # default for OpenAI/Voyage models; required otherwise

Only models that emit (or can be truncated to) 1024 dims are accepted, because the vector tables are fixed at that size. Any other EMBED_MODEL fails at startup with the accepted list:

EMBED_MODEL

Default EMBED_BASE_URL

Notes

text-embedding-3-small

https://api.openai.com/v1

truncated to 1024 via dimensions

text-embedding-3-large

https://api.openai.com/v1

truncated to 1024 via dimensions

voyage-3-large

https://api.voyageai.com/v1

1024 by default

BAAI/bge-m3

none — set EMBED_BASE_URL

self-hosted, e.g. vLLM; 1024 native

Qwen/Qwen3-Embedding-0.6B

none — set EMBED_BASE_URL

self-hosted, e.g. vLLM; no query instruction prefix is applied

For self-hosted servers the model must be served under exactly the name above (vLLM: --served-model-name).

Switching models on an existing database: two models with the same dimension do not share a vector space. Vectors already stored by another model are not comparable with new query vectors, and recall will not error — it will return plausible but wrong neighbours. Re-embed existing memories with the library's reembed(h, embedder, id) (one id at a time; no bulk command or MCP tool is provided) and re-run the reindex tool for docs after switching. New databases are unaffected.

Standalone usage

npm install @justfortytwo/memory

Prerequisites. Requires Node.js >= 20. The package depends on better-sqlite3 ^12, a native module that ships prebuilt binaries for LTS Node releases — on an unsupported Node version or platform, npm install will compile it from source (needs a C/C++ toolchain). It also needs an embedding source for real embeddings — a local (or remote) Ollama, or an opt-in remote provider; without EMBED_MODEL set it falls back to a deterministic FakeEmbedder (see Embedder). sqlite-vec ships as a bundled npm dependency — no manual SQLite-extension install is needed.

# build (once); the server runs the built JS, not TS
npm run build

# apply migrations to the DB (DB_PATH or ./memory.db)
DB_PATH=./memory.db npm run migrate

# run the MCP server over stdio
DB_PATH=./memory.db EMBED_MODEL=qwen3-embedding:0.6b fortytwo-memory

The bin is fortytwo-memory → dist/index.js. You can also run it with npx -y @justfortytwo/memory (it is published to npm).

Register in your own .mcp.json

To use the server in any MCP host, drop this into your project's .mcp.json with a real DB path:

{
  "mcpServers": {
    "fortytwo-memory": {
      "command": "npx",
      "args": ["-y", "@justfortytwo/memory"],
      "env": {
        "DB_PATH": "./memory.db",
        "EMBED_MODEL": "qwen3-embedding:0.6b",
        "OLLAMA_BASE_URL": "http://localhost:11434"
      }
    }
  }
}

OLLAMA_BASE_URL may point at a remote host. The embedder strips a trailing slash, so either form works — but prefer no trailing slash.

As a library

import { openDb, runMigrations, OllamaEmbedder, embedderFromEnv, store, recall, deleteByIds } from '@justfortytwo/memory';

const h = openDb('memory.db');
await runMigrations(h.k);
const embedder = new OllamaEmbedder();
// or choose from env exactly like the server does (EMBED_PROVIDER / EMBED_MODEL / ...):
// const embedder = embedderFromEnv();

await store(h, embedder, { content: 'the deploy script lives in scripts/deploy.sh', source: 'owner', observed: 'stated' });
const hits = await recall(h, embedder, 'how do I deploy?', 5);

deleteByIds(h, [hits[0].id]); // hard-delete (row + vector + FTS); returns the count removed

Deleting memories

deleteByIds(h, ids) hard-deletes memories — the row, its vector, and its FTS entry — so nothing resurfaces in recall/lexical/query. It is intentionally a library API and NOT an MCP tool: deletion is an owner-privileged operation, and exposing it to the assistant's turn loop would let prompt-injected content trick it into erasing memories. Selecting which ids to remove (by query, tag, date range, …) is the caller's job — see @justfortytwo/installer's forget.

Continuous enrichment

enrich(h, embedder, candidates) folds a batch of candidate memories into the store: it drops low-salience candidates, dedupes near-duplicates by meaning, and writes the survivors with provenance — honoring an explicit supersedes to replace a stale belief (history is kept, never a silent overwrite). enrichFromTurn(h, embedder, turn, extractor) runs an injected SalienceExtractor and feeds its candidates to enrich.

The salience extractor itself is model-driven and lives in the sibling @justfortytwo/salience engine (a SalienceExtractor with an injected LlmClient) — memory owns only the dedupe + write, never the model call.

Peer seams

memory depends on two sibling packages one-directionally (declared as optional peers, no cycle):

  • @justfortytwo/gate — memory ships GateApprovalStore (src/gate-approval-store.ts), a durable SQLite-backed implementation of gate's ApprovalStore + AuditLogger interfaces. Pass it to gate's decide(..., { store, audit }) to back the safety gate's one-shot approvals with memory's db instead of the gate's standalone JSONL store.

  • @justfortytwo/salience — the model-driven salience extractor injected into enrichFromTurn (see above).

Development

npm run build      # tsc
npm test           # vitest run
npm run test:watch # vitest

Set RUN_OLLAMA_TESTS=1 to run the opt-in live-Ollama embedder test.

License

MIT © 2026 Enrico Deleo


Created and maintained by Enrico Deleo.

Incremental library reads

memoryHead(h) returns { database, position }, using a persistent database identity and SQLite's AUTOINCREMENT high watermark (not timestamps or MAX(id)). memoryDelta(h, cursor, limit = 50) returns ascending insertion pages and the last reviewed position; it includes superseded rows as evidence and never skips unreturned rows. Deleted ID gaps remain safe. Invalid/foreign/backwards cursors fail closed. These are library APIs only; the MCP tool contract is unchanged.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      A local, fully-offline MCP memory server that enables persistent storage and retrieval of information using SQLite with both keyword and semantic vector search capabilities.
      10
      13 npm
      13
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Persistent semantic memory server for AI assistants via MCP, enabling long-term context retention and semantic search across conversations.
      12
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Semantic memory server for AI agent teams. Stores, searches, and retrieves knowledge across sessions using pluggable vector backends with local ONNX embeddings, exposed as an MCP server.
      MIT