reflect-memory
Integrates with Reflect Memory's multi-vendor chat, enabling Perplexity to access and write memories.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@reflect-memoryadd a memory: meeting with John at 3pm tomorrow"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Reflect Memory
Privacy-first AI memory system. Memories are structured, editable, and deletable. Manual writes are always available; Ambient Mode (default On) adds silent capture and silent retrieval via MCP tools, with a per-user opt-out to approval-gated Suggested Memories. The host model stays stateless — it only sees what Reflect returns.
Requirements
Node.js >= 20.0.0 (LTS)
An OpenAI-compatible API key (OpenAI, local model via ollama, etc.)
Related MCP server: Engram
Setup
npm installEnvironment Variables
Required:
export RM_API_KEY="your-secret-api-key" # User key -- full access to all endpoints
export RM_MODEL_API_KEY="sk-..." # Your OpenAI (or compatible) API key
export RM_MODEL_NAME="gpt-4o-mini" # Model identifierOptional:
export RM_PORT=3000 # HTTP port (default: 3000)
export RM_DB_PATH="/data/reflect-memory.db" # SQLite file path (default on Railway)
export RM_MODEL_BASE_URL="https://api.openai.com/v1" # Model API base URL
export RM_MODEL_TEMPERATURE=0.7 # Temperature (default: 0.7)
export RM_MODEL_MAX_TOKENS=1024 # Max tokens (default: 1024)
export RM_SYSTEM_PROMPT="Your custom prompt" # System prompt for AI queriesAgent keys (per-vendor, optional):
export RM_AGENT_KEY_CHATGPT="agent-key-for-chatgpt" # Registers vendor "chatgpt"
export RM_AGENT_KEY_CLAUDE="agent-key-for-claude" # Registers vendor "claude"
# RM_AGENT_KEY_<NAME> -- any env var matching this pattern registers a vendorDashboard multi-user auth (required for dashboard deployment):
export RM_DASHBOARD_SERVICE_KEY="..." # Shared with dashboard. Generate: openssl rand -hex 32
export RM_DASHBOARD_JWT_SECRET="..." # Must match dashboard AUTH_SECRET. Minimum 32 characters.Multi-vendor chat (dashboard Chat tab -- enables GPT, Claude, Gemini, Perplexity, Grok):
export RM_CHAT_OPENAI_KEY="sk-..." # Defaults to RM_MODEL_API_KEY if omitted
export RM_CHAT_ANTHROPIC_KEY="sk-ant-..." # Claude (console.anthropic.com)
export RM_CHAT_GOOGLE_KEY="..." # Gemini (aistudio.google.com)
export RM_CHAT_PERPLEXITY_KEY="..." # Perplexity (perplexity.ai/settings/api)
export RM_CHAT_XAI_KEY="..." # Grok (x.ai)Each agent key gives the vendor scoped access:
Can write memories via
POST /agent/memoriesCan query via
POST /query(sees only memories withallowed_vendorscontaining"*"or their vendor name)Can check identity via
GET /whoamiCannot access user endpoints (
POST /memories,GET /memories/:id,PUT /memories/:id,DELETE /memories/:id,POST /memories/list)
Run
Development (with hot reload via tsx):
npm run devProduction:
npm run build
npm startAPI
All requests (except /health) require the Authorization header:
Authorization: Bearer your-secret-api-keyHealth check (no auth required)
curl -s https://api.reflectmemory.com/health | jqWho am I? (identity debugging)
curl -s https://api.reflectmemory.com/whoami \
-H "Authorization: Bearer your-secret-api-key" | jqResponse:
{ "role": "user", "vendor": null }With an agent key:
{ "role": "agent", "vendor": "chatgpt" }Create a memory (user path)
curl -s -X POST http://localhost:3000/memories \
-H "Authorization: Bearer your-secret-api-key" \
-H "Content-Type: application/json" \
-d '{
"title": "Project deadline",
"content": "The API migration must be completed by end of Q3 2026.",
"tags": ["work", "deadlines"]
}' | jqallowed_vendors is optional for user writes. If omitted, defaults to ["*"] (all vendors can see it). To restrict:
curl -s -X POST http://localhost:3000/memories \
-H "Authorization: Bearer your-secret-api-key" \
-H "Content-Type: application/json" \
-d '{
"title": "Private note",
"content": "Only Claude should see this.",
"tags": ["private"],
"allowed_vendors": ["claude"]
}' | jqCreate a memory (agent path)
Agents must use POST /agent/memories. The origin field is set server-side from the agent's key -- it cannot be self-reported. allowed_vendors is required.
curl -s -X POST http://localhost:3000/agent/memories \
-H "Authorization: Bearer agent-key-for-chatgpt" \
-H "Content-Type: application/json" \
-d '{
"title": "ChatGPT learned this",
"content": "User prefers bullet points over paragraphs.",
"tags": ["preference"],
"allowed_vendors": ["chatgpt"]
}' | jqResponse (201):
{
"id": "a1b2c3d4-...",
"user_id": "...",
"title": "ChatGPT learned this",
"content": "User prefers bullet points over paragraphs.",
"tags": ["preference"],
"origin": "chatgpt",
"allowed_vendors": ["chatgpt"],
"created_at": "2026-02-08T...",
"updated_at": "2026-02-08T..."
}Read a memory by ID
curl -s http://localhost:3000/memories/MEMORY_ID \
-H "Authorization: Bearer your-secret-api-key" | jqList memories (explicit filter required)
All memories:
curl -s -X POST http://localhost:3000/memories/list \
-H "Authorization: Bearer your-secret-api-key" \
-H "Content-Type: application/json" \
-d '{ "filter": { "by": "all" } }' | jqBy tags:
curl -s -X POST http://localhost:3000/memories/list \
-H "Authorization: Bearer your-secret-api-key" \
-H "Content-Type: application/json" \
-d '{ "filter": { "by": "tags", "tags": ["work"] } }' | jqUpdate a memory (full replacement)
Now requires allowed_vendors in the body (full replacement -- all fields required).
curl -s -X PUT http://localhost:3000/memories/MEMORY_ID \
-H "Authorization: Bearer your-secret-api-key" \
-H "Content-Type: application/json" \
-d '{
"title": "Project deadline (revised)",
"content": "The API migration deadline has been extended to Q4 2026.",
"tags": ["work", "deadlines", "revised"],
"allowed_vendors": ["*"]
}' | jqDelete a memory
curl -s -X DELETE http://localhost:3000/memories/MEMORY_ID \
-H "Authorization: Bearer your-secret-api-key" -w "\nHTTP %{http_code}\n"Returns 204 No Content on success. The row is gone.
Query the AI (with memory context)
User key sees all memories matching the filter:
curl -s -X POST http://localhost:3000/query \
-H "Authorization: Bearer your-secret-api-key" \
-H "Content-Type: application/json" \
-d '{
"query": "When is the API migration deadline?",
"memory_filter": { "by": "tags", "tags": ["deadlines"] }
}' | jqAgent key sees only memories where allowed_vendors contains "*" or the agent's vendor name:
curl -s -X POST http://localhost:3000/query \
-H "Authorization: Bearer agent-key-for-chatgpt" \
-H "Content-Type: application/json" \
-d '{
"query": "What are the user preferences?",
"memory_filter": { "by": "all" }
}' | jqThe vendor_filter field in the receipt shows which vendor filter was applied (null for users, vendor name for agents).
MCP Server
Reflect Memory includes a built-in MCP (Model Context Protocol) server for native integration with Claude, Cursor, and other MCP-compatible tools.
Endpoint: /mcp (proxied through the main API — single port, no extra config)
Transport: Streamable HTTP (MCP clients must use streamable-http / streamableHttp)
Enabling MCP: Set at least one agent key environment variable. Agent keys serve double duty: they tell the server to start the MCP endpoint and authenticate requests against it.
export RM_AGENT_KEY_CURSOR="your-cursor-key"
export RM_AGENT_KEY_CLAUDE="your-claude-key"Without any RM_AGENT_KEY_* variables set, the /mcp endpoint returns 404.
Cursor — create .cursor/mcp.json in your project:
{
"mcpServers": {
"reflect-memory": {
"type": "streamable-http",
"url": "https://api.reflectmemory.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_AGENT_KEY"
}
}
}
}Claude — go to Claude.ai Settings > Connectors, click +, paste https://api.reflectmemory.com/mcp. Claude handles OAuth automatically.
MCP tools (20):
Group | Tools |
Read / discovery |
|
Write / lifecycle |
|
Graph / threads |
|
Org / team |
|
Ambient |
|
See integrations/cursor/README.md and integrations/claude/README.md for detailed setup guides. Design notes: docs/design/ambient-memory-mode.md. Full architecture: ARCHITECTURE.md.
Ambient Mode
Ambient Mode lowers friction without removing control. Preference is On by default (including guests); users toggle it in the dashboard Settings. The preference carries guest → signup.
Setting | Behavior |
On (default) | Before substantive replies, agents call |
Off | Manual writes remain; |
Architecture constraints (Phase 1):
Captures write to the personal pool only. Org/team visibility still requires an explicit
share_memory.Provenance tags:
auto_captured,ambient-memory-mode,ambient:cortex. Theoriginfield stays the writing vendor (cursor,claude,chatgpt, …).Strong matches (or refinements of a just-retrieved memory) update in place and write
memory_versionshistory instead of creating sibling rows.Consolidation is trigger-based (volume of new ambient captures or age threshold), env-tunable — not a silent background cron that bypasses the API.
Connect-time session briefing includes Ambient instructions so MCP clients know which path to follow.
REST: PATCH /users/me/ambient-mode. Implementation: src/cortex-service.ts.
Team Memories
Team Memories let multiple users share context through a shared pool. Any team member can share personal memories with the team, and all members can read them from any connected tool.
# Create a team
curl -s -X POST http://localhost:3000/teams \
-H "Authorization: Bearer your-secret-api-key" \
-H "Content-Type: application/json" \
-d '{"name": "My Team"}' | jq
# Invite a member
curl -s -X POST http://localhost:3000/teams/TEAM_ID/invite \
-H "Authorization: Bearer your-secret-api-key" \
-H "Content-Type: application/json" \
-d '{"email": "teammate@example.com"}' | jqTeam tools (read_team_memories, share_memory) are available in all MCP clients once the user belongs to a team. The team API endpoints (/teams, /teams/:id/invite, etc.) use standard Bearer token auth.
Docker Quick Start (Private Deploy)
Run Reflect Memory locally with Docker Compose. Data stays on your machine.
Upgrading? The container runs as a non-root user. If you have an existing
/datavolume with root-owned files, rundocker compose down && docker compose --profile isolated-hosted up --buildto rebuild. If the database fails to open, fix volume permissions:docker run --rm -v rm_data_isolated:/data node:20-bookworm-slim chown -R 65534:65534 /data
Clone the repo and create a
.envfile:
git clone https://github.com/van-reflect/Reflect-Memory.git
cd Reflect-Memory# .env
RM_API_KEY=your-api-key
RM_MODEL_API_KEY=sk-...
RM_MODEL_NAME=gpt-4o-mini
# MCP — at least one agent key is required to enable /mcp
RM_AGENT_KEY_CURSOR=pick-any-strong-secret
RM_AGENT_KEY_CLAUDE=pick-any-strong-secretBuild and start:
docker compose --profile isolated-hosted up --build -dVerify:
curl -s http://localhost:3000/health | jq
# → { "service": "reflect-memory", "status": "ok", ... }
curl -s http://localhost:3000/whoami \
-H "Authorization: Bearer your-api-key" | jq
# → { "role": "user", "vendor": null }Connect Cursor to your local instance:
{
"mcpServers": {
"reflect-memory": {
"type": "streamable-http",
"url": "http://localhost:3000/mcp",
"headers": {
"Authorization": "Bearer your-RM_AGENT_KEY_CURSOR-value"
}
}
}
}Important: The /mcp endpoint uses agent keys for auth, not RM_API_KEY. Your RM_API_KEY works for REST/curl calls, but MCP clients must use the corresponding RM_AGENT_KEY_* value.
Production / private deploy notes
Hosted production (api.reflectmemory.com) runs on self-managed infrastructure (Docker + reverse proxy), not a serverless platform. For private deploy, prefer Docker Compose above or the Helm chart under charts/reflect-memory.
MCP / SSE: In multi-process production setups, route /mcp directly to the MCP port (see infra/README.md). Proxying long-lived MCP sessions through the main API process can break Streamable HTTP / SSE clients.
PaaS (optional): The app also runs on any Node host that provides a persistent volume for SQLite (e.g. Railway with a /data mount). Set RM_API_KEY, RM_MODEL_API_KEY, RM_MODEL_NAME, and at least one RM_AGENT_KEY_* (or RM_PUBLIC_URL for OAuth). Build: npm run build · Start: npm start.
Verification Checklist
Whoami
# User key
curl -s https://api.reflectmemory.com/whoami \
-H "Authorization: Bearer YOUR_USER_KEY" | jq
# → { "role": "user", "vendor": null }
# Agent key (ChatGPT)
curl -s https://api.reflectmemory.com/whoami \
-H "Authorization: Bearer YOUR_CHATGPT_AGENT_KEY" | jq
# → { "role": "agent", "vendor": "chatgpt" }Agent write
curl -s -X POST https://api.reflectmemory.com/agent/memories \
-H "Authorization: Bearer YOUR_CHATGPT_AGENT_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Agent test",
"content": "Written by chatgpt agent.",
"tags": ["agent-test"],
"allowed_vendors": ["chatgpt"]
}' | jq
# → origin: "chatgpt", allowed_vendors: ["chatgpt"]Agent query scoping
# Agent sees only memories with allowed_vendors containing "*" or "chatgpt"
curl -s -X POST https://api.reflectmemory.com/query \
-H "Authorization: Bearer YOUR_CHATGPT_AGENT_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "What do you know?",
"memory_filter": { "by": "all" }
}' | jq '.memories_used | length'
# → vendor_filter: "chatgpt" in receiptUser sees all
# User sees every memory regardless of allowed_vendors
curl -s -X POST https://api.reflectmemory.com/memories/list \
-H "Authorization: Bearer YOUR_USER_KEY" \
-H "Content-Type: application/json" \
-d '{ "filter": { "by": "all" } }' | jq '.memories | length'Agent route restriction
# Agent cannot hit user-only endpoints
curl -s -X POST https://api.reflectmemory.com/memories \
-H "Authorization: Bearer YOUR_CHATGPT_AGENT_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"x","content":"x","tags":["x"]}' | jq
# → { "error": "Agent keys cannot access this endpoint" } (403)Persistence (data survives redeploy)
Create a memory, note the ID
Restart or redeploy the container (volume must persist)
Read the memory by ID -- should still exist
Architecture
User key → POST /memories → Memory Service → SQLite (origin: "user")
→ GET /memories/:id → Memory Service → SQLite
→ POST /memories/list → Memory Service → SQLite
→ PUT /memories/:id → Memory Service → SQLite
→ DELETE /memories/:id → Memory Service → SQLite
Agent key → POST /agent/memories → Memory Service → SQLite (origin: vendor)
→ POST /query → Memory Service (vendor-filtered read)
→ Context Builder → Model Gateway → QueryReceipt
→ MCP /mcp → Memory Service (+ Ambient cortex when On)
Both → GET /health (no auth)
→ GET /whoami (returns role + vendor)
→ POST /query (vendor filter from key, not body)See ARCHITECTURE.md for Ambient Mode, visibility, and deployment detail.
Hard Invariants
Explicit Intent -- Requests declare what they want. Ambient Mode is a user preference (default On) that authorizes agent-mediated capture/retrieve tools — not opaque background mutation.
Hard Deletion -- User-facing delete removes the row from the active store (dashboard soft-delete + purge cycle for recovery windows; hard purge for retention jobs).
Pure Context Builder -- No I/O. Same inputs, same output. Always.
No autonomous model writes -- The host LLM cannot mutate memory except by calling Reflect tools/APIs. Ambient capture still goes through
capture_session_memories→ memory service, with provenance tags and audit events. Toggle Off restores approval-gated Suggested Memories.Deterministic Visibility -- Every query response includes the full receipt: memories used, prompt sent, model config, vendor filter. Ambient Phase 1 captures stay personal until an explicit share.
Hard Security Constraints
/agent/memoriesmust never acceptoriginin the body. If present, hard 400 (enforced byadditionalProperties: falsein the schema).Agent keys must never be allowed to call user endpoints. Agents can only hit
/agent/*,/query,/whoami,/health. Everything else returns 403.
This server cannot be deployed
Maintenance
Related MCP Connectors
Person-owned AI memory that learns, not just stores — portable context for any MCP client.
Persistent, portable memory for AI assistants — your private memory graph, from any MCP client.
Private, portable memory and reusable skills for AI agents.
Personal AI memory — gives every AI agent shared, persistent memory of you
Related MCP Servers
- AlicenseAqualityDmaintenanceA privacy-first memory layer for AI that securely bridges local knowledge with AI assistants through MCP tools, with intelligent redaction and local vector database.25 npm1MIT
- AlicenseNot gradedqualityDmaintenanceA local-first memory MCP server that enables storing, searching, and managing personal memories with hybrid keyword and semantic recall, all on-device.26 npmMIT
- AlicenseNot gradedqualityCmaintenanceUser-owned AI memory layer exposing persistent memory, task graph, and semantic search via MCP server, with data stored on DWN under user control.6 npmApache 2.0
- AlicenseNot gradedqualityDmaintenanceA local-first memory server for AI tools that provides cross-tool, consent-gated, and auditable memory management via MCP.AGPL 3.0