Skip to content

Repository files navigation

Memoflare

Memoflare is an MCP server that gives AI agents durable, path-addressed memory — a filesystem-shaped store agents can read, write, search, and manage. It is built for agent-first workflows and can run locally, in Docker, or on Cloudflare Workers.

What you get

  • Five MCP tools: remember, read, update, forget, search (hybrid full-text + vector search)
  • MCP resources: core://, tree://, memo://{path} for passive discovery
  • Bootstrap flow: agents are instructed to read core:// first to load skills and core memos
  • Two runtimes: Node.js (local) and Cloudflare Worker (edge) sharing the same service layer

Requirements

  • Node.js ≥ 20.12
  • pnpm (recommended)

Quick start (local development)

pnpm install
cp .env.example .env   # optional; defaults work for loopback dev
pnpm run local
  • HTTP MCP: http://localhost:3001/mcp
  • Health check: http://localhost:3001/

Stdio (Claude Desktop, Cursor, etc.)

pnpm run local -- --stdio

Custom data directory

pnpm run local -- --root ./data

Default root without overrides: ~/memoflare (memo files plus .memoflare/memory.db).


Self-hosting

Memoflare can run entirely on your own hardware without Cloudflare. You get local SQLite + filesystem storage, sqlite-vec for vectors, and FastEmbed for embeddings (model pre-downloaded in the Docker image).

Option A — Docker (recommended for VPS / homelab)

1. Configure environment

cp .env.example .env

Set MEMORY_ROOT=./data (or an absolute path) so memo files and the DB persist on the host. Compose bind-mounts that path to /app/memoflare inside the container.

2. Start the stack

pnpm run docker:up

By default the service listens on 127.0.0.1:3001 only. MCP endpoint: http://127.0.0.1:3001/mcp.

3. Expose beyond localhost (optional)

If you put Memoflare behind a reverse proxy or need LAN access:

  1. Set a strong MEMORY_BEARER in .env
  2. Change the Compose port mapping to bind the host interface you intend (or keep loopback and terminate TLS at the proxy)
  3. Point clients at http(s)://<your-host>/mcp with Authorization: Bearer <token>

Do not publish port 3001 to the public internet without MEMORY_BEARER (or MEMORY_ALLOW_INSECURE=1, which is only appropriate for trusted local setups).

4. Operations

pnpm run docker:logs      # follow logs
pnpm run docker:restart
pnpm run docker:down

Host layout after use:

{MEMORY_ROOT}/
  <your-top-level>/...     # memo markdown/json files
  .memoflare/memory.db     # SQLite index + vectors
  .trash/...               # soft-deleted memos

Option B — Node.js on a server (no Docker)

pnpm install
pnpm run local:build
node dist/local.js --host 0.0.0.0 --port 3001 --root /var/lib/memoflare --bearer "$MEMORY_BEARER"

Binding to non-loopback addresses requires --bearer (or --allow-insecure for controlled environments). Use a process manager (systemd, pm2) and a reverse proxy with TLS in production.

Option C — Stdio on a desktop

For MCP clients that spawn the server as a subprocess:

pnpm run local -- --stdio --root ~/memoflare

No HTTP port; auth is handled by OS process isolation.

Connecting an MCP client (self-hosted HTTP)

Example for Cursor / Claude Desktop (HTTP transport):

{
  "mcpServers": {
    "memoflare": {
      "url": "http://127.0.0.1:3001/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_TOKEN"
      }
    }
  }
}

Omit headers when using loopback without a bearer token.


Cloudflare deployment

Production edge deployment uses a Cloudflare Worker with D1 (metadata + FTS), R2 (memo bytes), Vectorize (semantic search), and Workers AI (embeddings). OAuth via KV is optional.

Prerequisites

1. Create Cloudflare resources

From the repo root:

# D1 database
pnpm exec wrangler d1 create memoflare-db
# Copy the database_id from the output into wrangler.jsonc under d1_databases[0]

# R2 bucket (dashboard or CLI)
pnpm exec wrangler r2 bucket create memoflare-files

# Vectorize index (768-dim cosine — matches BGE base EN v1.5)
pnpm exec wrangler vectorize create memoflare-vectors --dimensions=768 --metric=cosine

Edit wrangler.jsonc and add the database_id returned by d1 create. Bucket and index names must match the file (memoflare-files, memoflare-vectors).

2. Configure secrets and vars

With OAuth disabled (default MEMOFLARE_OAUTH_ENABLED: "0"), the worker expects a static API bearer for /mcp and /sync:

pnpm exec wrangler secret put MEMORY_BEARER
# Enter a long random token; clients send Authorization: Bearer <token>

Optional CORS origin for browser clients:

pnpm exec wrangler secret put ALLOWED_ORIGIN

3. Apply database migrations

wrangler deploy does not apply D1 migrations. After schema changes (or on first deploy):

pnpm exec wrangler d1 migrations apply memoflare-db --remote

4. Deploy

pnpm install
pnpm run typecheck
pnpm test
pnpm run deploy

Note the Worker URL from the output (e.g. https://memoflare.<subdomain>.workers.dev).

5. Verify

curl -s "https://memoflare.<subdomain>.workers.dev/"

Expected:

{ "name": "Memoflare", "status": "ok", "mode": "cloud" }

MCP (with bearer token):

curl -s -H "Authorization: Bearer YOUR_TOKEN" \
  "https://memoflare.<subdomain>.workers.dev/mcp"

6. Optional — OAuth 2.1 (human consent flow)

  1. Create KV: pnpm exec wrangler kv namespace create OAUTH_KV

  2. Add to wrangler.jsonc:

    "vars": { "MEMOFLARE_OAUTH_ENABLED": "1" },
    "kv_namespaces": [{ "binding": "OAUTH_KV", "id": "<namespace-id>" }]
  3. Set consent password: pnpm exec wrangler secret put MEMOFLARE_OAUTH_PASSWORD

  4. Redeploy. Unauthenticated MCP returns 401 until a user completes /authorize.

Scopes: memos:read, memos:write, config:write, admin. The static MEMORY_BEARER still resolves as admin via resolveExternalToken.

Cloud bindings reference

Binding Resource
MEMOFLARE_DB D1 memoflare-db
MEMOFLARE_FILES R2 memoflare-files
MEMOFLARE_VECTORS Vectorize memoflare-vectors
AI Workers AI (embeddings)
OAUTH_KV KV (OAuth only)

Sync local ↔ cloud

Create .env.cloud (not committed):

MEMORY_CLOUD_URL=https://memoflare.<subdomain>.workers.dev
MEMORY_BEARER=your-cloud-bearer-token
pnpm run sync:push    # local → cloud
pnpm run sync:pull    # cloud → local

Use the same MEMORY_BEARER you configured as a Wrangler secret.

Local Worker dev

After wrangler.jsonc is filled in:

pnpm run dev

Development

pnpm run typecheck
pnpm test

On first install, if native modules fail to build:

pnpm approve-builds
pnpm install

MCP tools (summary)

Tool Purpose
remember Create or replace a memo at a path
read Read memos, directory trees, or workspace bootstrap (core://)
update Append, patch, rename, or edit metadata
forget Trash, restore, or purge memos
search Keyword search or vector similarity

Authentication summary

Mode Behavior
Local loopback HTTP No token by default
Local public bind Requires MEMORY_BEARER or --allow-insecure
Cloud (OAuth off) Requires MEMORY_BEARER on /mcp and /sync
Cloud (OAuth on) OAuth tokens with scopes; static bearer still works as admin
Stdio No token (process isolation)

Project layout

src/
  local.ts          # Node.js entry (HTTP + stdio)
  worker.ts         # Cloudflare Worker entry
  mcp/              # MCP tools and resources
  services/         # Memo pipeline, search, config, directory
  providers/        # Local vs cloud storage/embeddings/vectors
migrations/         # D1 / SQLite schema
tests/              # Vitest suite
config/             # Drizzle config
wrangler.jsonc      # Cloudflare Worker config
docker-compose.yml  # Self-hosted Docker

License

MIT — see LICENSE.

About

MCP server for durable, path-addressed memory for AI agents

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages