Skip to content

Repository files navigation

OpenBrain MCP Server

A self-hosted AI memory layer with typed knowledge tables, hybrid search, and session handoff. Built for Onramp and any MCP-compatible AI client.

One Postgres database. One MCP endpoint. Every AI tool you use shares the same memory.


Lineage

Inspired by Nate B. Jones's OB1 (Open Brain) and the broader Open Brain community. This is an independent implementation — no OB1 code is used. Built from scratch in Python, incorporating architectural lessons from community implementations.

OB1 established the vision: one database, one protocol, every AI tool shares the same memory. This project builds on that vision with a different language, different schema, and additional capabilities learned from real-world deployments.

What's different from OB1

OB1 OpenBrain MCP
Language TypeScript on Deno Python (FastMCP)
Database Supabase (hosted) Self-hosted Postgres + pgvector
Schema Single thoughts table Typed tables: rules, facts, incidents, tasks, documents
Embeddings OpenRouter only Ollama (default), OpenAI, OpenRouter
MCP tools 4 12 (adds boot, recall, supersede, session lifecycle, browse, forget, update, rename_project)
Search Vector cosine Hybrid (vector + Postgres BM25 keyword)
Validation SHA fingerprint dedup on capture Write gate: headline/body word limits + semantic-similarity dedup
Session tracking None start_session / end_session with handoff notes
Memory lifecycle Manual only Reactivation tracking on facts (recall bumps the score; periodic decay is scaffolded but disabled by default), soft-delete via forget, supersede chain for rules
Audit None Append-only audit_log for every mutation
Deployment Supabase Edge Functions Docker / Onramp / any container host

Features

  • 12 MCP tools: capture, search, recall, boot, browse, stats, update, supersede, forget, rename_project, start_session, end_session
  • Typed memory tables so different memory types can have different lifecycles:
    • rules — immutable behavioral guidance, modified only via supersede
    • facts — knowledge with a reactivation score that recall bumps upward; the periodic decay process is scaffolded (env knobs exposed) but disabled by default in this release
    • incidents — postmortems, archivable
    • tasksopen / blocked / done / stale
    • documents — large handoff specs, architecture docs, and project briefs (up to ~60KB). Capped at 10 active per project. Use for passing detailed plans between AI contexts (e.g. claude.ai → Claude Code)
  • Write gate validates every capture: headline ≤15 words, body ≤400 words (≤15,000 for documents), semantic-similarity duplicate check (cosine threshold)
  • Hybrid search blends pgvector cosine similarity with Postgres tsvector BM25 — configurable weight
  • Headline-only boot payloads with hard token cap so a session start doesn't burn 15K tokens loading memory bodies
  • Session handoff — end one session with a note → next boot / start_session surfaces it
  • Audit log — every insert / update / supersede / delete recorded
  • Ollama-first embeddings — local, free, no API key. OpenAI and OpenRouter supported as alternatives
  • All knobs in .env with sensible defaults

Quick start — Onramp

If you run Onramp:

cd /apps/onramp
make enable-service openbrain
make edit-env openbrain          # review auto-generated DB password and access key
make start-service openbrain
make logs openbrain

The service is then reachable at https://openbrain.<HOST_DOMAIN>/mcp with TLS via Traefik. The auto-generated OPENBRAIN_MCP_ACCESS_KEY in services-enabled/openbrain.env is what your MCP clients authenticate with.

You'll also need an embedding model in Ollama:

docker exec ollama ollama pull nomic-embed-text

Quick start — standalone Docker

docker network create openbrain
docker run -d --name openbrain-db --network openbrain \
  -e POSTGRES_USER=openbrain \
  -e POSTGRES_PASSWORD=changeme \
  -e POSTGRES_DB=openbrain \
  -v $PWD/pgdata:/var/lib/postgresql/data \
  pgvector/pgvector:pg16

docker run -d --name openbrain --network openbrain -p 8080:8080 \
  -e DATABASE_URL=postgres://openbrain:changeme@openbrain-db:5432/openbrain \
  -e OPENBRAIN_OLLAMA_BASE_URL=http://host.docker.internal:11434 \
  -e OPENBRAIN_MCP_ACCESS_KEY=$(openssl rand -hex 16) \
  ghcr.io/crack-kitty/openbrain-mcp:latest

Then point an MCP client at http://localhost:8080/mcp with the bearer token from your run command (see Connecting AI clients below).

Connecting AI clients

OPENBRAIN_MCP_ACCESS_KEY is required — the server refuses to start without it. Generate a strong random value (e.g. openssl rand -hex 32).

Authenticate with the Authorization: Bearer YOUR_KEY header. This is the only method enabled by default.

Claude Code

Add to the mcpServers block in ~/.claude.json:

{
  "mcpServers": {
    "openbrain": {
      "type": "http",
      "url": "https://openbrain.example.com/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_OPENBRAIN_MCP_ACCESS_KEY"
      }
    }
  }
}

Cursor / Gemini CLI / Other MCP clients

Any client that speaks MCP over HTTP works. Send the access key in the Authorization header. The MCP endpoint is /mcp.

Clients that can't send custom headers (Claude.ai, ChatGPT)

⚠️ Security trade-off. Passing the access key as a URL query parameter leaks it through browser history, web-server access logs, upstream proxies, monitoring/observability tools, and HTTP Referer headers. Use this only if your client cannot send a custom Authorization header, and treat the key as compromised the moment anyone else sees the URL. Rotate it more aggressively than you would a header-based key.

Query-parameter auth is off by default. Enable it by setting:

OPENBRAIN_ALLOW_QUERY_KEY=1

Then connect with the key in the URL:

Claude.ai (Desktop / Web)

Settings → Integrations → Add more integrations... → scroll to the bottom → Add custom integration → paste this URL:

https://openbrain.example.com/mcp?key=YOUR_OPENBRAIN_MCP_ACCESS_KEY

Select No Authentication — the access key is embedded in the URL.

ChatGPT (Plus / Pro)

Settings → Connectors → Developer Mode → Add custom MCP server → paste the same ?key= URL. Select No Authentication.

Configuration

All configuration is via environment variables. Defaults in parentheses.

Auth & networking

Variable Default Notes
DATABASE_URL (required) Postgres connection string with pgvector available
OPENBRAIN_HOST 0.0.0.0 Bind address
OPENBRAIN_PORT 8080 Listen port
OPENBRAIN_MCP_ACCESS_KEY (required) Access key — server refuses to start if unset. Pass as Authorization: Bearer header.
OPENBRAIN_ALLOW_QUERY_KEY false Set 1 to also accept the key as ?key= query parameter (leaks via URLs/logs/referrers — see "Clients that can't send custom headers" in Connecting AI clients)

Embeddings

Variable Default Notes
OPENBRAIN_EMBEDDING_PROVIDER ollama ollama / openai / openrouter
OPENBRAIN_EMBEDDING_MODEL nomic-embed-text Must match the configured provider
OPENBRAIN_EMBEDDING_DIMENSIONS 768 Must match the model's output size
OPENBRAIN_OLLAMA_BASE_URL http://ollama:11434 Used when provider=ollama
OPENBRAIN_OPENAI_API_KEY (unset) Used when provider=openai
OPENBRAIN_OPENAI_MODEL text-embedding-3-small OpenAI embedding model
OPENBRAIN_OPENROUTER_API_KEY (unset) Used when provider=openrouter

Search tuning

Variable Default Notes
OPENBRAIN_HYBRID_WEIGHT 0.3 Keyword score weight (0 = pure vector, 1 = pure keyword)
OPENBRAIN_DEDUP_THRESHOLD 0.92 Cosine ≥ this on capture → reject as duplicate
OPENBRAIN_MERGE_LOWER_THRESHOLD 0.70 Lower bound of the smart-merge zone (reserved for future consolidation)

Write gate

Variable Default Notes
OPENBRAIN_HEADLINE_MAX_WORDS 15 Hard cap on headline length
OPENBRAIN_BODY_MAX_WORDS 400 Hard cap on body length (all kinds except documents)
OPENBRAIN_DOCUMENT_BODY_MAX_WORDS 15000 Hard cap on document body length (~60KB)
OPENBRAIN_DOCUMENT_MAX_ACTIVE 10 Max active documents per project
OPENBRAIN_DOCUMENT_EMBED_PREFIX_WORDS 500 How many words of a document body to embed for search (headline is always fully embedded)

Memory decay (scaffolded — disabled by default)

The fields exist in the schema and the env knobs are wired through config.py, but the periodic decay/consolidation process is not yet running in this release. Recall still bumps a fact's decay_score upward; nothing currently decreases it.

Variable Default Notes
OPENBRAIN_DECAY_LAMBDA 0.005 Reserved: per-day decay rate (consumed only when consolidation is enabled in a future release)
OPENBRAIN_CONSOLIDATION_INTERVAL 0 Reserved: minutes between consolidation passes (0 = disabled; no consumer in this release)

Boot payload

Variable Default Notes
OPENBRAIN_BOOT_TOKEN_CAP 2000 Hard token cap on the boot payload (minimum 200)
OPENBRAIN_BOOT_BLOCKER_CAP 5 Max BLOCKER rules in boot
OPENBRAIN_BOOT_PATTERN_CAP 5 Max PATTERN rules in boot
OPENBRAIN_BOOT_TASK_CAP 20 Max active tasks in boot
OPENBRAIN_HANDOFF_MAX_CHARS 4000 Max chars accepted by end_session(handoff_note=...). Larger handoffs are rejected; in boot(), a handoff that still exceeds the token cap after shrinking is truncated with a sentinel, then dropped entirely if even that won't fit.

Optional metadata-extraction LLM

Variable Default Notes
OPENBRAIN_METADATA_LLM_PROVIDER ollama Reserved for richer auto-tagging on capture
OPENBRAIN_METADATA_LLM_MODEL qwen2.5-coder:14b Same

Architecture

The schema separates memories by lifecycle, not by content. Behavioral rules and project facts are fundamentally different — they're written for different reasons, accessed at different times, and decay (or don't) at different rates. Stuffing them in one table forced compromises that fell over at scale in earlier Open Brain implementations.

OpenBrain MCP uses five typed tables:

  • rules — immutable, severity-classified (BLOCKER / PATTERN), modified only via supersede so the audit chain is preserved. Loaded into the boot payload.
  • facts — knowledge with access_count and a decay_score that recall bumps upward. The periodic decay process is scaffolded (env knobs exist) but not yet active in this release, so today this is reactivation tracking rather than full decay. Not loaded at boot — fetched on demand via search + recall.
  • incidents — postmortems and bug records, archivable after a quiet period.
  • tasks — open / blocked / done / stale, surfaced in the boot payload while open.
  • documents — large-format memories for architecture docs, project briefs, and handoff specs that exceed the normal 400-word body limit (up to ~60KB / 15,000 words). Capped at 10 active per project. Not loaded at boot (too heavy) — discoverable via search, retrievable via recall. Only the headline and first 500 words of body are embedded for search; the full body is stored and returned on recall.

A memory_index table mirrors headlines and embeddings across all five kinds for a single search query path. An HNSW index serves cosine search; a tsvector GIN index serves keyword search. Hybrid scoring blends the two with a configurable weight.

Every mutation lands in audit_log with a JSON snapshot of the row at the time of the change — useful when something looks wrong six months from now. The audit write is best-effort: it runs after the main mutation transaction commits, on a separate connection, so a process crash between the commit and the audit insert can leave a committed mutation with no audit row. For a personal memory service this is the right trade-off (the audit is for hindsight, not authorization); harden it if you're storing material that demands a true audit trail.

Development

git clone https://github.com/crack-kitty/openbrain-mcp
cd openbrain-mcp

Unit tests

No containers needed — tests the write gate and validation logic directly:

uv run --with pytest pytest tests/

Integration tests

Spins up an isolated Postgres + OpenBrain stack (separate from production), runs the full test suite, and tears it down:

./tests/run_integration.sh

This uses docker-compose.test.yml which starts a throwaway pgvector database and a fresh OpenBrain instance on port 8081. Production is never touched.

License

MIT — see LICENSE.

Acknowledgments

  • Nate B. Jones for creating OB1 and the Open Brain concept
  • The Open Brain community for architectural patterns and real-world deployment lessons
  • Built for the Onramp self-hosting framework

About

Self-hosted AI memory layer (MCP server). Typed memory tables, hybrid search, session handoff. For Onramp + any MCP client.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages