tartarus-mcp
by saluca-labs
README.md
# tartarus-mcp
Local-first MCP memory server. Persistent, searchable memory for any AI agent.
Built on the Apache-2.0 [Asphodel](./src/vendor/asphodel/NOTICE) memory core, vendored in this repo. Zero cloud dependencies. SQLite-backed.
## Install (build from source)
tartarus-mcp is not published to npm or any other package registry. Build it from this repository, pinned to a reviewed commit:
```bash
git clone https://github.com/saluca-labs/tartarus-mcp.git
cd tartarus-mcp
git checkout d21ea0fc72dd4b1b348ce6f4d6f6090e54ffd152
npm ci --ignore-scripts=false
npm run build
node dist/index.js install
```
`install` configures Claude Code, Cursor and Windsurf to run `node /absolute/path/to/tartarus-mcp/dist/index.js`, so keep the checkout where it is. It also prints the equivalent `claude mcp add` line for the Claude Code CLI.
`--ignore-scripts=false` is needed only if your npm config sets `ignore-scripts=true`: the `better-sqlite3` dependency compiles or downloads its native binding in an install script.
## Manual setup
After building, add this to your MCP settings, using the absolute path of your checkout:
```json
{
"mcpServers": {
"tartarus": {
"command": "node",
"args": ["/absolute/path/to/tartarus-mcp/dist/index.js"]
}
}
}
```
### Without a local checkout
npm can fetch and build the pinned commit straight from GitHub. This does not use the npm registry for tartarus-mcp itself; its third-party dependencies still come from npm.
```json
{
"mcpServers": {
"tartarus": {
"command": "npx",
"args": ["-y", "--ignore-scripts=false", "github:saluca-labs/tartarus-mcp#d21ea0fc72dd4b1b348ce6f4d6f6090e54ffd152"]
}
}
}
```
The first start takes about 30 seconds while it builds. Pin a full commit SHA, never a branch.
## Tools
| Tool | Description |
|------|-------------|
| `memory_remember` | Store a memory (topics auto-extracted) |
| `memory_recall` | Retrieve memories by topic |
| `memory_search` | Full-text search across all memories |
| `memory_forget` | Delete a memory by ID |
| `memory_list` | List recent memories |
| `profile_get` | Read the agent profile (empty `{}` on a fresh install) |
| `profile_update` | Merge changes into the agent profile |
## Agent profile
Memory answers *what happened*. The profile answers *who am I working with, and how do we work* -
the standing facts an agent would otherwise re-derive every session, or re-ask about.
It **starts empty** and the agent fills it in over time:
```jsonc
// profile_get on a fresh install
{ "profile": {}, "updated_at": null, "revision": 0 }
// profile_update { "patch": { "user": { "name": "Ada" }, "tone": "terse" } }
{ "profile": { "user": { "name": "Ada" }, "tone": "terse" }, "revision": 1, ... }
// profile_update { "patch": { "user": { "role": "engineer" }, "tone": null } }
{ "profile": { "user": { "name": "Ada", "role": "engineer" } }, "revision": 2, ... }
```
**Merge semantics**, because this is the part that is easy to get wrong:
- objects merge **recursively**, so setting one field keeps its siblings
- `null` **deletes** a key - the only way to remove one
- arrays **replace** wholesale; positional merging of lists is never what a caller means
- `"replace": true` swaps the whole document, for a deliberate reset
**What goes where.** Durable facts about the person, the project or the working agreement belong
in the profile. Things that *happened* belong in `memory_remember`. The distinction matters
because memories decay and compete for recall, while the profile is one small document meant to
be read in full at the start of a session.
The profile lives in its own table in the same SQLite file, so `memory_forget` cannot delete part
of an identity by id and decay cannot quietly age out a working agreement.
## Config
```bash
TARTARUS_DB=/path/to/memory.db # default: ~/.tartarus/memory.db
```
## Enterprise
Hash-chained audit trails, multi-tenant isolation, compliance controls, and team memory at [asphodel.ai](https://asphodel.ai).
## License
Functional Source License 1.1, Apache 2.0 Future License (`FSL-1.1-ALv2`), see [LICENSE](./LICENSE). Each version becomes available under the Apache License 2.0 on the second anniversary of its release. Copyright [Saluca LLC](https://saluca.com).
The vendored Asphodel core in [`src/vendor/asphodel/`](./src/vendor/asphodel/) (and its tests in `tests/vendor/asphodel/`) is licensed under the Apache License 2.0, not FSL; see its [LICENSE](./src/vendor/asphodel/LICENSE) and [NOTICE](./src/vendor/asphodel/NOTICE), which record the origin commit.
Versions 0.2.0 and earlier were published to npm with an `Apache-2.0` licence field, and those releases remain available under Apache 2.0.
## Distribution
npm is no longer a distribution channel. On 2026-09-16 Saluca removed all of its packages from npm, including `tartarus-mcp` and `@saluca/asphodel`, which tartarus-mcp used to depend on. That is why the Asphodel core is vendored here, why `package.json` is `"private": true`, and why the npm publish workflow was removed. Install from source as described above. Do not install a package named `tartarus-mcp` from npm: it is not ours.This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessUnresponsive