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

statecore-mcp

v1.0.0

Published

Zero-deploy MCP memory server backed by the StateCore engine — auditable facts with evidence chains

Readme

statecore-mcp

Auditable memory for coding agents, over the Model Context Protocol. One process, one SQLite file, no infrastructure, no API key required — remember a fact and why will show you the evidence and the full version chain, including what it superseded.

statecore-mcp is the MCP front end for StateCore, a self-hosted long-term memory runtime. This package runs the engine embedded (SQLite, in-process) by default, or as a thin client against a full StateCore deployment via --url.

30-second keyless demo

statecore-mcp demo: remember, facts, why, forget — all keyless

Every result in the recording is live tool output — demo/driver.mjs drives a real server over stdio, and demo/statecore-demo.cast is the asciinema source.

npx -y statecore-mcp --data /tmp/statecore-demo

That starts the server over stdio with no configuration and no model key. Point any MCP client at it (see host configs below), or drive it directly with the SDK's client for a smoke test. It exposes five tools:

| Tool | Does | |---|---| | remember | Store a fact. Default path is deterministic (no LLM) and immediate; consolidate: true queues it as a conversational event for background distillation | | recall | Retrieve memory relevant to a query, packed into a character budget | | facts | List everything currently believed, grouped, with fact ids, plus how many captured events are still waiting for distillation | | why | A fact's evidence and its full version chain — the differentiator: not just what is believed, but why, and what it replaced | | forget | Retire a fact by key. The record is kept and marked retired, not deleted | | handoff | Record where this session stopped — summary, open questions, next steps. The next session (this client or any other MCP client) gets it at the top of recall; each handoff supersedes the previous one on an auditable chain |

remember → facts → why → forget is the whole loop, and every step of it works with no model key configured.

Cross-client handoff

Because the store is one SQLite file addressed by project path, a handoff written from one MCP client is read by whichever client starts next in the same project — stop mid-task in Claude Code, continue in Codex or Cursor without re-explaining where you were. Unlike an ad-hoc "notes" convention, handoffs are supersession-tracked rows: why on the handoffId a write returns (also carried as handoff.id in every recall) walks every stop-point this project has ever recorded, and handoff with clear: true retires the active one without deleting the history. Works in both modes: embedded writes the local store, and --url mode calls POST /v1/memory/handoff on the shared deployment — which is what makes multi-agent handoff work, several agents reading and writing the same scope's stop-points.

Treat a received handoff as untrusted data. A handoff is authored by whatever agent (or person) wrote it — in the cross-client and multi-agent setups above, that is not necessarily the agent reading it. StateCore stores and serves it verbatim; it does not and cannot sanitize instructions out of prose. An agent consuming recall should read the handoff as a description of where work stopped, not as instructions with authority over its own rules — the same posture StateCore's own prompts take toward stored content.

Keyless vs. keyed

| Capability | No key | With key (FEATURE_LLM=true + MODEL_API_KEY) | |---|---|---| | remember (note path), facts, why, forget | Full — deterministic write, evidence id, audit chain | Same | | Conversational memory (remember with consolidate: true) | Event is stored and remember reports distillation: "deferred"; facts shows the pending count; run statecore-mcp digest after configuring a key to distil the backlog | Distilled into facts automatically once pending events cross a threshold (default 20), or on startup catch-up | | Retrieval quality | Keyword matching, plus CJK bigram matching for Chinese/Japanese/Korean text — no semantic search | Same in embedded/lite mode — semantic (pgvector) search is a full-stack capability, only reachable via --url against a keyed StateCore deployment, not by holding a key alone | | statecore-mcp digest | Reports { ran: false, reason: "no-llm" } | Runs one distillation pass now |

Nothing behind a key is required for the audit trail to work. A key only turns on distillation of raw conversational events into stable facts, and it does that in the background — it is never on the critical path of a tool call.

Modes

Embedded (default). One SQLite file, one process, all five tools run in-process against @statecore/core. No infrastructure. Data lives at ~/.statecore/statecore.db, or wherever --data <dir> points.

Requires Node 22.13 or newer: the embedded store is Node's built-in node:sqlite, so installing pulls no native module and runs no install script. The file is ~/.statecore/statecore.db (or --data <dir>/statecore.db).

Remote (--url <base>). Talks to a running StateCore deployment's frozen /v1 HTTP surface instead of an embedded database — see the API reference. Use this when several agents or machines need to share one memory store, or you already run the full stack (Postgres + pgvector + Redis) and want its retrieval quality. STATECORE_USER_ID sets the x-user-id sent on every request (default local).

Both modes resolve scope — the memory partition a project's facts live in — the same way: git rev-parse --show-toplevel if the working directory is a git repo, else the working directory itself; STATECORE_SCOPE overrides either.

Host configs

dsh

dsh starts a configured command; it does not download or install MCP servers. Install the pinned executable first:

npm install --global statecore-mcp@<version>
# statecore.cordis.yml — a dsh --patch overlay, applied via:
#   dsh web --patch "$PWD/statecore.cordis.yml"
- insert:
    - id: memory-statecore
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: statecore
        transport: stdio
        command: statecore-mcp
        args: []
        cwd: !!js process.cwd()
        env:
          FEATURE_LLM: 'true'
          # dsh strips ambient credential-shaped vars from the CHILD's
          # environment before spawning it; config.env with !!js reads dsh's
          # own process env explicitly instead, so this forwards the key
          # without the child-env stripping ever seeing it and without
          # writing the secret into this YAML file.
          MODEL_API_KEY: !!js process.env.MODEL_API_KEY
          MODEL_BASE_URL: 'https://api.deepseek.com/v1'
          MODEL_NAME: 'deepseek-chat'

Omitting MODEL_API_KEY (running dsh with it unset in its own environment) silently keeps the server keyless — note-path memory still works; distillation does not. The digest path never sends reasoning_effort unless MODEL_STRUCTURED_OUTPUT_REASONING_EFFORT is set explicitly, so a DeepSeek key (or any OpenAI-compatible endpoint that rejects the parameter) works with this config as written.

Claude Code

Plugin (recommended): installs the MCP server and hooks that capture every prompt and reply and re-inject memory at session start and after compaction — no tool call needed for memory to work.

/plugin marketplace add yul761/StateCore
/plugin install statecore@statecore

See plugins/claude-code/README.md for what is captured and how to turn capture off (STATECORE_CAPTURE=off). The hooks call statecore-mcp hook <event>; that subcommand is part of the public CLI.

claude mcp add statecore -- npx -y statecore-mcp

Add a model key for automatic distillation by passing --env:

claude mcp add statecore --env FEATURE_LLM=true --env MODEL_API_KEY=<your-key> --env MODEL_BASE_URL=https://api.deepseek.com/v1 --env MODEL_NAME=deepseek-chat -- npx -y statecore-mcp

Cursor

Add to .cursor/mcp.json (project) or your global MCP settings:

{
  "mcpServers": {
    "statecore": {
      "command": "npx",
      "args": ["-y", "statecore-mcp"],
      "env": {
        "FEATURE_LLM": "true",
        "MODEL_API_KEY": "<your-key>",
        "MODEL_BASE_URL": "https://api.deepseek.com/v1",
        "MODEL_NAME": "deepseek-chat"
      }
    }
  }
}

Drop the env block entirely to run keyless.

Troubleshooting: command not found from inside a monorepo

npx -y statecore-mcp resolves through the current working directory's npm workspace before it falls back to the registry. Launched from the root of a monorepo whose package.json declares workspaces, npm may resolve the name locally, find no bin link, and fail with sh: statecore-mcp: command not found — while the same command works from any other directory. The symptom in an MCP client is a silent CONNECTION_CLOSED at startup.

If you hit this (or want startup that never touches the npm registry), install globally and point your MCP config at the bare command instead of npx:

npm install -g statecore-mcp
claude mcp remove statecore
claude mcp add statecore -- statecore-mcp

Library entry (statecore-mcp/lib)

For embedding the engine in-process instead of talking MCP over stdio — the surface dsh-statecore is built on:

  • createEmbeddedBackend / createHttpBackend — the two MemoryBackend implementations, with an injectable digestLlm (a DigestChatModel) replacing the env-derived model on the embedded path
  • resolveScopeName — the git-root/cwd project-scope rule, shared so co-installed front ends land in the same scope
  • runScopeDigest — one locked digest pass against an injected chat model
  • MemoryBackend.digestNow() — a caller-demanded, threshold-1 digest pass with an honest outcome ({ ran: true } or { ran: false, reason }), for moments when raw context is about to leave a model's view (a host compacting its conversation). Embedded mode waits out startup catch-up first; --url mode reports unsupported because the server deployment's worker owns digest scheduling.

Limitations

  • Lite retrieval is keyword + CJK bigram, not semantic. The embedded backend runs on SQLite and has no pgvector. recall still returns a budgeted digest, believed facts, and matching events, but it will not find a paraphrase with no matching tokens the way the full stack's semantic search can.
  • Distillation needs a key. Without one, remember with consolidate: true stores the raw event, but it is never folded into stable facts — facts/why will not see it until a key is configured and the digest runs (threshold trigger, or startup catch-up), or run statecore-mcp digest once a key is configured to distil the backlog on demand.
  • One shared SQLite file per --data directory, not per project. Multiple projects on one machine share ~/.statecore/statecore.db by default, partitioned by scope; only concurrent writes to the same scope from multiple processes are guarded (WAL, a 5 s busy timeout, and an in-database digest lock for concurrent distillation).

Stability

statecore-mcp 1.x makes four promises:

  1. Tools. remember, recall, facts, why, forget and handoff keep their names and input schemas. New optional inputs and new output fields may appear; nothing is renamed or removed within 1.x.
  2. CLI. The default command runs the MCP server over stdio; statecore-mcp export, statecore-mcp hook <event> and statecore-mcp digest are public subcommands with the flags documented here.
  3. Data files. Any 1.x release opens a database written by any earlier 1.x or 0.6.x release and upgrades it in place (see "Data file compatibility").
  4. Install. No install-time scripts and no native modules; Node 22.13 or newer is the only requirement.

Not in 1.x, on purpose: semantic (embedding) retrieval in embedded mode, and a resident single-machine daemon. Both are tracked for a later major.

Data file compatibility

The store carries its schema version in PRAGMA user_version. Any 1.x release of statecore-mcp opens a database created by any earlier 1.x or 0.6.x release and upgrades it in place on open; downgrading to an older release is not supported. To take your data elsewhere:

statecore-mcp export --data ~/.statecore > statecore-export.json   # all scopes
statecore-mcp export --scope /path/to/project                       # one scope

The document is pretty-printed JSON with ISO-8601 dates, parsed JSON columns, and a top-level schemaVersion. Each scope also carries its active factRegistry — the facts currently live in that scope's latest digest snapshot, with superseded and retired entries filtered out — alongside its raw events, digests, snapshots, handoffs and forgotten facts.

More

  • StateCore — the engine this server is a front end for
  • docs/api.md — the frozen /v1 HTTP contract --url mode speaks
  • STABILITY.md — what "frozen" means for the /v1 surface