NFTS Memory MCP
README.md
# π§ NFTS Memory MCP
One shared memory for **claude.ai**, **Claude Desktop**, and **Claude Code** β on any computer. Save something in one, it's there in all of them.
Self-hosted, SQLite-backed, zero recurring cost. Runs as one systemd service on your MCP Hub, same pattern as your other custom MCP servers.
---
## How it works
```
βββββββββββββββββββββββββββ
claude.ai ββββββββββββΆβ β
(connector, OAuth) β nfts-memory-mcp β
β βββββββββββββββββ β
Claude Desktop ββββββββΆβ Express + MCP SDK β
(MCP config, OAuth) β SQLite + FTS5 search ββββΆ data/memory.db
β Built-in OAuth server β
Claude Code βββββββββββΆβ Web dashboard β
(MCP config, OAuth) β β
βββββββββββββββββββββββββββ
```
- **One process, one database.** Every client talks to the same SQLite file over HTTP β there's nothing to sync, because there's only ever one copy.
- **9 MCP tools** let Claude save, search, update, and organize memories: `memory_save`, `memory_search`, `memory_recent`, `memory_context`, `memory_update`, `memory_archive`, `memory_delete`, `memory_list_projects`, `memory_stats`.
- **Full-text search** via SQLite FTS5 (porter stemming, ranked results, snippet highlighting) β fast even at tens of thousands of memories.
- **Built-in OAuth 2.0 server** (with PKCE + dynamic client registration) so claude.ai, Desktop and Code can each connect as their own authorized client β this is what makes it usable as a claude.ai connector, not just a local tool.
- **Web dashboard** at your domain root β browse, search, manually add/edit/archive memories, see stats, and manage which apps are connected.
- **Projects & categories.** Every memory is tagged with a project (`nfts`, `aural`, `dantectl`, `general`, ...) and a category (`fact`, `decision`, `preference`, `todo`, `config`, `contact`, `idea`), so Claude can filter context to what's relevant.
---
## Deploy
On your MCP Hub (or any box with Node 18+):
```bash
# 1. Copy this whole folder to the server, then:
cd nfts-memory-mcp
sudo bash deploy/deploy.sh
```
The script installs a `nftsmemory` system user, copies files to `/opt/nfts-memory-mcp`, installs dependencies, and sets up the systemd service. It prints the remaining manual steps (edit `.env`, nginx + certbot, start the service) β takes about 5 minutes.
**Suggested subdomain:** `memory.nftech-apps.net`, following your existing `mqtt.` / `mcp.` pattern.
Once it's running:
```bash
curl https://memory.nftech-apps.net/healthz
# {"ok":true,"service":"nfts-memory-mcp"}
```
### Verifying the full flow
`scripts/verify.sh` runs an end-to-end test against a running server (client registration β OAuth login β token β save/search a memory). Point it at your server with `BASE_URL` if testing remotely, otherwise it defaults to localhost.
---
## Connect each client
All three go through the same OAuth flow β sign in with the `ADMIN_USER` / `ADMIN_PASSWORD` you set in `.env`.
### claude.ai (web / mobile)
Settings β Connectors β Add connector β paste `https://memory.nftech-apps.net/mcp` β Connect β sign in. Done β every conversation on any device now has access.
### Claude Desktop
Settings β Connectors β Add custom connector β same URL, same login. (Desktop already shares claude.ai's account memory β this adds Code-style tool access on top, so Desktop can *search and save* memories explicitly, not just passively recall.)
### Claude Code (CLI)
```bash
claude mcp add --transport http nfts-memory https://memory.nftech-apps.net/mcp
```
It'll open a browser for the same OAuth login. After that, every `claude` session on every machine you run this on shares the same memory.
Check **Connections** in the web dashboard afterwards β you'll see all three listed with their own token, so you can revoke any one independently (e.g. if you get a new laptop and want to kill the old token).
---
## Using it day to day
You don't need to do anything special β just talk normally:
- *"Remember that the Xero email endpoint is POST /Invoices/{id}/Email"* β Claude calls `memory_save`
- *"What did we decide about the WiFi upgrade proposal pricing?"* β Claude calls `memory_search`
- *"Catch me up on dantectl"* β Claude calls `memory_context` with `project="dantectl"`
Claude decides when to save/search based on the conversation β you can also be explicit ("save this to memory", "search memory for...") if you want to force it.
The **dashboard** (`https://memory.nftech-apps.net/`) is for you: browsing everything, manually adding a memory, archiving stale ones, and seeing which apps are connected.
---
## Maintenance
**Backups** β it's one SQLite file. Add to your existing weekly Vultr snapshot routine, or simply:
```bash
sqlite3 /opt/nfts-memory-mcp/data/memory.db ".backup /path/to/backup-$(date +%F).db"
```
**Logs:**
```bash
journalctl -u nfts-memory-mcp -f
```
**Updating code:** re-run `deploy/deploy.sh` (it won't touch your `.env` or `data/`), then `systemctl restart nfts-memory-mcp`.
**Revoking a lost/compromised device:** dashboard β Connections β Revoke next to that client's token.
---
## Why this instead of claude-mem
[claude-mem](https://github.com/thedotmack/claude-mem) only hooks into Claude Code's session lifecycle β it can't reach claude.ai or Desktop, and it doesn't sync across machines on its own. This is a plain MCP server, so it works identically everywhere Claude can connect to an MCP server, self-hosted on infrastructure you already run, with no per-seat or per-token SaaS cost.
---
## Tech stack
Node.js, Express, `@modelcontextprotocol/sdk` (Streamable HTTP transport), `better-sqlite3` (WAL mode + FTS5), zero build step β it's plain JS, matching the rest of your MCP Hub services.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing