mor
v0.14.2
Published
A shared memory store for humans and AI
Maintainers
Readme
mor
[!WARNING] This is a personal project. I maintain it for my own use and share it because others might find it useful. Feature PRs are unlikely to be merged — if you have an idea, start a discussion first. Fork freely — it's MIT licensed.
A shared memory store for humans and AI. Plain markdown files with SQLite full-text search.
Use it as a CLI, an MCP server (Claude Code, Claude Desktop, Cursor, etc.), or an HTTP server for accessing memories across machines.
Install
npm install -g morRequires Node.js 20+.
Quick start
# Add memories
echo "Always use snake_case for Python variables" | mor add -t "Python naming"
mor add notes.md -t "Meeting notes" --tags "meeting,project-x"
mor add https://raw.githubusercontent.com/owner/repo/main/config.ts
# Search (FTS5 — tokenized, stemmed)
mor find "python naming"
# Grep (literal substring or regex)
mor grep "snake_case"
mor grep -i "todo"
mor grep -E "async\s+function"
mor grep -w "Beer" -n -C 2
# Read, edit, copy, remove
mor cat "python naming"
mor edit "python naming"
mor cp "python naming" ./out.md
mor rm "python naming"
# List
mor ls
mor ls -lCommands
| Command | Description |
| ------------------- | --------------------------------------------------------------------------------------------------------------- |
| find <query> | Full-text search (--limit, -s threshold, --json) |
| grep <pattern> | Substring or regex search (-i, -E regex, -w word, -n line numbers, -l files only, -A/-B/-C context) |
| add [file\|url] | Add from file, URL, stdin, or $EDITOR (-t title, -d description, --tags, --type) |
| cat <query> | Print content (--raw for frontmatter, --links for cross-references) |
| cp <query> <dest> | Copy content to file |
| edit <query> | Open in $EDITOR (--raw to edit frontmatter) |
| update <query> | Update metadata or content (-t title, -d description, --tags, --type, --content-from) |
| rm <query> | Remove a memory |
| links [query] | Show cross-references for a memory (--broken to find dangling links) |
| ls | List all (--limit, -l long, --tags, --types) |
| sync | Pull, commit, and push the memory folder via git |
| reindex | Rebuild search index |
| import <dir> | Import .md files from a directory |
| mcp | Start MCP server (stdio) |
| serve | Start HTTP server (-p port, -H host, --token, --mcp) |
| login | Authenticate with a remote server via OAuth (-s server URL) |
Queries resolve in order: full UUID, UUID prefix (8+ chars), filename, FTS search.
find, grep, and ls support shared filters: --type, --tag, --repo, --ext (all support glob patterns).
MCP server
Add to your Claude Code or Claude Desktop config:
{
"mcpServers": {
"memory": {
"command": "mor",
"args": ["mcp"]
}
}
}Tools: memory_search, memory_read, memory_create, memory_update, memory_remove, memory_list, memory_grep.
To make sure Claude Code checks mor first when you ask it to recall something, add this to ~/.claude/CLAUDE.md:
## Memory
When the user asks to recall, find, check, or reuse something they previously saved
or remembered — use the `mor` MCP server tools (`memory_search`, `memory_read`,
`memory_list`). This is the user's primary memory store containing code snippets,
files, and reference notes. Always check mor before saying something wasn't found.Remote access
Run the server on one machine, access from anywhere:
# Server
mor serve --port 7677 --token mypassphrase --mcpMCP clients (Claude Code, Claude Desktop, etc.)
Point your MCP client at the server URL — no secret in the config:
{
"mcpServers": {
"memory": {
"type": "url",
"url": "http://mybox.tail1234.ts.net:7677/mcp"
}
}
}The client discovers auth via WWW-Authenticate → OAuth metadata → browser passphrase flow, all automatic.
CLI client
# OAuth login — saves server URL to config and credentials to credentials.json
mor login -s http://mybox.tail1234.ts.net:7677
# All commands now proxy to the remote server
mor find "python naming"Or configure a direct token instead:
// ~/.config/mor/config.json
{
"server": {
"url": "http://mybox.tail1234.ts.net:7677",
"token": "mypassphrase",
},
}OAuth tokens auto-refresh on expiry.
Authentication
When --token is set, all routes require auth. Two methods work everywhere:
- Bearer token:
Authorization: Bearer <passphrase>or?token=<passphrase> - OAuth access token: obtained via the OAuth flow (
mor loginor MCP client auto-discovery)
Unauthenticated requests get a 401 with a WWW-Authenticate header pointing to the OAuth discovery endpoint.
HTTP API
| Method | Path | Description |
| -------- | ------------------------------------------------------------ | -------------------------------------------------------------------- |
| GET | /health | Health check |
| GET | /memories?limit=N&offset=N | List all |
| GET | /memories/search?q=...&limit=N&offset=N | FTS search |
| GET | /memories/grep?q=...&limit=N&offset=N&ignoreCase=1®ex=1 | Substring or regex search |
| GET | /memories/:query | Read one |
| GET | /memories/:query/links | Get forward and backlinks |
| POST | /memories | Create ({title, content, description?, tags?, type?, repository?}) |
| PUT | /memories/:query | Update ({title?, description?, content?, tags?, type?}) |
| DELETE | /memories/:query | Remove |
| POST | /mcp | MCP protocol (streamable HTTP) |
Embeddings (experimental)
Optionally augment FTS search with vector similarity. Configure in ~/.config/mor/config.json:
{
"embedding": {
"provider": "openai",
"model": "text-embedding-3-small",
"dimensions": 1536
}
}Providers: openai (or compatible API via baseUrl), azure-openai, ollama. Run mor reindex after configuring.
Azure OpenAI uses AZURE_OPENAI_API_KEY (or apiKey in config) and requires a deployment name (defaults to model name).
Storage
Memories are markdown files with YAML frontmatter, stored in ~/.config/mor/memories/ with a SQLite index at ~/.config/mor/index.db. Override with MOR_HOME.
~/.config/mor/
config.json
credentials.json # OAuth tokens (created by `mor login`)
index.db # search index
oauth.db # OAuth clients and tokens (server-side)
memories/
python-naming-a1b2.md
meeting-notes-c3d4.mdFiles are human-readable and git-friendly. Use mor sync to pull, commit, and push if the memory folder is a git repo. Enable autosync to sync automatically after every add, update, or remove:
{
"autosync": true
}License
MIT
