内容
# OpenBrain
Fully local AI memory for Apple Silicon. Gives any MCP client persistent semantic memory with vector search — no cloud APIs required.
Everything runs on your Mac: embeddings via MLX on Metal GPU, enrichment via a local LLM, storage in PostgreSQL with pgvector.
Built on the [OB1](https://github.com/NateBJones-Projects/OB1) architecture by [@NateBJones-Projects](https://github.com/NateBJones-Projects).
## Architecture

A Bun MCP server brokers requests from any MCP client to PostgreSQL+pgvector for storage, a local MLX embedding service for vectorization, and a local mlx-lm server for enrichment. Redis caches embeddings and search results. A separate Bun web UI reads directly from PostgreSQL. Everything runs on-device — no cloud APIs in the data path.
## Requirements
- **Apple Silicon Mac** (M1/M2/M3/M4) — required for MLX GPU inference
- **16 GB RAM minimum** for the default model (`Qwen3-8B-4bit`, ~4.5 GB); 32 GB+ lets you run larger enrichment models
- macOS 14+
- [Node.js](https://nodejs.org) 22+ (LTS v24 recommended) and [pnpm](https://pnpm.io) 11+
- [Bun](https://bun.sh) 1.1+ as the runtime (we use `pnpm` to install deps; `bun` to run them)
- Python 3.13+ with [uv](https://docs.astral.sh/uv/)
- [PostgreSQL 17](https://www.postgresql.org/) with [pgvector](https://github.com/pgvector/pgvector) extension
- [Redis](https://redis.io/) (optional but recommended)
- [Firecrawl](https://firecrawl.dev) API key — used for all web page scraping
- [yt-dlp](https://github.com/yt-dlp/yt-dlp) (optional — YouTube transcript extraction)
### Firecrawl
[Firecrawl](https://firecrawl.dev) handles all web-page scraping (markdown extraction, JS rendering, etc.). It's a cloud service; set your key in `.env`:
```
FIRECRAWL_API_KEY=fc-...
```
Without a key, `POST /api/ingest` for web URLs will return an error.
### Quick install (recommended)
```bash
bash installer/bootstrap.sh
```
This runs the full chain: prerequisites (Homebrew packages, Bun, Python venv with `mlx-lm`), database setup, schema, and launchd services. Idempotent — safe to re-run.
### Manual install
If you'd rather install the prerequisites yourself:
```bash
# Homebrew packages
brew install postgresql@17 pgvector redis uv yt-dlp pnpm
brew services start postgresql@17
brew services start redis
# Node 22+ via nvm (skip if you already have one)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
. ~/.nvm/nvm.sh && nvm install --lts && nvm alias default 'lts/*'
# Optional, for Gmail integration via the agents/ subsystem
brew install gogcli
# Bun via its official installer (no Homebrew formula). We use Bun as the
# runtime (Bun.serve, Bun.spawn) but never `bun install` — that hits a
# macOS SIP/provenance issue. pnpm handles deps.
curl -fsSL https://bun.sh/install | bash
```
After installing Bun, restart your shell (or `source ~/.zshrc`) so the `bun` binary is on your `PATH`.
## Quick Start
```bash
# 1. Clone and enter the repo
git clone https://github.com/sajennings79/apple-silicon-openbrain.git
cd apple-silicon-openbrain
# 2. Configure environment
cp .env.example .env
# Edit .env if needed (defaults work for local setup)
# 3. Run setup (creates database, installs Bun + Python deps)
bash scripts/setup.sh
# 4. Create a Python venv for the LLM enrichment server
python3 -m venv ~/.mlx-venv
~/.mlx-venv/bin/pip install mlx-lm
# 5. Start all services (installs as launchd daemons)
bash scripts/install-services.sh
# 6. Verify everything is running
bun run health
```
Or start services manually:
```bash
bun run dev # MCP server (port 6277)
cd embed-service && uv run server.py # Embedding service (port 6278)
~/.mlx-venv/bin/python -m mlx_lm.server \
--model mlx-community/Qwen3-8B-4bit \
--port 8000 --max-tokens 4096 # LLM enrichment (port 8000)
bun run ui # Web UI (port 6279)
```
## First Run: Model Downloads
Models are pulled from Hugging Face Hub the first time each service starts — there's no separate download step. Both services block on startup until the download completes, then come online.
| Model | Size | Used by | Triggered by |
|-------|------|---------|--------------|
| `mlx-community/Qwen3-Embedding-0.6B-4bit-DWQ` | ~400 MB | Embedding service (`:6278`) | FastAPI startup |
| `mlx-community/Qwen3-8B-4bit` (default) | ~4.5 GB | LLM enrichment (`:8000`) | `mlx_lm.server` startup |
The default LLM is sized for 16 GB RAM systems. To trade RAM for quality, override `LLM_MODEL` in `.env` (and the matching `--model` arg in `~/Library/LaunchAgents/com.openbrain.llm.plist`):
| RAM | Suggested model | Disk |
|-----|-----------------|------|
| 16 GB (default) | `mlx-community/Qwen3-8B-4bit` | ~4.5 GB |
| 32 GB | `mlx-community/Qwen3.6-27B-4bit` (dense) or `mlx-community/Qwen3.6-35B-A3B-4bit` (MoE) | ~17 GB |
| 64 GB+ | `mlx-community/Qwen3.5-122B-A10B-4bit` | ~60 GB |
All models are public repos — no Hugging Face token required. Files cache to `~/.cache/huggingface/hub/` and subsequent starts run fully offline.
If you installed the launchd services, the first-run download happens silently in the background. Watch progress with:
```bash
tail -f logs/embed.log # embedding model (~30s on fast connection)
tail -f logs/llm.log # ~2 min for the default 8B model on a fast connection
```
`bun run health` will report the LLM service as down until its download finishes. Interrupted downloads resume on the next start.
## MCP Client Configuration
OpenBrain exposes both HTTP and stdio MCP transports. Configure your client to point at whichever it supports.
**HTTP transport** (recommended — one shared server for all clients):
```json
{
"mcpServers": {
"openbrain": {
"type": "http",
"url": "http://localhost:6277/mcp"
}
}
}
```
**stdio transport** (for clients that spawn the server as a subprocess):
```json
{
"mcpServers": {
"openbrain": {
"type": "stdio",
"command": "bun",
"args": ["run", "/path/to/openbrain/src/stdio.ts"]
}
}
}
```
The exact config-file location depends on your client (e.g. `.mcp.json` in a project root, or a global config under your home directory).
## MCP Tools
| Tool | Description |
|------|-------------|
| **StoreMemory** | Store text with automatic embedding, LLM enrichment (summary, tags, entities), and cross-memory linking |
| **SearchMemory** | Semantic vector search with optional filters (type, source, tags, date range) |
| **RecallMemory** | Retrieve a specific memory by UUID |
| **ListMemories** | Paginated list with filters |
| **UpdateMemory** | Update content or metadata; re-embeds and re-enriches on content changes |
| **DeleteMemory** | Soft-delete a memory by UUID |
## Services
| Service | Port | Purpose |
|---------|------|---------|
| MCP Server | 6277 | MCP protocol + URL ingestion API |
| Embedding Service | 6278 | Local MLX embeddings (Qwen3-Embedding-0.6B, 1024-dim) |
| LLM Server | 8000 | Local MLX enrichment (Qwen3-8B by default) |
| Web UI | 6279 | Dashboard for browsing and searching memories |
| PostgreSQL | 5432 | Memory storage with pgvector |
| Redis | 6379 | Embedding + search result caching |
## Web UI
The web UI at `http://localhost:6279` provides:
- Memory search and browsing with tag/source/type filters
- Dashboard with statistics (total memories, per source, per type)
- Monthly histogram and 30-day sparkline
- New memory creation form
- Tag management
## URL Ingestion
Save web pages and YouTube transcripts directly to memory using the bookmarklet.
1. Open `scripts/bookmarklet.html` in your browser
2. Drag the bookmarklet link to your bookmarks bar
3. Click it on any page to save the content to OpenBrain
**Web pages** are scraped via [Firecrawl](https://firecrawl.dev) (markdown extraction, JS rendering). Set `FIRECRAWL_API_KEY` in `.env` — without it, web ingestion will error.
**YouTube URLs** are handled locally via `yt-dlp` (install: `brew install yt-dlp`). Transcripts are extracted and stored with video metadata.
## Gradual Setup
You don't need all services running to get started:
1. **Minimum**: PostgreSQL + Embedding Service + MCP Server — gives you store and search
2. **Add enrichment**: Start the mlx-lm server — memories get auto-enriched with summaries and tags
3. **Add caching**: Start Redis — faster repeated searches and embedding lookups
4. **Add UI**: Start the web UI — browse and manage memories visually
5. **Add ingestion**: Set `FIRECRAWL_API_KEY` in `.env` and install the bookmarklet — save web content from your browser.
To skip enrichment entirely (e.g., while setting up), set `DISABLE_ENRICHMENT=true` in `.env`.
## Sources (recurring ingestion)
OpenBrain pulls content into memory on a schedule. Each **source** is a row in the `sources` table with a kind (`rss`, `mail`, or `webpage`), config, and an interval.
```bash
# Create an RSS source via the REST API:
echo '{"kind":"rss","name":"HN","config":{"feedUrl":"https://news.ycombinator.com/rss"},"intervalSeconds":3600}' \
| curl -X POST http://localhost:6277/api/sources -H 'content-type: application/json' --data @-
# Sync now:
curl -X POST http://localhost:6277/api/sources/<id>/sync
# Sync everything that's due:
curl -X POST http://localhost:6277/api/sources/poll-due
```
The Mac app (Phase 3+) drives `poll-due` from an hourly timer and exposes a UI for source CRUD. Until then, talk to the REST API directly. (The timer is just a heartbeat — each source's own `intervalSeconds` decides when it's actually due.)
### Mail sources via `gog`
To pull Gmail into memory, install [gogcli](https://github.com/steipete/gogcli) and authenticate:
```bash
brew install gogcli
gog auth add you@gmail.com
```
Then create a `mail` source:
```json
{
"kind": "mail",
"name": "Personal Gmail (last day)",
"config": {
"account": "you@gmail.com",
"query": "newer_than:1d -in:promotions -in:spam -in:trash",
"maxMessages": 25
},
"intervalSeconds": 900
}
```
**Important**: launchd-managed services have no TTY for `gog`'s keyring password prompt. Set `GOG_KEYRING_PASSWORD` in `.env` (gitignored) to your gog keyring password, then restart the MCP service. Without this, mail syncs will fail with `"no TTY available for keyring file backend password prompt"`.
## Recurring agents
OpenBrain ships with a small **starter pack** of prompt-driven agents that run on a schedule, query the memory store, call the local LLM, and write the result back as a new memory. All of this happens locally — no API keys.
```bash
# Run a shipped agent once, see the output:
bun run agents/run-agent.ts agents/prompts/newsletter-digest.md
# Or via the wrapper:
agents/run-agent.sh newsletter-digest.md
```
Shipped prompts live in `agents/prompts/`. Bring your own by dropping additional `.md` files into a directory of your choice (the [Mac app](apps/mac/) defaults to `~/Developer/claude-cron/prompts/`). See `agents/prompts/README.md` for the format.
## Remote Access via Tailscale
To access OpenBrain from other devices on your network:
```bash
# Expose MCP server over Tailscale HTTPS
tailscale serve --bg --https=6443 http://localhost:6277
```
Then update your bookmarklet URL to use `https://your-machine.tail-xxxxx.ts.net:6443` and set `AUTH_TOKEN` in `.env` to protect the endpoint.
## Development
```bash
bun run dev # MCP server with auto-reload
bun run ui # Web UI
bun run health # Check all service health
bun run db:generate # Generate Drizzle migration from schema changes
bun run db:migrate # Apply pending migrations
# Re-enrich memories missing summaries
bun run scripts/enrich-backlog.ts
```
## Managing Services
```bash
# Install as launchd daemons (auto-start on boot)
bash scripts/install-services.sh
# Uninstall all services
bash scripts/uninstall-services.sh
# Restart a single service
kill $(lsof -ti :6277) # KeepAlive restarts it automatically
# View logs
tail -f logs/mcp.log
tail -f logs/embed.log
tail -f logs/llm.log
```
## License
MIT
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器