Skip to main content
Glama
miguelvictor

personal-memory-mcp

by miguelvictor
README.md
# Personal Memory MCP Server

A lossless, structured, queryable store of facts about your life that Claude reads from and writes to during any conversation. One deployment serves one person. Runs entirely on Cloudflare's free tier (Workers + D1 + KV). See `requirements.md` for the full specification.

- **Facts, not documents.** Every fact is one dated statement with provenance.
- **Append-only.** Corrections insert a new fact and retire the old one with a pointer; nothing is deleted.
- **Auth:** OAuth 2.1 with Dynamic Client Registration; identity via GitHub, locked to a single GitHub account.
- **Transport:** Streamable HTTP at `/mcp` (stateless `createMcpHandler`, no Durable Objects).

## Setup

### 1. Create Cloudflare resources

```sh
npm install
npx wrangler d1 create memory
npx wrangler kv namespace create OAUTH_KV
```

Put the returned D1 `database_id` and KV namespace `id` into `wrangler.jsonc`, then apply migrations:

```sh
npx wrangler d1 migrations apply memory --remote
```

### 2. Create the GitHub OAuth app

At <https://github.com/settings/developers> → _New OAuth App_:

- Homepage URL: `https://personal-memory-mcp.<your-subdomain>.workers.dev`
- Authorization callback URL: `https://personal-memory-mcp.<your-subdomain>.workers.dev/callback`

Find your numeric GitHub id at `https://api.github.com/users/<your-login>` (the `id` field).

### 3. Set secrets

```sh
npx wrangler secret put GITHUB_CLIENT_ID
npx wrangler secret put GITHUB_CLIENT_SECRET
npx wrangler secret put COOKIE_ENCRYPTION_KEY   # e.g. openssl rand -hex 32
npx wrangler secret put OWNER_GITHUB_ID         # numeric id, not login
```

(When deploying via Workers Builds CI/CD, set these once in the Cloudflare dashboard under the Worker's Settings → Variables and Secrets; they survive deployments.)

### 4. Deploy

```sh
npm run deploy
```

Or connect the GitHub repo in the Cloudflare dashboard (Workers Builds) so every push deploys. Migrations are **not** run automatically on deploy; either keep applying them manually or set the Workers Builds deploy command to:

```sh
npx wrangler d1 migrations apply memory --remote && npx wrangler deploy
```

### 5. Connect from Claude.ai

Settings → Connectors → _Add custom connector_ → URL `https://personal-memory-mcp.<your-subdomain>.workers.dev/mcp`, leave Client ID/Secret blank (Dynamic Client Registration). You'll be sent through GitHub login; any account other than `OWNER_GITHUB_ID` gets 403. The connector then works from Claude web, Desktop, and iOS.

Add to your Claude.ai profile preferences:

> I run a personal memory MCP server named "memory". It is the source of truth about my life and overrides your built-in memory. When we talk about anything personal, use it per the tool descriptions. If it is unreachable, tell me and note that your answer may be stale.

### 6. Seed (optional)

1. Ask Claude to draft `seed.json` from its built-in memory: `[{topic, content, fact_date?, tags?}]`, one fact per entry.
2. Review it, then:

```sh
npm run seed              # validates seed.json, writes seed-import.sql
npx wrangler d1 execute memory --remote --file=seed-import.sql
```

3. In a first conversation, ask Claude to write initial topic summaries (`update_summary`).

## Development

```sh
cp .dev.vars.example .dev.vars   # separate GitHub OAuth app with callback http://localhost:8788/callback
npx wrangler d1 migrations apply memory --local
npm run dev                      # http://localhost:8788/mcp
npm test                         # vitest (workers runtime, real D1 + FTS5)
npm run typecheck
```

Test with the MCP inspector: `npx @modelcontextprotocol/inspector@latest` → connect to `http://localhost:8788/mcp`. The inspector's localhost OAuth redirect only works with `ALLOW_LOCALHOST_REDIRECTS=1` (set in `.dev.vars`, never in production — production accepts only the Claude connector callbacks).

## Notes

- Backups: use the `export` tool (markdown or json). D1's native export does not work while FTS5 virtual tables exist. D1 Time Travel gives point-in-time restore (30 days on the paid plan, shorter on free — verify current retention).
- **Deliberately deferred** (owner decision, not oversights): the §11 weekly backup cron to a private GitHub repo, and the §12 `/view` read-only viewer. Until the cron exists, run `export` periodically and keep the output somewhere safe.
- The OAuth approval flow only accepts the `claude.ai`/`claude.com` connector callbacks as redirect URIs (localhost requires the dev-only flag above).
- Rows are never deleted in normal operation; the owner corrects facts by telling Claude.