Skip to main content
Glama
README.md
# memhub

**One small, self-hosted MCP memory server that keeps Claude, ChatGPT and your own agents on the same page.**

You brainstorm a feature with Claude, then open ChatGPT the next day, or hand the work to a local agent. Each one starts from zero, because each keeps its own private memory. memhub is a shared notebook they all read and write through the [Model Context Protocol](https://modelcontextprotocol.io). You host it and own the data, and it's plain markdown in a git repo.

```
 claude.ai ──────┐
 chatgpt.com ────┼──► memhub ──► data/  (markdown + git, SQLite FTS index)
 local agents ───┘
```

## Why it stays cheap on tokens

Memory systems usually cost tokens in two places: tool definitions loaded into every turn, and lookups that return too much. memhub keeps both small.

- **5 tools**, short descriptions: about **530 tokens** of definitions per turn (measured as characters ÷ 4).
- **Nothing is pushed into prompts.** Agents pull a project's state only when that project comes up.
- **Hard output caps.** A state card is at most 3,000 characters, a log entry 1,200, and a search result about 4,000.
- **The server compacts, not the model.** Old log entries roll into monthly archives that stay searchable.

## How memory is organized

Each project has two things:

| | What | How it changes |
|---|---|---|
| **State card** | Summary, decisions, open questions, next steps | Rewritten in place, size-capped |
| **Log** | Dated entries tagged with who wrote them (`claude`, `chatgpt`, ...) and a kind (`decision`, `progress`, `fact`, `note`) | Append-only |

**Conflict safety.** To replace a state card, an agent must send the version it last read. If another agent changed the card in the meantime, the write is rejected and the current card comes back so the agent can merge and retry. Log appends never conflict.

**Everything is reversible.** Every write is a git commit in `data/`, so `git log` shows who changed what, and you can restore any earlier version.

## Tools

| Tool | Returns |
|---|---|
| `index()` | One line per project: name, last update, summary |
| `get_state(project, recent=3)` | The state card, its version, and recent log entries |
| `recall(query, project?, k=5)` | Keyword search over state, logs and archive, as short snippets |
| `checkpoint(project, log, kind?, state?, version?, source?)` | Appends a log entry and optionally replaces the state card |
| `forget(project, entry_id)` | Removes one log entry |

## Quick start

**Docker**

```bash
git clone https://github.com/alx-kap/memhub && cd memhub
cp .env.example .env
docker compose run --rm memhub memhub token     # paste the output into MEMHUB_PATH_TOKEN in .env
mkdir -p data && sudo chown 1000:1000 data
docker compose up -d --build
curl http://127.0.0.1:8765/healthz              # -> ok
```

**Without Docker** (Python 3.10+)

```bash
pip install .
export MEMHUB_PATH_TOKEN=$(memhub token)
memhub serve                                     # http://127.0.0.1:8765/mcp/<token>
```

Your MCP endpoint is `http://127.0.0.1:8765/mcp/<MEMHUB_PATH_TOKEN>`.

**With OAuth** (recommended once memhub is public): set `MEMHUB_PUBLIC_URL` and `MEMHUB_OWNER_PASSWORD`. Clients then connect to `https://<your-host>/mcp`, and you approve each one on a memhub page. See [docs/exposing.md](docs/exposing.md#oauth).

## Connecting clients

claude.ai and chatgpt.com connect from their own servers, so memhub needs a public HTTPS URL. A tunnel is the easiest way to get one without opening router ports; see **[docs/exposing.md](docs/exposing.md)**. Local agents can skip that and use localhost or stdio.

| Client | How |
|---|---|
| claude.ai | Custom connector: OAuth URL, or the path-token URL with no authentication |
| chatgpt.com | Developer Mode connector: OAuth, or the path-token URL with "No authentication" |
| Claude Desktop, Hermes, other local agents | `memhub serve --stdio`, or the localhost URL |

Step-by-step instructions, plus the short instruction text that gets each agent to actually use memhub, are in **[docs/clients.md](docs/clients.md)**.

## What "automatic" means here

- **Web apps (claude.ai, chatgpt.com):** the model decides when to call a tool. With the instruction text from `docs/clients.md`, they read memory when a known project comes up. Writes happen when you say **"checkpoint"**. No setting can force a tool call at the start of every chat.
- **Agents you control (Hermes, scripts):** you can make it fully automatic. Examples are in [docs/clients.md](docs/clients.md#hermes-agent).

## Configuration

All settings are environment variables; see [.env.example](.env.example).

| Variable | Default | Purpose |
|---|---|---|
| `MEMHUB_PATH_TOKEN` | | Secret path segment, 24+ characters. Required for HTTP unless OAuth is on |
| `MEMHUB_PUBLIC_URL` | | Public origin, e.g. `https://memhub.example.com`. Turns on OAuth at `/mcp` |
| `MEMHUB_OWNER_PASSWORD` | | Required with OAuth, 12+ characters. You type it to approve each client |
| `MEMHUB_ALLOWED_HOSTS` | | Public hostname(s) of your tunnel. Include `:port` if not 443 |
| `MEMHUB_DATA` | `./data` | Where memory lives |
| `MEMHUB_HOST` / `MEMHUB_PORT` | `127.0.0.1` / `8765` | Listen address |
| `MEMHUB_GIT` | `1` | Commit each write to git |
| `MEMHUB_INSTRUCTIONS_FILE` | | Replace the usage instructions sent to clients |
| `MEMHUB_MAX_STATE_CHARS` | `3000` | State card cap |
| `MEMHUB_MAX_ENTRY_CHARS` | `1200` | Log entry cap |
| `MEMHUB_RECALL_CHARS` | `4000` | Search output budget |

## Maintenance

```bash
memhub compact --days 30 --keep 10    # archive old log entries (run weekly from cron)
cd data && git push                   # back up memory to a private remote
```

With OAuth on, manage the clients you've approved:

```bash
memhub clients                        # list clients, their access and last use
memhub revoke <client_id>             # cut one off immediately (or: memhub revoke all)
```

With Docker: `docker compose exec -T memhub memhub compact`, and likewise for `clients` and `revoke`.

## Security

memhub has two ways to authenticate. With the **path token**, anyone with the full URL can read and write your memory. With **OAuth**, each client gets its own expiring tokens that you approve, can make read-only, and can revoke. Read **[SECURITY.md](SECURITY.md)** before exposing memhub publicly.

## Limitations

- **Keyword search only.** There are no embeddings yet; `recall` matches words, not meaning.
- **Single user.** There are no accounts. With OAuth, each client is read-write or read-only.
- **ChatGPT write access depends on your plan.** Some plans allow only read-only custom connectors. If `checkpoint` fails from ChatGPT while `index` works, that's the reason.

## Roadmap

- A native memory-provider plugin for Hermes Agent
- Optional semantic search (sqlite-vec)

## License

MIT. See [LICENSE](LICENSE).

Maintenance

ActivityMaintained
ResponsivenessNo issues