Open Brain MCP
A self-hosted second brain MCP server that enables capturing thoughts with deduplication and semantic search using local embeddings and PostgreSQL with pgvector, all running on your own hardware.
README
open-brain-mcp
A self-hosted second brain MCP server — capture thoughts from any MCP client, search them semantically, keep everything on hardware you control.
Inspired by Nate B. Jones's Open Brain (OB1), rebuilt with zero required cloud AI dependencies: local Postgres + pgvector, local fastembed embeddings (BAAI/bge-small-en-v1.5, 384-dim). No Supabase, no hosted embedding API required for core operation.
Project state (2026-07-20): usable alpha / production-personal.
Running in production on a single VM for Miss Minutes (Hermes agent) with optional claude.ai remote connector. API surface is stable enough for daily use; expect small breaking changes until 1.0. Not a multi-tenant SaaS.
Current status
| Area | State |
|---|---|
| stdio MCP (local agents) | Stable — full tool set |
| HTTP MCP for claude.ai | Stable — capture_thought + search_thoughts only |
| Embeddings | Local CPU via fastembed (first run downloads model) |
| Multi-user auth | None — protect HTTP with secret URL path + network controls |
| HA / replication | Not built — single Postgres |
| Obsidian sync | Out of band — vault is a client/ingest source, not embedded |
| Schema migrations | Manual SQL (see below) |
Architecture in one line: one Postgres database on your server; every agent (Hermes, Claude Code, claude.ai, OpenCode, …) is just an MCP client.
Claude.ai ──HTTP MCP──┐
Hermes/Discord ─stdio─┼──► open-brain-mcp ──► Postgres+pgvector (you host)
Laptop agent ──stdio/TS┘
Tools
| Tool | stdio | HTTP (claude.ai) | Purpose |
|---|---|---|---|
capture_thought |
✅ | ✅ | Store thought (fingerprint dedupe) + optional JSON metadata |
search_thoughts |
✅ | ✅ | Semantic search + threshold + metadata filter |
recent_thoughts |
✅ | — | Latest N |
get_thought |
✅ | — | Fetch by id |
brain_stats |
✅ | — | Counts / breakdown |
brain_health |
✅ | — | DB + embed model check |
Requirements
- Python 3.11+
- Postgres 15+ with pgvector
- ~500MB+ RAM for embedding model once loaded
Database
sudo -u postgres psql -c "CREATE USER openbrain WITH PASSWORD '…';"
sudo -u postgres psql -c "CREATE DATABASE openbrain OWNER openbrain;"
sudo -u postgres psql -d openbrain -c "CREATE EXTENSION IF NOT EXISTS vector;"
Minimal schema (384-dim):
CREATE TABLE IF NOT EXISTS thoughts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
content TEXT NOT NULL,
metadata JSONB NOT NULL DEFAULT '{}',
fingerprint TEXT,
embedding vector(384),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE UNIQUE INDEX IF NOT EXISTS thoughts_fingerprint_uidx ON thoughts (fingerprint)
WHERE fingerprint IS NOT NULL;
CREATE INDEX IF NOT EXISTS thoughts_embedding_ivfflat ON thoughts
USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
-- similarity helper used by search (cosine distance)
CREATE OR REPLACE FUNCTION match_thoughts(
query_embedding vector(384),
match_threshold float DEFAULT 0.35,
match_count int DEFAULT 8,
metadata_filter jsonb DEFAULT '{}'::jsonb
) RETURNS TABLE (
id uuid,
content text,
metadata jsonb,
created_at timestamptz,
similarity float
) LANGUAGE sql STABLE AS $$
SELECT t.id, t.content, t.metadata, t.created_at,
1 - (t.embedding <=> query_embedding) AS similarity
FROM thoughts t
WHERE t.embedding IS NOT NULL
AND 1 - (t.embedding <=> query_embedding) >= match_threshold
AND (metadata_filter = '{}'::jsonb OR t.metadata @> metadata_filter)
ORDER BY t.embedding <=> query_embedding
LIMIT match_count;
$$;
If your live DB already has a compatible
match_thoughts/thoughtsschema from an earlier OB1-inspired setup, keep it — adjust only if dimensions differ.
Install
git clone https://github.com/lazo99/open-brain-mcp.git
cd open-brain-mcp
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
Credentials (never commit):
# ~/.secrets/open-brain.env
DATABASE_URL=postgresql://openbrain:***@127.0.0.1:5432/openbrain
OPEN_BRAIN_EMBED_MODEL=BAAI/bge-small-en-v1.5
# HTTP / claude.ai only:
OPEN_BRAIN_REMOTE_SECRET=long-random-string
# optional convenience:
# OPEN_BRAIN_REMOTE_URL=https://brain.example.com/<secret>/mcp
Run
stdio (Hermes, Claude Code, OpenCode, Cursor, …)
./run.sh
# or:
claude mcp add open-brain -- /path/to/open-brain-mcp/run.sh
run.sh sources ~/.secrets/open-brain.env when present.
HTTP for claude.ai (server_http.py)
Minimal streamable-HTTP surface (capture_thought + search_thoughts only).
- Listens on
127.0.0.1:8090 - MCP path:
/{OPEN_BRAIN_REMOTE_SECRET}/mcp - Put a reverse proxy or Cloudflare Tunnel in front (e.g.
brain.example.com) - The URL path is the credential (claude.ai custom connectors typically cannot set arbitrary auth headers)
export DATABASE_URL=…
export OPEN_BRAIN_REMOTE_SECRET=…
.venv/bin/python server_http.py
In claude.ai: Settings → Connectors → add remote MCP → paste:
https://brain.example.com/<OPEN_BRAIN_REMOTE_SECRET>/mcp
Remote stdio (second machine)
Keep Postgres bound to localhost. Bridge with SSH/Tailscale:
#!/usr/bin/env bash
exec ssh user@your-vm '~/Code/open-brain-mcp/run.sh'
Register that script as the MCP command on the laptop.
Production notes (reference deployment)
Personal production pattern used by the author:
- Single GCP VM, Postgres local, Tailscale for admin
open-brain-web.serviceruns HTTP MCP as a locked-down user- Cloudflare Tunnel hostname →
127.0.0.1:8090 - Hermes Agent on the same VM uses stdio MCP for full tools
- claude.ai uses HTTP MCP for capture/search only
- Secrets: env files + password manager + optional cloud secret manager — not git
Security
- Treat HTTP secret URLs like passwords; rotate if leaked
- Prefer localhost + tunnel over public bind
- DB user should only need rights on
thoughts(+ sequence/functions used) - Do not log request URLs that contain the secret path
Roadmap (honest)
- [ ] Packaged SQL migration files in-repo
- [ ] Optional token header auth if/when claude.ai supports it cleanly
- [ ] Obsidian plugin or documented ingest recipe
- [ ] Metrics / backup docs
- [ ] 1.0 when schema + HTTP auth story freeze
License
MIT
Related
- Upstream idea: OB1
- This repo: https://github.com/lazo99/open-brain-mcp
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.