npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@taraksh011/memoryhub

v0.9.0

Published

MCP server for persistent memory using Qdrant vector store

Readme

memoryhub

MCP server for persistent memory using Qdrant vector store.

Stores text memories with LLM-generated embeddings and retrieves them via semantic search.

Install

npm install @taraksh011/memoryhub

Or run directly:

npx @taraksh011/memoryhub

Quick Start

# Start Qdrant (see docs/install-qdrant.md for help)
docker run -p 6333:6333 qdrant/qdrant

# Set API credentials (or run the setup wizard)
memoryhub configure

# Start memoryhub in stdio mode (for MCP clients)
memoryhub

# Or auto-start Qdrant + serve in one step
memoryhub bootstrap

Prerequisites

Memory Hub needs three things:

  1. Node.js >= 24 — runtime
  2. Qdrant — vector database (install guide)
  3. LLM API — extracts facts from text (e.g. OpenAI, Anthropic, local Ollama)
  4. Embedding API — converts text to vectors (e.g. OpenAI text-embedding-3-small, local Ollama)

Qdrant and the embedding API are required. The LLM is optional: if it is unset or fails, the raw text is stored as-is instead of extracted facts. The embedding config is separate from the LLM config — it does not fall back to it (see config example below). memoryhub configure walks you through all of them.

Configuration

Configuration is checked in this order: environment variableconfig filedefault.

Config files are looked up in this order (first existing wins): $MEMORYHUB_CONFIG./memoryhub.json~/.memoryhub/config.json.

The config file is hot-reloaded: edits are picked up within ~1 second without restarting the server (a 1s watcher re-reads the file and logs config hot-reloaded (...)). Environment variables are read once at startup, so they still require a restart. Runtime update_config values keep precedence over the file until the process restarts.

Config file

Create a memoryhub.json in your project root, or config.json in the memoryhub directory (~/.memoryhub/ by default):

{
  "qdrant": {
    "url": "http://localhost:6333"
  },
  "collection": "memories",
  "vector_size": 768,
  "retry_delay_ms": 1000,
  "dedup": {
    "enabled": true,
    "threshold": 0.85,
    "skip_threshold": 0.99
  },
  "llm": {
    "model": "gpt-4o-mini",
    "base_url": "https://api.openai.com/v1",
    "api_key": "sk-..."
  },
  "embedder": {
    "model": "text-embedding-3-small",
    "base_url": "https://api.openai.com/v1",
    "api_key": "sk-..."
  }
}

The embedder config is required — it does not fall back to the llm settings. Embedding models and chat models are usually different endpoints, so both must be configured explicitly.

Environment variables

Short names (LLM_BASE, LLM_KEY) are preferred. Long names (LLM_BASE_URL, LLM_API_KEY) are supported for backward compatibility.

| Env Var | Short Alias | Default | Description | |---------|-------------|---------|-------------| | MEMORYHUB_DIR | — | ~/.memoryhub | Base directory for config and data files | | QDRANT_URL | — | http://localhost:6333 | Qdrant server URL | | MEMORYHUB_COLLECTION | — | memories | Collection name | | MEMORYHUB_VECTOR_SIZE | — | 768 | Vector dimension | | LLM_MODEL | — | — | LLM model for extraction | | LLM_BASE_URL | LLM_BASE | — | LLM API base URL | | LLM_API_KEY | LLM_KEY | — | LLM API key | | EMBED_MODEL | — | — | Embedding model (required) | | EMBED_BASE_URL | EMBED_BASE | — | Embedding API base URL (required) | | EMBED_API_KEY | EMBED_KEY | — | Embedding API key (required) | | MEMORYHUB_PORT | — | 9876 | Port for HTTP serve mode | | MEMORYHUB_HOST | — | :: | Bind host for HTTP serve mode (dual-stack by default: accepts both IPv4 and IPv6 on ::). Set 0.0.0.0 for IPv4-only | | MEMORYHUB_IPV6_ONLY | — | false | Set true to make the :: socket IPv6-only (no IPv4 connections) | | MEMORYHUB_RETRY_DELAY_MS | — | 1000 | Base retry delay for LLM/embed API calls (exponential backoff) | | MEMORYHUB_DEDUP_ENABLED | — | true | Semantic dedup on add_memories (merge/skip near-duplicates) | | MEMORYHUB_DEDUP_THRESHOLD | — | 0.85 | Similarity score ≥ this merges the new fact into the existing memory | | MEMORYHUB_DEDUP_SKIP_THRESHOLD | — | 0.99 | Similarity score ≥ this skips the new fact entirely (identical duplicate) | | MEMORYHUB_API_TOKEN | — | — | Optional bearer token. When set, the HTTP transport requires Authorization: Bearer <token> on every request (401 otherwise) | | MEMORYHUB_SESSION_IDLE_MS | — | 0 | Idle timeout for HTTP sessions in milliseconds. 0 disables idle pruning (sessions live until the client closes them or the server restarts; at capacity the least-recently-used session is evicted). Set a positive value (e.g. 900000 for 15 min) to expire sessions that go silent — clients should then send periodic MCP ping requests (a heartbeat) to keep the session alive, and must re-initialize on HTTP 404 |

Memory Scopes

Memories can be global or project-scoped:

  • Omit project → memory is global (visible to all searches)
  • Pass project="my-repo" → memory is scoped to that project
  • Search/list without project → returns all memories (global + all projects)
  • Search/list with project="my-repo" → returns only that project's memories

Use scopes to keep memories isolated per repo, per feature, or any other boundary.

MCP Tools

| Tool | Description | Scope Support | |------|-------------|---------------| | add_memories | Store text (LLM extracts facts, embeds them). Deduplicates near-duplicates by default. Optional project, source, importance (0–1), expires_at (ISO), dedup (bool), threshold (0–1). Returns per-memory action: inserted | merged | skipped | Optional project | | batch_add_memories | Add multiple texts in one call (items: [{text, project?, source?, importance?, expires_at?, dedup?, threshold?}]). Per-item outcomes; item-level failures don't abort the batch | Optional project per item | | search_memory | Semantic search with optional limit; returns full metadata per hit. Filter by project and/or source; set exact: true to match the query text verbatim instead of by similarity; min_score (0–1) drops hits below a similarity threshold (not usable with exact: true) | Optional project / source filter | | list_memories | List memories with pagination (limit, offset as cursor from next_offset); newest first; filter by project and/or source; returns full metadata | Optional project / source filter | | get_memory | Get a single memory by ID (full metadata) | — | | get_memories | Get multiple memories by IDs | — | | update_memory | Update a memory's text (re-embeds); optional source, importance, expires_at | — | | delete_memories | Delete specific memories by IDs | — | | delete_all_memories | Delete ALL memories (or filter by project) | Optional project filter, returns count | | export_memories | Export memories as JSON ({exported_at, count, memories}) for backup/migration; optional project / source filters | Optional project / source filter | | import_memories | Import export JSON (array or {memories: [...]}). Texts are re-embedded on import; original IDs and metadata are preserved | — | | review_stale | Report-only audit: buckets for expired, expiring soon (days, default 7), and older than older_than_days (default 90). Optional project / source / limit. Never modifies data | Optional project / source filter | | memory_stats | Collection statistics: totals, by_project, by_source, expired, expiring_soon_7d, avg_age_days, oldest/newest_created_at, size_bytes (estimate) | — | | get_config | Show current runtime configuration (API keys masked) | — | | update_config | Update a config value at runtime; set persist: true to write it atomically to the config file | — | | health_check | Check connectivity to Qdrant | — |

Every memory stores created_at, updated_at, and (when provided) project, source, expires_at, importance; all read tools return these fields. Memory IDs must be UUIDs (or numeric strings) — invalid IDs are rejected with a validation error before hitting Qdrant.

Config changes via update_config are in-memory only unless persist: true is passed (writes to ~/.memoryhub/config.json atomically, survives restart).

Retry

LLM and embedding API calls retry up to 3 attempts on transient errors (rate limits, server errors) with exponential backoff.

CLI

| Command | Description | |---------|-------------| | memoryhub | Start MCP server in stdio mode | | memoryhub serve | Start Streamable HTTP server | | memoryhub start | Daemon mode (background) | | memoryhub stop | Stop daemon | | memoryhub status | Check daemon status | | memoryhub bootstrap | Auto-start Qdrant if needed, then serve | | memoryhub configure | Interactive setup wizard (Qdrant, LLM, embedder) with connectivity checks; --set KEY=VALUE, --file, --no-verify for scripted use. --set and --file support all keys including API_TOKEN and DEDUP_* | | memoryhub install [--start] | Install auto-start service (systemd/launchd/Windows) pointing at the latest installed binary — package upgrades are picked up on the next boot/restart automatically, no re-run needed. --start also starts it immediately | | memoryhub uninstall | Remove auto-start service | | memoryhub --help | Show help | | memoryhub --version | Show version |

Transport Modes

  • stdio (default): Connect MCP clients via stdin/stdout
  • Streamable HTTP: memoryhub serve starts an HTTP server on port 9876 implementing the MCP Streamable HTTP transport (single POST /mcp endpoint, session management via Mcp-Session-Id header, DELETE /mcp to close a session). Clients must send Accept: application/json, text/event-stream on POST requests. The server binds to :: dual-stack by default (accepts both IPv4 and IPv6) — set MEMORYHUB_IPV6_ONLY=true to restrict to IPv6 only, or MEMORYHUB_HOST to pick a specific address. By default sessions are not pruned for idleness; when MEMORYHUB_SESSION_IDLE_MS is set, sessions that stay silent past the timeout are pruned and subsequent requests with the old session ID get 404 — clients must then re-initialize (send a fresh initialize without a session ID), per the MCP Streamable HTTP spec.

Remote clients connect to http://<host>:9876/mcp. If API_TOKEN is set, every request must include Authorization: Bearer <token>; unauthenticated requests get 401. Request bodies are capped at 5 MB (413).

Build

pnpm build       # type-check + bundle
pnpm typecheck   # type-check only
pnpm dev         # run with tsx

License

MIT