brain-mcp
by markschaake
README.md
# brain-mcp
An MCP (Model Context Protocol) server that provides persistent semantic memory backed by PostgreSQL + pgvector. Store "thoughts" with vector embeddings and organize them via a flexible dimensional model.
## Two Servers
This repo provides two MCP servers with a shared codebase:
- **brain-mcp** (`dist/index.js`) — General-purpose knowledge store with ADR support. Use this for non-code contexts.
- **brain-code-mcp** (`dist/code.js`) — Superset of brain-mcp with code-aware tools. Use this for software projects.
You only need to configure one — brain-code-mcp includes all brain-mcp tools.
## Features
- **Semantic search** — find thoughts by meaning using cosine similarity over vector embeddings
- **Dimensional organization** — tag thoughts with typed dimensions (person, project, topic, tag, file, symbol, etc.)
- **Thought temporality** — thoughts have types (`fact`, `decision`, `observation`, `question`) and can be superseded while preserving history
- **Multi-brain support** — isolated knowledge spaces via the `BRAIN_NAME` environment variable
- **Conflict detection** — automatically surfaces similar existing thoughts when capturing new ones
- **Architecture Decision Records** — structured ADR capture with auto-numbering, alternatives, and consequences
- **Code-linked knowledge** — link thoughts to repositories, files, and symbols (brain-code-mcp)
- **Knowledge freshness** — detect stale knowledge when referenced code changes (brain-code-mcp)
## Tools
### Core tools (both servers)
| Tool | Description |
|------|-------------|
| `capture_thought` | Store a thought with type, dimensions, metadata, and embedding. Surfaces conflicts with similar active thoughts. |
| `search` | Semantic vector search with optional filters (dimension, thought type, etc.) |
| `list_recent` | Chronological listing with optional filters |
| `explore_dimension` | All thoughts linked to a given dimension |
| `list_dimensions` | All dimensions with thought counts |
| `list_brains` | List all brains with optional thought counts. Respects `BRAIN_ACCESSIBLE`. |
| `supersede_thought` | Replace an existing thought, preserving history. Auto-preserves ADR metadata. |
| `capture_adr` | Record an Architecture Decision Record with context, alternatives, and consequences |
| `list_adrs` | List and filter ADRs by status or dimension |
### Code tools (brain-code-mcp only)
| Tool | Description |
|------|-------------|
| `capture_code_context` | Capture knowledge linked to specific files, symbols, or repositories |
| `search_code` | Semantic search filtered to code-linked knowledge |
| `check_freshness` | Check if code-linked knowledge is stale by comparing git state |
| `refresh_stale_knowledge` | Find stale thoughts with git diffs for review |
### Core prompts (both servers)
| Prompt | Description |
|--------|-------------|
| `brain_overview` | Comprehensive orientation: thought counts, dimensions, recent thoughts, ADR summary, open questions |
| `deep_dive` | Deep dive into a dimension with all linked thoughts, co-occurring dimensions, and ADRs |
| `decision_review` | Review active decisions and ADRs, flagging overdue revisit dates |
| `capture_session` | Set up a knowledge capture session with existing taxonomy and related knowledge |
### Code prompts (brain-code-mcp only)
| Prompt | Description |
|--------|-------------|
| `codebase_knowledge` | All knowledge about a repo grouped by file/symbol, with optional freshness checks |
| `file_context` | All knowledge about a specific file with freshness and semantically related unlinked knowledge |
## Setup
### Prerequisites
- Node.js
- PostgreSQL with [pgvector](https://github.com/pgvector/pgvector) extension
- An [OpenRouter](https://openrouter.ai/) API key (for generating embeddings)
### Quick start (Claude Code)
Set `OPENROUTER_API_KEY` in your shell environment (e.g. in `~/.bashrc` or `~/.zshrc`):
```bash
export OPENROUTER_API_KEY="your-key-here"
```
Then add to your project's `.mcp.json`:
```json
{
"mcpServers": {
"brain": {
"command": "npx",
"args": ["-y", "github:markschaake/brain-mcp"],
"env": {
"DATABASE_URL": "postgresql://user:pass@host:5432/brain",
"BRAIN_NAME": "personal"
}
}
}
}
```
For brain-code-mcp (includes code-aware tools):
```json
{
"mcpServers": {
"brain": {
"command": "npx",
"args": ["-y", "-p", "github:markschaake/brain-mcp", "brain-code-mcp"],
"env": {
"DATABASE_URL": "postgresql://user:pass@host:5432/brain",
"BRAIN_NAME": "my-project"
}
}
}
}
```
> **Note:** Do not put `OPENROUTER_API_KEY` in `.mcp.json` — it is often checked into version control. The server reads it from the environment automatically.
The database schema is automatically created on first run.
### Database options
**Option 1: Use the included docker-compose** (easiest for local development)
```bash
git clone https://github.com/markschaake/brain-mcp.git
cd brain-mcp
docker compose up -d # starts PostgreSQL+pgvector on port 5488
```
With docker-compose, the default `DATABASE_URL` (`postgresql://brain:brain@localhost:5488/brain`) works without any configuration.
**Option 2: Bring your own PostgreSQL**
Any PostgreSQL instance with the pgvector extension installed will work. Set `DATABASE_URL` in your MCP config. The schema is auto-applied on first server startup.
### Local development
```bash
pnpm install
pnpm run build
pnpm run dev # watch mode (tsc --watch)
pnpm run lint # run ESLint
# Run directly
OPENROUTER_API_KEY=your-key node dist/index.js # brain-mcp
OPENROUTER_API_KEY=your-key node dist/code.js # brain-code-mcp
```
## Environment variables
| Variable | Description | Default |
|----------|-------------|---------|
| `DATABASE_URL` | PostgreSQL connection string | `postgresql://brain:brain@localhost:5488/brain` |
| `OPENROUTER_API_KEY` | Required for embedding generation | — |
| `EMBEDDING_MODEL` | Override the embedding model | `openai/text-embedding-3-small` |
| `BRAIN_NAME` | Which brain (knowledge space) to use | `personal` |
| `BRAIN_ACCESSIBLE` | Comma-separated whitelist of brain names this instance can access. Empty = all brains accessible. | (empty) |
## Multi-brain usage
All tools and prompts accept an optional `brain` parameter to target a specific brain by name at runtime, without restarting the server. Omit it to use the default brain (`BRAIN_NAME`).
Read-only tools (`search`, `list_recent`, `explore_dimension`, `list_dimensions`, `list_adrs`, `search_code`, `check_freshness`, `refresh_stale_knowledge`) also accept `brain: "*"` to query across all accessible brains.
Write tools (`capture_thought`, `supersede_thought`, `capture_adr`, `capture_code_context`) reject `"*"` — you must specify a brain name for writes.
Use `BRAIN_ACCESSIBLE` to restrict which brains a server instance can access:
```json
{
"mcpServers": {
"brain": {
"command": "npx",
"args": ["-y", "github:markschaake/brain-mcp"],
"env": {
"DATABASE_URL": "postgresql://user:pass@host:5432/brain",
"BRAIN_NAME": "personal",
"BRAIN_ACCESSIBLE": "personal,work,shared"
}
}
}
}
```
When `BRAIN_ACCESSIBLE` is empty (default), all brains are accessible.
## Architecture
### Source files
| File | Purpose |
|------|---------|
| `src/index.ts` | brain-mcp entry point |
| `src/code.ts` | brain-code-mcp entry point (superset) |
| `src/tools.ts` | Shared tool registration (core + ADR tools) |
| `src/db.ts` | PostgreSQL connection pool and helpers |
| `src/migrate.ts` | Auto-migration runner (applies `migrations/*.sql` on startup) |
| `src/embeddings.ts` | Embedding generation via OpenRouter |
| `src/git.ts` | Git operations for freshness detection |
| `src/prompts.ts` | MCP prompt registration (core prompts for both servers) |
### Database schema
Migrations are in `migrations/` and are auto-applied on server startup.
- **brains** — isolated knowledge spaces
- **thoughts** — content + vector(1536) embedding + metadata (jsonb) + thought type + status
- **dimensions** — typed categories with metadata, unique per (brain, name, type)
- **thought_dimensions** — many-to-many links with optional context
Embeddings are indexed with HNSW for fast cosine similarity search.
### Code-linked dimension types
brain-code-mcp uses these dimension types to link knowledge to code:
| Type | Name convention | Metadata |
|------|----------------|----------|
| `repo` | Repository name | `{}` (extensible) |
| `file` | Repo-relative path | `{repo, line_start, line_end, git_sha}` |
| `symbol` | Symbol name | `{repo, file, kind}` |
### ADR metadata
ADRs are stored as `decision` thoughts with structured metadata:
```jsonc
{
"adr": true,
"adr_number": 7,
"adr_title": "Use pgvector for semantic search",
"adr_status": "accepted", // proposed | accepted | deprecated | superseded
"adr_context": "Why this decision was needed...",
"adr_alternatives": [{ "name": "Pinecone", "pros": [...], "cons": [...] }],
"adr_consequences": ["Must run PostgreSQL with pgvector"],
"adr_decided_date": "2026-03-01"
}
```
## License
ISC
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues