Skip to main content
Glama

brain-mcp

Your Obsidian vault, as memory for every AI you use.

An open-source Model Context Protocol server that serves your notes, from your own machine, to Claude and any MCP client.

CI npm License: MIT PRs welcome Good first issues Research issues

Node.js 22+ TypeScript MCP SQLite FTS5 Obsidian Local models OAuth 2.1 Cloudflare Tunnel

Website · Quick start · How it works · Contribute · Research questions


Why brain-mcp

Every new chat starts from zero. You explain who you are, what you are building and how you like to work, and tomorrow, in another app, you explain it again.

brain-mcp keeps that context in the Markdown notes you already own. Connect any MCP client and it learns who you are, how you work, what your projects are and what you touched this week. It can search, follow links and write back to the vault as you talk.

  • Your files, your machine. Notes stay plain Markdown in a folder you control. Nothing is uploaded to a third party.

  • One memory, every client. Claude Code, Claude Desktop, claude.ai, Cursor, Hermes Agent, your phone and anything else that speaks MCP read the same vault.

  • Hybrid retrieval, fully local. Keyword search plus meaning search with a small embedding model, then a reranker, all on your CPU. It can also answer "the vault does not record this" instead of guessing.

  • Measured. Every ranking change is scored by two bundled evals, keyword and hybrid side by side.

  • Private by default. OAuth 2.1 with PKCE for remote access, read, write and private scopes, secret redaction and an audit log of every call.

  • Writes back. brain_remember and brain_capture turn what a model learns into notes you can read and edit.

  • Small and readable. About 3,800 lines of strict TypeScript. Easy to study, easy to extend.

Related MCP server: obsidian-mcp

How it works

flowchart LR
    V["Obsidian vault<br/>plain Markdown"]

    subgraph S["brain-mcp: one Node process, one SQLite file"]
        I["Indexer<br/>sections, links,<br/>topics, projects"]
        DB[("SQLite<br/>FTS5 word index<br/>section embeddings<br/>link graph")]
        M["Local models on CPU<br/>bge-small embedder<br/>bge-reranker"]
        R["Hybrid retrieval"]
        T["14 MCP tools"]
        G["Scopes, redaction,<br/>audit log"]
        I --> DB --> R --> T --> G
        M -.-> DB
        M -.-> R
    end

    V -->|file watcher| I
    G -->|stdio| C1["Claude Code,<br/>Claude Desktop"]
    G -->|HTTP + bearer token| C2["Clients on<br/>your network"]
    G -->|OAuth 2.1 through<br/>Cloudflare Tunnel| C3["claude.ai, phone,<br/>any MCP client"]
    T -. "remember, capture, write,<br/>edit, move, delete<br/>(allowed folders only)" .-> V
  1. Index. Every note is split into sections and indexed with its links, topics and project. Each section also gets an embedding (bge-small-en-v1.5) in the background. A file watcher keeps both current within a second of a save.

  2. Retrieve. A question goes through five steps:

    • Understand: expand shorthands (pg → PostgreSQL) and fix typos against the vault's own words.

    • Search four ways: keywords per section (BM25), meaning (embeddings), exact dates, and note titles.

    • Fuse the four lists with reciprocal rank fusion.

    • Rerank the best candidates with a cross-encoder (bge-reranker-base), always including each list's first pick, so fusion cannot bury a hit only one search found. When keyword and meaning search agree on the top hit and fusion keeps it in the top 3, only those 3 are reranked.

    • Decide: if even the best passage scores below a floor, answer "nothing relevant"; otherwise return the strong hits, cited by note, with a coverage label (good, thin, none).

  3. Serve. Over stdio beside your editor, over HTTP with a bearer token on your network, or behind an OAuth 2.1 login through Cloudflare Tunnel for the public internet.

  4. Remember and write. brain_remember appends durable facts and refuses near duplicates. A fact can replace an earlier one, expire, or start at a given date; brain_identity serves only the facts true now, and brain_facts keeps the history. Four more tools write, edit, move and delete hand-written notes, inside the folders you allow.

The retrieval step from question to answer:

flowchart LR
    Q["Question"] --> U["Understand<br/>shorthands,<br/>typo fixes"]
    U --> K["Keywords<br/>per section, BM25"]
    U --> D["Meaning<br/>embeddings"]
    U --> DT["Exact dates"]
    U --> NT["Note titles<br/>BM25"]
    K & D & DT & NT --> F["Fuse<br/>reciprocal rank fusion"]
    F --> RR["Rerank top 16<br/>cross-encoder<br/>(top 3 when keywords<br/>and meaning agree)"]
    RR --> GT{"Best score<br/>above the floor?"}
    GT -->|no| X["Nothing relevant"]
    GT -->|yes| A["Cited passages<br/>coverage: good or thin"]

Everything runs on your machine: the models are downloaded once into data/models, and no note leaves the server. If the models are not ready yet, retrieval falls back to keywords, so the server never blocks. Set BRAIN_MCP_HYBRID=0 to stay keyword-only.

NOTE

The architecture is intentionally simple right now, and ideas are welcome. It is one process and one SQLite file, with a hybrid ranker built from fixed rules. Some of it is already tweakable: the retrieval block in brain.config.json (embedding and reranker models, how many candidates to rerank, the score blend, the "nothing relevant" floor, your own shorthands), context budgets under context, and fusion constants such as RRF_K and TITLE_BONUS in src/vault/index.ts. Much more could become configurable, such as pluggable retrievers and storage, graph strategies, and query rewriting. If you have an idea, open an issue or a research proposal, even before there is code.

Tools

Tool

What it returns

brain_identity

Persona bundle: profile note, memory notes, the captured facts that are true now, skills, project list and recent focus. The server instructions ask clients to call this first. Pass topic for a smaller bundle.

brain_context

The sections most relevant to a question, with source note ids and a coverage label, from the hybrid ranker, packed under a size budget. Says so explicitly when the vault does not record the answer.

brain_search

Hybrid search (keywords, meaning, reranker, spelling correction) with project, type, topic and date filters. Returns ranked notes with snippets.

brain_read

One note, or one section of it, with metadata, topics and resolved links.

brain_project

Briefing on a project: description, latest progress, decisions, recent changes and notes grouped by type. With no argument it lists projects.

brain_graph

Links out, backlinks grouped by project, and notes that share topics.

brain_recent

Notes modified in the last N days, newest first.

brain_capture

Writes a new note with graph-ready frontmatter into the capture folder.

brain_remember

Appends a fact to the memory file; it joins brain_identity straight away. replaces names facts it makes outdated, subject + attribute replace the previous fact with the same pair on their own, and valid_from / valid_until bound when it holds. Near duplicates of current facts are refused (token Jaccard ≥ 0.6 or containment ≥ 0.85); a partial overlap in the same category is held back until the caller passes replaces or force=true.

brain_facts

Captured facts and when each was true: the current ones, the ones true at an as_of date, or every version with what replaced it (history). Filters by subject, category and words.

brain_write

Creates a note at a chosen path in a writable folder (Notes/ and the capture folder by default), or replaces one with overwrite=true. A hub note groups every note whose project matches its title.

brain_edit

Changes part of a note in one of three ways: replace text that matches once, replace a section under a heading, or append. Keeps the file's line endings and bumps modified.

brain_move

Moves or renames a note within the writable folders. Never overwrites, and names any notes whose links stop resolving.

brain_delete

Moves a note into .trash/, which is never indexed. Nothing is erased.

The four write tools need the brain:write scope. They refuse notes a pipeline generates, hidden folders, paths outside the vault, and the memory file, which stays append-only through brain_remember.

Also exposed: the resources brain://identity and brain://note/{path}, and the prompts assume_persona and project_briefing.

The index lives in data/index.db, embeddings included. It is rebuilt on every start (about 10 ms for the 15-note example vault) and kept current by the watcher; embeddings are keyed by a hash of the text, so unchanged sections are never embedded twice. Every tool call is appended to logs/audit.jsonl.

Quick start

Requires Node 22 or newer. One command sets it up on your notes:

npx debawho-brain-mcp init

It lists the Obsidian vaults on your machine and asks which one to serve (or makes a starter vault in ~/second-brain), asks your name, offers smart search, and offers to connect Claude Code for you. Your notes stay where they are; the config, index and logs go in ~/.brain-mcp/. Then ask Claude "what do you know about me?"

The package itself is about 50 MB and searches by keyword. Smart search adds two local models that rank by meaning, and puts the right note first more often (67% against 42% on the example vault's eval). It is a one-time download of 100 to 200 MB for your platform's ONNX runtime, plus 300 MB of models, all kept in ~/.brain-mcp/. init asks for it; add it later with npx debawho-brain-mcp smart-search, or take it out with npx debawho-brain-mcp smart-search remove.

To connect a client yourself, Claude Code:

claude mcp add --scope user brain -- npx -y debawho-brain-mcp --stdio

Hermes Agent:

hermes mcp add brain --command npx --args -y debawho-brain-mcp --stdio

Claude Desktop, Cursor and other clients that read an mcpServers config:

{
  "mcpServers": {
    "brain": { "command": "npx", "args": ["-y", "debawho-brain-mcp", "--stdio"] }
  }
}

On Windows, put cmd /c in front of npx: "command": "cmd", "args": ["/c", "npx", "-y", "debawho-brain-mcp", "--stdio"]. Run npx debawho-brain-mcp --help for the HTTP and OAuth modes.

From source

For development, the checks and evals, or Docker:

git clone https://github.com/debashishthakur/brain-mcp.git
cd brain-mcp
npm install
npm run build
node scripts/smoke.mjs

The repository ships with example-vault/, a small fictional vault belonging to Ines Varga, a backend engineer with two side projects. brain.config.json points at it, so the smoke test drives every tool, resource and prompt over stdio against real notes, then restores the vault.

The first hybrid query downloads the two models (about 300 MB) from Hugging Face into data/models. After that, everything runs offline.

Make it yours (from source)

npm run setup

The same setup as init, for a clone. It asks for your name (it suggests the one from git config) and where your notes are. Point it at an existing Obsidian vault, or press Enter for a starter vault in my-vault/ with a profile note to fill in. It writes brain.config.local.json, which git ignores and the server uses from then on, with its own index so your notes never mix with the example. It ends by printing the claude mcp add command for your machine: run it, then ask Claude "what do you know about me?"

Delete brain.config.local.json to go back to the example vault. The checks and evals always run against the example vault, so they keep passing after setup.

npm run typecheck
node scripts/verify.mjs          # redaction, file watcher, HTTP bearer auth, audit log
node scripts/verify-facts.mjs    # fact windows: dates, replacements, expiry, bad references
node scripts/verify-memory.mjs   # brain_remember dedupe and replacements, brain_facts, identity, brain_context
node scripts/verify-write.mjs    # write, edit, move and delete on a throwaway vault
node scripts/verify-oauth.mjs    # the full OAuth 2.1 flow against a throwaway auth database
node scripts/verify-hybrid.mjs   # hybrid search: refusal, spelling, identifiers, context
node scripts/verify-setup.mjs    # npm run setup, in a temp folder
node scripts/verify-package.mjs  # the npm package as a new user gets it: pack, install, init, serve
node scripts/verify-smart-search.mjs  # the smart-search add-on: this OS's runtime only, hybrid ranking, remove
node scripts/eval-retrieval.mjs  # 12 questions, keyword vs hybrid
node scripts/eval-hybrid.mjs     # 15 harder questions: paraphrase, typo, identifier, date, multi-hop, alias, off-topic
node scripts/debug-rank.mjs "your question"   # trace one query through every ranking step

If npm install reports held-back install scripts, the two packages that need them (better-sqlite3 and esbuild) are already listed under allowScripts in package.json. Run npm install-scripts approve better-sqlite3 esbuild if your npm still asks. The scripts of onnxruntime-node and protobufjs are not needed for CPU use.

Run with Docker

Token-mode HTTP server in a container, using the example vault by default. The image is Alpine-based and searches by keyword, because the ONNX runtime behind smart search needs glibc.

export BRAIN_MCP_TOKEN="$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")"
docker compose up --build

The compose file publishes 127.0.0.1-friendly port 3737, mounts brain.config.json and example-vault read-only, and keeps data/ and logs/ on the host. Health is checked at GET /healthz.

Keep the service private. The container binds 0.0.0.0 only so Docker can publish the port. Publish it on loopback (127.0.0.1:3737:3737) or a private network such as Tailscale — do not expose it to the public internet. Anything public should use OAuth (--oauth) behind a TLS proxy, as in the security model below.

To use your own vault, point vaultPath at a host mount (or replace the example-vault volume) and keep BRAIN_MCP_CONFIG on a config file whose vaultPath matches that mount.

Retrieval eval

Two scripts score retrieval on the example vault, keyword and hybrid side by side. Results are deterministic and reproducible from a fresh clone.

eval-retrieval.mjs, 12 everyday questions:

Ranker

Right note first

Right note in top 5

Expected note in the context pack

Time per question (laptop CPU)

Keyword only

42%

100%

100%

2 ms

Hybrid (default)

83%

100%

100%

about 1.1 s

eval-hybrid.mjs, 15 harder questions:

Ranker

Right note first

Right note in top 5

Off-topic questions refused

Keyword only

67%

100%

2 of 3

Hybrid (default)

67%

75%

3 of 3

Hybrid search puts the right note first far more often and refuses questions the vault cannot answer. Its weak spot is paraphrase: on the harder set it still misses some real questions asked in other words, such as "why is the bird audio never sent to an online service". Calibrating the "nothing relevant" floor is issue #3, and a faster reranker is issue #10. When you point the server at your own vault, replace the cases with questions about your notes.

Use your own vault

npx debawho-brain-mcp init, or npm run setup in a clone, does this for you. To do it by hand, copy brain.config.json to brain.config.local.json (or ~/.brain-mcp/config.json for the npm package) and change what differs:

{
  "vaultPath": "../my-vault",
  "dataDir": "./data/local",
  "owner": "Your Name",
  "privatePaths": ["Private/**", "Journal/**"],
  "identity": {
    "profileNote": "About me",
    "memoryProject": "Assistant Memory",
    "skillsProject": "Assistant Skills"
  }
}

vaultPath and dataDir are resolved relative to the config file. The server uses the first config it finds: --config <path>, then BRAIN_MCP_CONFIG, then brain.config.local.json, then ~/.brain-mcp/config.json (npm package only), then brain.config.json. Run npm run reindex to check the note count; the first log line names the config in use.

Any Markdown file in the vault is indexed. Frontmatter makes it richer:

Field

Used for

title

Display name and title matching. Falls back to the file name.

type

hub marks a project hub, concept a shared topic note. progress and decision notes get their own sections in brain_project. Other useful values: runbook, architecture, plan, research, spec, audit, agent, note.

project

The project a note belongs to, usually a wikilink to its hub: "[[Harbor Ledger]]".

topics

Concepts the note is about, as wikilinks. Drives the topic filter and shared-topic neighbours.

related, part-of

Extra links, added to the graph like body wikilinks.

aliases

Other names brain_read and brain_graph will resolve.

visibility

private hides the note from connections without the brain:private scope.

modified

Date used for recency, brain_recent and the identity focus list. Falls back to the file's mtime.

note-count, last-touched

Shown next to each hub in the identity bundle.

Wikilinks in the body ([[Note]], [[Note#Heading]], [[Note|alias]]) become graph edges. A leading # Title that repeats the title is dropped from what clients read, and a generated ## Connections trailer after a --- rule is left out of search and context.

  • Profile: the note named by identity.profileNote, matched by title, alias, path or file name.

  • Memory: every note whose project is identity.memoryProject. Write each one with a How to apply line; the bundle tells the client to follow them.

  • Captured facts: the facts in memoryFile that are true now. Replaced, expired and not-yet-valid ones stay in the file and are left out. Over the size cap, who the owner is and how to work with them stay longest, then the newest project and reference facts.

  • Skills: notes in identity.skillsProject, listed by their first paragraph.

  • Projects: every note with type: hub.

  • Current focus: content notes modified in the last identity.focusWindowDays days.

The memory file stays plain Markdown and stays append-only: once written, a fact is never edited by the server. A later fact says what it changes, on lines you can read in Obsidian:

## 2026-09-22 18:21 · project

The app uses SQLite.

*via mcp:claude-code*

## 2026-10-16 09:10 · project

The app uses Postgres.

**Key:** the app / database

**Valid from:** 2026-10-01

**Replaces:** 2026-09-22 18:21

*via mcp:claude-code*
  • Ids are the stamps in the headings. Two facts saved in the same minute become 2026-10-16 09:10 and 2026-10-16 09:10 #2.

  • Replaces ends the named facts when the new one starts (its Valid from, or when it was recorded). Only earlier facts can be replaced. A Supersedes line from older versions counts the same way.

  • Key (subject / attribute) makes replacement automatic: a later fact with the same pair, in any letter case, replaces the current one.

  • Valid until ends a temporary fact. A bare date means through that day. Times are UTC.

The index derives a facts table from these lines whenever the file changes, and rebuilds it from the file on every start, so the file is the only copy that matters. To undo a replacement, delete the Replaces line in Obsidian. brain_identity serves the facts true now, brain_facts answers what was true at another date, and brain_context still finds an old fact but marks it as replaced or expired.

Key

Meaning

vaultPath

Vault folder, relative to the config file.

dataDir

Folder for the search index and the OAuth database, relative to the config file. Default: data/ in a clone, ~/.brain-mcp/data/ for the npm package. Setup sets ./data/local, so your index never mixes with the example vault's. The models stay in data/models either way.

owner

Name used in the server instructions and the identity bundle.

captureDir

The only folder the server writes to.

memoryFile

File brain_remember appends to. Must be inside captureDir.

ignoreDirs

Top-level folders that are never indexed. Any path segment starting with . is skipped too.

denyPaths

Globs that are never served to anyone.

privateProjects, privatePaths

Project names and globs that need the brain:private scope.

context.*

brain_context budget, per-section cap, sections per note and candidate pool sizes.

identity.*

Profile note, memory and skills projects, focus window and size caps.

retrieval.*

Hybrid ranking: hybrid on or off, embedModel, rerankModel, rerankN (candidates to rerank), blend (fused rank vs reranker), floor (below it, "nothing relevant"), keepRatio, earlyExit, and aliases for your own shorthands. Every field is optional.

writableDirs

Folders the write, edit, move and delete tools may change. Default: the capture folder and Notes.

http.*

Host, port and path for HTTP modes. The shipped config uses 127.0.0.1:3737/mcp.

auth.*

Mode, public URL, token lifetimes, lockout policy and default scopes for OAuth.

Environment overrides: BRAIN_MCP_HOME (where the npm package keeps its config, index and logs; default ~/.brain-mcp), BRAIN_MCP_CONFIG, BRAIN_MCP_DATA_DIR, BRAIN_MCP_LOG_DIR, BRAIN_MCP_HOST, BRAIN_MCP_PORT, BRAIN_MCP_AUTH_MODE (token or oauth), BRAIN_MCP_PUBLIC_URL, and BRAIN_MCP_HYBRID=0 to switch back to keyword-only ranking.

Connect a client

Claude Code

claude mcp add --scope user brain -- npx -y debawho-brain-mcp --stdio

From a clone, run the build instead: claude mcp add --scope user brain -- node /absolute/path/to/brain-mcp/dist/index.js --stdio.

Or commit a .mcp.json to a project so it is available whenever that folder is open:

{
  "mcpServers": {
    "brain": {
      "command": "node",
      "args": ["/absolute/path/to/brain-mcp/dist/index.js", "--stdio"]
    }
  }
}

Claude Desktop

Add the same mcpServers block to claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\) and restart the app.

Hermes Agent

hermes mcp add brain --command npx --args -y debawho-brain-mcp --stdio
hermes mcp test brain    # connects and lists the 13 tools

The tools appear in Hermes as mcp_brain_brain_identity, mcp_brain_brain_context and so on. For the remote server, use hermes mcp add brain --url https://brain.example.com/mcp --auth oauth and sign in once.

Agent skill

skills/brain-mcp is a SKILL.md that teaches an agent to use the server well: load the owner's identity only for their own work, pick the right tool for each question, cite note ids, say when the vault doesn't record something, and write back only with the owner's consent. Copy the folder into your agent's skills directory, for example ~/.claude/skills/brain-mcp/ for Claude Code. It is instructions only, with no scripts.

export BRAIN_MCP_TOKEN="$(node dist/index.js --gen-token)"   # keep this somewhere safe
node dist/index.js --http                                     # http://127.0.0.1:3737/mcp

BRAIN_MCP_TOKEN grants the read, write and private scopes. BRAIN_MCP_TOKEN_RO grants read only. Tokens shorter than 32 characters are ignored, and the server refuses to start in this mode with no token. It binds to loopback; only expose it over a private network such as Tailscale. Anything public should use --oauth.

--oauth starts the public transport: an OAuth 2.1 authorization server plus the protected /mcp endpoint, meant to listen on loopback behind Cloudflare Tunnel or another TLS-terminating proxy. node scripts/verify-oauth.mjs checks the whole flow end to end.

What a client goes through. Discovery (/.well-known/oauth-protected-resource/mcp → /.well-known/oauth-authorization-server), dynamic client registration at /register (https or loopback redirect URIs only), /authorize with PKCE S256, a login page (password plus a 6-digit authenticator code, both checked every time; five failures pause sign-in for 15 minutes), a consent page listing the scopes, then /token. Access tokens live one hour. Refresh tokens rotate on every use and live 30 days, and presenting a rotated-out refresh token revokes the whole grant. Tokens are opaque and stored only as SHA-256 hashes; the password is stored as an scrypt hash.

On a Linux box (Node 22+). Clone to ~/brain-mcp, put your vault where vaultPath expects it, set auth.publicUrl to your hostname (for example https://brain.example.com), then:

~/brain-mcp/deploy/setup-linux.sh                      # builds, installs the systemd unit
cd ~/brain-mcp && node dist/index.js auth init         # password + QR code for your authenticator app
sudo systemctl start brain-mcp

Then follow the Cloudflare Tunnel steps the script prints. deploy/cloudflared-config.yml is the ingress template.

On a Windows box (elevated PowerShell, Node 22+ via winget install OpenJS.NodeJS.LTS). Clone to $HOME\brain-mcp, then:

Set-ExecutionPolicy -Scope Process Bypass -Force
& "$HOME\brain-mcp\deploy\setup-windows.ps1"   # builds, registers a boot-time task as SYSTEM, disables sleep
cd $HOME\brain-mcp; node dist\index.js auth init
Start-ScheduledTask -TaskName brain-mcp

Connect clients

  • claude.ai: Settings → Connectors → Add custom connector → https://brain.example.com/mcp. Sign in once on the page that opens.

  • Claude Code: claude mcp add --scope user --transport http brain https://brain.example.com/mcp, then run /mcp and authenticate.

  • Anything else that speaks MCP over HTTP with OAuth: the same URL.

Manage access from the box:

node dist/index.js auth status          # configured? counts, recent failures
node dist/index.js auth clients         # every registered client and its live grants
node dist/index.js auth grants          # active refresh grants with last-used time
node dist/index.js auth revoke-client <client_id>
node dist/index.js auth revoke-all
node dist/index.js auth set-password    # or rotate-totp

Keep the vault fresh on the box with Syncthing, or a git push and a pull on a timer. The watcher picks changes up within a second.

Security model

  • Transport. stdio inherits the OS user. HTTP needs a bearer token compared in constant time, and each session is bound to the client id that opened it.

  • Scopes. brain:read, brain:write, brain:private. Notes marked visibility: private, or matched by privateProjects or privatePaths, need the private scope. denyPaths are never served. The example vault keeps one note under Private/ so you can watch this work.

  • Redaction. Credential-shaped strings (Anthropic, OpenAI, GitHub, AWS, Google, Slack and Stripe keys, JWTs, private keys, password= style assignments, credentials embedded in URLs) are masked as [REDACTED:kind] before they leave the server.

  • Writes are confined to the writable folders (writableDirs). Generated notes, hidden folders and paths outside the vault are refused, and deletes go to .trash/.

  • Local models. Embeddings and reranking run on your CPU. Note text is never sent to a model service.

  • Audit. Every call records timestamp, transport, client, session, tool, truncated arguments, note ids returned and redaction count.

Found a vulnerability? Please report it privately, as described in SECURITY.md.

Roadmap

  • Section-level full-text search with title and graph fusion

  • Remote access with OAuth 2.1, PKCE, password and authenticator code

  • Secret redaction, scopes and an audit log

  • Live index with a file watcher

  • Hybrid retrieval: local embeddings fused with BM25, a cross-encoder reranker, spelling correction (#1)

  • Write, edit, move and delete tools for hand-written notes

  • Calibrate the "nothing relevant" floor so real questions are not refused (#3)

  • A faster reranker that keeps accuracy (#10)

  • Graph expansion with Personalized PageRank over wikilinks (#2)

  • Harder eval questions (#4)

  • Docker image (#5) — Dockerfile + docker-compose.yml, see Run with Docker

  • Importers for other note tools (#6)

  • Passkey sign-in (#7)

  • Facts that change over time: replacements, expiry and history (#8)

Contributing

IMPORTANT

brain-mcp is built to be learned from and experimented on, and it needs contributors to succeed. It is a small, readable codebase with a real, measurable problem at its centre: helping an AI find the right note in someone's personal knowledge. If you are learning how MCP servers work, studying retrieval, or researching memory for AI systems, this is a good place to do it, and every improvement you make is measured by the bundled eval.

The architecture is deliberately simple today, so there is plenty of room to reshape it. Proposals to make parts of it configurable or swappable are as welcome as code.

Good for learning

You want to learn

Start here

How an MCP server exposes tools, resources and prompts

src/tools.ts, src/index.ts

Hybrid search: BM25, embeddings, rank fusion

src/vault/index.ts, src/context.ts

Running embedding and reranker models on a CPU

src/vault/dense.ts

Turning wikilinks and frontmatter into a knowledge graph

src/vault/parse.ts

OAuth 2.1 with PKCE, token rotation and TOTP

src/auth/

Scopes and secret redaction

src/policy.ts

Evaluating retrieval honestly

scripts/eval-retrieval.mjs

Open research questions

Each of these is an open issue with a suggested approach and a definition of done:

  • When should retrieval abstain? Hybrid search refuses all off-topic questions, but also some real ones. Calibrating the floor is open. (#3)

  • Which reranker gives the best accuracy per millisecond on a CPU? A model six times faster finds the right note in 58% of everyday questions instead of 75%. (#10)

  • Can the graph a vault already has replace an LLM-built one for multi-hop questions? (#2)

  • How should AI memory notice that a fact changed? The memory file now records replacements and expiry, and brain_facts answers what was true when. A change the caller does not name is only caught by word overlap within one category; catching it by meaning is open. (#8)

  • How do you evaluate retrieval over personal data without sharing that data? Start with a harder public eval set. (#4)

How to contribute

  1. Pick something. Browse good first issues, research questions or help wanted, or open an issue with your idea.

  2. Run the checks. Everything runs against the bundled example vault, so no personal data is needed.

  3. Measure. If your change touches ranking, run node scripts/eval-retrieval.mjs before and after and paste both into the pull request. Good ideas win on numbers.

  4. Open a pull request. CI builds, typechecks and runs every verification script.

Read CONTRIBUTING.md for the details, and please follow the code of conduct.

Citing

If you use brain-mcp in research or teaching, please cite it. GitHub's Cite this repository button uses CITATION.cff.

Project structure

brain-mcp/
├── src/
│   ├── index.ts          entry point: init, stdio, --http, --oauth, --reindex
│   ├── tools.ts          the 14 MCP tools, resources and prompts
│   ├── context.ts        brain_context: fusion and packing under a budget
│   ├── identity.ts       the persona bundle
│   ├── memory.ts         the memory file's blocks and near-duplicate checks
│   ├── facts.ts          facts with validity windows: replacements, expiry, history
│   ├── policy.ts         scopes and secret redaction
│   ├── vault/            parsing notes, the SQLite index, hybrid ranking
│   │   └── dense.ts      local embeddings and the reranker
│   └── auth/             OAuth 2.1 server, login page, TOTP, token store
├── scripts/              setup, smoke test, verification scripts, retrieval eval
├── templates/            the starter vault init and npm run setup create
├── example-vault/        a fictional vault used by every script
├── deploy/               Linux and Windows setup, Cloudflare Tunnel template
└── brain.config.json     the example vault's config; npm run setup writes yours beside it

License

MIT. Created by Debashish Thakur.

Available Tools

13 tools
brain_captureSave a durable noteA

Write a new note into the vault's capture folder with graph-ready frontmatter. Use for plans, decisions, ideas, meeting notes, or session logs the owner wants to keep. Not for one-line facts (use brain_remember).

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyYesMarkdown body. Link concepts inline with [[Concept]] on first mention.
kindNonote
titleYesSpecific noun phrase, not a filename
topicsNoConcept names, e.g. ['OAuth', 'RAG']
projectNoProject hub name this belongs to, e.g. 'Website Redesign'

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false, destructiveHint=false, idempotentHint=false and openWorldHint=false, so the write/safety profile is covered. The description adds where the note lands (capture folder) and that frontmatter is generated, but says nothing about duplicate-title handling or whether an existing file of the same name is overwritten or rejected.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences with zero filler: what it writes, the destination, when to use it, when not to. Purpose and destination are front-loaded before the exclusion.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description could have stated what the caller gets back (created path/link or confirmation), and it says nothing about duplicate handling for a non-idempotent writer. Everything else an agent needs to select and call the tool is present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 80%, so the schema already documents title, body, topics and project. The description's use-case list ('plans, decisions, ideas... logs') loosely maps onto the kind enum, but it adds no syntax, format, or constraint detail beyond what the schema provides. Baseline 3 fits.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (write/create) and resource (a new note) plus the destination (the vault's capture folder) and the extra behavior (graph-ready frontmatter). It explicitly differentiates itself from the sibling brain_remember for the one-line-fact case.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete when-to-use triggers ('plans, decisions, ideas, meeting notes, or session logs the owner wants to keep') and an explicit exclusion with the alternative named ('Not for one-line facts (use brain_remember)'). An agent can route between the two without opening either schema.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

brain_contextGet the vault sections that answer a questionA
Read-onlyIdempotent

One call that returns the most relevant sections from across the vault for a question, with source note ids. Use this before brain_search when you need to answer or reason about something the owner may have written down. Ask in plain words: retrieval is hybrid (keywords + meaning + a reranker), so paraphrases work; still include specific nouns, ids and dates when you have them. The reply states its coverage (good / thin / none).

ParametersJSON Schema
NameRequiredDescriptionDefault
projectNoRestrict to one project
questionYesThe question or topic, in plain words with specific nouns
budget_charsNoSize cap for the returned pack (default from config, ~18000)

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/openWorld=false, so the description need not restate safety. It adds genuinely useful behavioral context: hybrid retrieval (keywords + meaning + reranker), that paraphrases work, and that the reply self-reports coverage as good/thin/none. It does not describe truncation/pagination behavior, but that is largely covered by budget_chars in the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the core behavior and formatted so routing, phrasing and output expectations read in order. Slightly dense but every sentence carries information; no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description still tells the agent what comes back (relevant sections with source note ids) and how to interpret confidence (coverage: good/thin/none), and it explains the retrieval mode so the agent knows how to compose the query. Nothing needed to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description meaningfully adds to the question parameter by specifying how to phrase it ('plain words', paraphrases okay, still include specific nouns/ids/dates). That guidance goes beyond the schema's 'question or topic, in plain words with specific nouns'.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('returns the most relevant sections from across the vault for a question, with source note ids') and explicitly contrasts itself with the sibling brain_search. An agent can identify the tool's distinct role without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear when-to-use ('before brain_search when you need to answer or reason about something the owner may have written down') and an ordering relative to the alternative. It never states a when-not or explains exactly what brain_search does differently, so it stops short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

brain_deleteDelete a hand-written note (to the vault trash)A
Destructive

Remove a note from Notes/ or Captures/ by moving it into the vault's .trash/ folder, which is never indexed. Nothing is erased; the result gives the path to restore from. Generated notes and the memory file cannot be deleted.

ParametersJSON Schema
NameRequiredDescriptionDefault
noteYesNote id (vault path), title or [[wikilink]]

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the destructiveHint=true annotation, it discloses the soft-delete semantics (nothing is erased, the file lands in .trash/ which is never indexed) and that the result returns a restore path. It also enumerates the eligibility restrictions, which the annotations do not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences, front-loaded with the action and mechanism, followed by the recovery and eligibility caveats. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter mutation with no output schema, the description covers the operation, reversibility, return value (restore path) and eligibility limits. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single 'note' parameter, and the description adds no syntax or format detail beyond it. Baseline 3 applies when the schema fully documents the parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (remove/move) and resource (note in Notes/ or Captures/) plus the exact mechanism (moving into .trash/). It also names the scope boundary — generated notes and the memory file cannot be deleted — which distinguishes it from sibling write/move tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear when-not condition: generated notes and the memory file are ineligible, and the target folders are restricted to Notes/ or Captures/. It does not name an alternative for relocating rather than deleting (e.g., brain_move), so the alternative-selection guidance is implicit rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

brain_editEdit part of a hand-written noteA
Destructive

Change part of a note under Notes/ or Captures/ without rewriting it. Give exactly one of: old_text + new_text (old_text must occur exactly once; new_text may be empty), section + content (replaces everything under that heading up to the next heading of the same or higher level; the heading itself stays), or append. Generated notes and the memory file cannot be edited.

ParametersJSON Schema
NameRequiredDescriptionDefault
noteYesNote id (vault path), title or [[wikilink]]
appendNoMarkdown to add at the end of the note
contentNoNew text for that section
sectionNoHeading text of the section to replace, without the # marks
new_textNo
old_textNoExact text to replace; must occur exactly once

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=false, so safety is partly covered. The description adds valuable behavior beyond them: the exactly-once precondition on old_text (a concrete failure mode), the heading-level replacement rule ('up to the next heading of the same or higher level; the heading itself stays'), and explicit exclusions. It omits any permission/auth requirements, hence not a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with purpose before the operational rules. Every clause carries information (scope, modes, preconditions, exclusions) with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 6-param mutation tool with no output schema and annotations already covering the safety profile, the description covers modes, preconditions, and exclusions. It doesn't state what happens on precondition failure (e.g., ambiguous old_text) or any return shape, but nothing critical for invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 83%, so baseline is 3, and the description clearly exceeds it by explaining mode exclusivity and mode-specific semantics: old_text must occur exactly once, new_text may be empty, section replaces content up to the next same-or-higher heading while keeping the heading, and append adds at the end.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Change part of a note') and immediately scopes it to Notes/ or Captures/ and distinguishes it from a full rewrite, which implicitly separates it from brain_write. An agent can tell it does partial edits, not whole-note replacement, without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit usage rules: 'Give exactly one of' three mutually exclusive modes, and states what cannot be edited (generated notes, the memory file). It doesn't name a sibling tool directly, but the 'without rewriting it' framing routes the agent away from brain_write.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

brain_graphExplore the link graphA
Read-onlyIdempotent

Neighbours of a note, hub, or concept: outgoing links, backlinks, and notes sharing the same topics. For a concept (e.g. 'OAuth') this shows every project that touches it. Use it to hop sideways between projects.

ParametersJSON Schema
NameRequiredDescriptionDefault
noteYesNote id, title, concept name, or [[wikilink]]
limitNo

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already cover the safety profile (readOnlyHint, idempotentHint, openWorldHint=false), so the bar is lower. The description adds genuine behavioral context beyond that: it explains that a concept input resolves to every project touching that concept, which tells the agent how the tool behaves for non-note inputs. It says nothing about result ordering, the limit's effect, or truncation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, no filler, with the core capability in the first clause. The concept example and the use-case line each add distinct information rather than restating the opening.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description usefully lists the returned relationship categories, so the agent knows roughly what to expect. It omits how the limit behaves and whether results are paged or ordered, which is the main remaining gap for a two-parameter read tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50%: 'note' is documented but 'limit' has no schema description, and the description never mentions limit either. It does reinforce that the note argument accepts hubs and concept names, mildly extending the schema's own wording. With half the parameters undocumented, this is adequate but not compensating for the gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a concrete retrieval target and enumerates exactly what comes back: outgoing links, backlinks, and topic-sharing notes. That is far more specific than a name restatement and clearly separates it from reading tools like brain_read. It stops short of naming which sibling to prefer when the agent wants a broader search (e.g. brain_search), so it lands at 4 rather than 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Use it to hop sideways between projects' states the intended context of use, and the OAuth example shows the concept-input scenario concretely. There are no exclusions or named alternatives, so it gives clear context but no negative guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

brain_identityLoad the owner's identity and standing contextA
Read-onlyIdempotent

Call this FIRST in every conversation. Returns who the owner is, their preferences and feedback rules, the projects they run, and what they touched recently. Adopt it as your persona and working context. Pass topic (a few words about what the conversation is about) to get a smaller bundle with only the memory notes that apply.

ParametersJSON Schema
NameRequiredDescriptionDefault
topicNoWhat this conversation is about, e.g. 'interview prep' or 'database backups'. Omit for the full bundle.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare this is a safe, idempotent, closed read, so the description is free to add behavioral meaning beyond safety: the bundle is a persona/working-context payload meant to be adopted, and passing `topic` changes the payload composition. It doesn't state format, size, or latency of the full bundle, but the added context is substantive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the imperative invocation rule, then the return contents, then the optional narrowing parameter. Four tight sentences with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of describing what comes back, and it enumerates the payload well (identity, preferences, feedback rules, projects, recent activity). It omits payload size/format expectations, which is the only real gap for a bundle of this scope.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema already says "Omit for the full bundle," so 3 would be the baseline. The description earns above baseline by explaining the tradeoff the parameter actually controls — a smaller bundle containing only the memory notes that apply — which clarifies the filtering effect on returned content.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Returns) and enumerates the exact resource contents: owner identity, preferences and feedback rules, projects, recent activity. This is distinctly different from read/search siblings like brain_search or brain_read, so an agent can route to it without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Call this FIRST in every conversation" gives a clear, strong usage condition, and the description explains when to narrow with `topic`. It stops short of naming alternatives or a when-not condition (e.g., what to use for later queries in the same conversation), so it isn't fully explicit about the sibling choice.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

brain_moveMove or rename a hand-written noteA
Destructive

Move or rename a note within Notes/ and Captures/, for example to promote a capture into Notes/. Refuses to overwrite an existing note, and reports any links that stop resolving.

ParametersJSON Schema
NameRequiredDescriptionDefault
toYesNew vault path, e.g. 'Notes/Harbor Ledger.md'
noteYesNote id (vault path), title or [[wikilink]]

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true, readOnlyHint=false, and idempotentHint=false, so the safety profile is covered. The description earns credit by adding two traits the annotations don't carry: a non-overwrite guarantee and a side effect where broken links are reported. That is meaningful mutation context beyond the structured hints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero filler, and the scope/behavior come before the example. Every clause carries information an agent can act on.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description usefully covers the observable result (refused overwrites, reported dangling links). What is missing is smaller: no indication of what happens if the destination directory does not exist or what the tool returns on success.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and both parameters have examples in the schema ('Notes/Harbor Ledger.md' and note id/title/[[wikilink]]). The description adds no path syntax, length limit, or wikilink-vs-path resolution details, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific pair of verbs (move/rename) against a specific resource (a hand-written note) and scopes it to Notes/ and Captures/, with a concrete example of promoting a capture into Notes/. It never names the siblings it must be distinguished from (brain_edit, brain_write, brain_capture), so the separation is inferable rather than explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'promote a capture into Notes/' example implies a usage context, but there is no explicit when-to-use versus brain_edit/brain_write, no stated prerequisites, and no conditions under which the tool should not be used. Usage is suggested, not specified.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

brain_projectProject briefingA
Read-onlyIdempotent

One-call briefing on a project: what it is, its notes grouped by type, latest progress entries, decisions, and what changed recently. Call this before discussing any project. Omit the project name to list all projects.

ParametersJSON Schema
NameRequiredDescriptionDefault
projectNoProject / hub name, e.g. 'Website Redesign'. Omit to list projects.
recent_daysNo

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnlyHint, idempotentHint, openWorldHint=false), so the bar is lower; the description still adds real value by disclosing the aggregate return shape and the dual behavior of listing all projects when the name is omitted. It does not mention rate limits, result caps, or pagination, so it is not exhaustive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two dense sentences, zero filler, with the aggregation scope front-loaded and the list-all fallback stated last where it belongs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description usefully enumerates the returned sections and covers the zero-argument listing mode, which is what an agent needs to call it correctly. The one gap is the unexplained recent_days window, which affects how results are scoped.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 50%: 'project' is documented in the schema, but 'recent_days' carries no description and the tool description never names it or explains the 30-day default / 1-365 range. 'What changed recently' hints at the recency window but does not compensate for the undocumented parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific verb and resource ('One-call briefing on a project') and enumerates what the briefing contains (notes by type, progress, decisions, recent changes), which implicitly separates it from single-purpose siblings like brain_read or brain_recent. It never names an alternative sibling explicitly, so it stops short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Call this before discussing any project' is an explicit, actionable when-to-use trigger, and the omit-the-name mode is spelled out. There is no when-not guidance or named alternative for narrower needs (e.g. when brain_search is preferable), so it is clear context without exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

brain_readRead a noteA
Read-onlyIdempotent

Return one note in full (or one section of it) by note id, title, or wikilink target. Includes frontmatter metadata, topics, and links.

ParametersJSON Schema
NameRequiredDescriptionDefault
noteYesNote id (vault path), exact title, or [[wikilink]]
sectionNoHeading text to return only that section
include_connectionsNoKeep the generated '## Connections' trailer

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and openWorldHint=false, so the safety profile is covered. The description adds useful return content details—frontmatter metadata, topics, and links—that go beyond what annotations provide, though it omits error behavior and response format specifics.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tightly written sentences with zero waste. The purpose is front-loaded, and the optional section behavior is noted without unnecessary elaboration.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read tool with no output schema, the description covers the core return content (frontmatter, topics, links) and the section option. It could mention missing-note behavior or response format, but nothing critical is absent for an agent to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema fully documents all three parameters. The description echoes the note and section concepts but adds no syntax or format details beyond what the schema already provides, making the baseline 3 appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Return') and resource ('one note in full or one section') by note id, title, or wikilink target. It clearly distinguishes reading a single note from broader tools like brain_search, but does not explicitly name any sibling alternative.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied: use this when you have a note identifier and want the full note or a section. However, there is no explicit when-to-use guidance, no exclusions, and no mention of alternatives like brain_search for discovery.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

brain_recentWhat changed recentlyA
Read-onlyIdempotent

Notes modified in the last N days, newest first. Answers 'what am I working on' and 'what did I do last week'. Hubs and concepts are excluded unless include_structural is set.

ParametersJSON Schema
NameRequiredDescriptionDefault
daysNo
limitNo
projectNo
include_structuralNo

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, closed-world behavior, so safety is covered. The description adds genuinely non-obvious behavior: results are ordered newest-first and hubs/concepts are suppressed unless include_structural is set, which materially changes what comes back.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences with the core scope (what, window, ordering) front-loaded, followed by use-case framing and the structural-exclusion caveat. No filler or restatement of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only list tool with annotations covering the safety profile and no output schema, the description covers scope, ordering, and the key filtering caveat. The remaining gap is the undocumented 'limit' and 'project' parameters, which an agent must infer from the schema alone.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the burden. It gives real meaning to 'days' (the N-day window) and 'include_structural' (which entity types are excluded), but says nothing about 'limit' or the 'project' filter, leaving half the parameters undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Notes modified in the last N days, newest first'), which clearly separates it from a general query tool. It does not, however, explicitly name a sibling such as brain_search to route the agent away from a broader search.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives concrete usage contexts via example questions ('what am I working on', 'what did I do last week'), which tells the agent when this tool is the right pick. It stops short of stating when NOT to use it or naming the alternative tool for filtered/full-history queries.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

brain_rememberRemember a durable factA

Append one durable fact about the owner to their memory file: a preference, a correction on how to work, a project constraint, or a reference. It becomes part of brain_identity immediately. Include why it matters and how to apply it. Near-duplicates of existing memory are refused; pass force=true to store anyway. Do not store session trivia.

ParametersJSON Schema
NameRequiredDescriptionDefault
whyNo
factYes
forceNoStore even if it looks like a duplicate
categoryYesuser = who they are; feedback = how to work with them; project = ongoing work; reference = pointer
how_to_applyNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish write/non-destructive/non-idempotent, but the description adds behavior not visible in structured fields: near-duplicates are refused by default, force overrides that refusal, and the fact propagates to brain_identity immediately. These are substantive operational traits (dedup semantics, side-effect timing) that an agent cannot infer from the schema or hints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Five short sentences, all load-bearing: action, content to include, override mechanism, and exclusion. The core action is front-loaded in the first clause and nothing is repeated from the schema or title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter mutation tool with no output schema, the description covers purpose, required content guidance, duplicate handling, and scope limits. No output schema exists, so return-value explanation is not needed, and the annotations carry the safety profile.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 40% (only force and category are documented), so the description must compensate. It does: 'Include why it matters and how to apply it' explains the why and how_to_apply fields, and the enumeration of fact kinds maps onto the category enum. It adds real meaning beyond the schema, though it never explains the 2000-character limit or the fact minLength constraint.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Append one durable fact about the owner to their memory file') and enumerates what counts as such a fact (preference, correction, project constraint, reference), which mirrors the category enum. The 'durable fact' framing plus the explicit exclusion of 'session trivia' effectively separates it from capture-style siblings without needing to name them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a positive use case (durable facts), an explicit exclusion ('Do not store session trivia'), and a procedural alternative for the duplicate case ('pass force=true to store anyway'). It stops short of naming or routing to sibling tools for adjacent operations, so it is clear context rather than full when/when-not/alternative guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

brain_writeCreate or replace a hand-written noteA
DestructiveIdempotent

Create a note at a path you choose under Notes/ or Captures/, or replace one there with overwrite=true. Use it for hubs, guides and runbooks maintained by hand. Unlike brain_capture you set the type, including 'hub': a hub groups every note whose frontmatter project matches its title. Generated notes elsewhere in the vault cannot be written.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyYesMarkdown body, without frontmatter or the # title heading
pathYesVault path, e.g. 'Notes/Harbor Ledger.md'
typeNonote, hub, moc, guide, runbook, plan, decision, ...note
orderNoPosition among Notes/ guides on Start Here
titleYes
topicsNoConcept names, e.g. ['OAuth', 'RAG']
projectNoHub this note belongs to, e.g. 'Harbor Ledger'
summaryNoOne line; Start Here shows it next to Notes/ guides
overwriteNoReplace the note if the path already exists

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructiveHint=true and idempotentHint=true; the description adds real value by disclosing the path constraint and the overwrite=true condition that triggers replacement. Does not mention permission requirements or what a failed overwrite returns, but covers the destructive surface adequately.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the create/replace action, then constraints and the sibling differentiation. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 9-param mutation with destructive and idempotent annotations and a rich schema, the description covers scope, the hub behavior, the overwrite path, and the sibling boundary. It leaves return-value and permission specifics unstated, but the schema and annotations carry those.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 89%, so the schema already documents all nine parameters including the overwrite and type semantics. Description reinforces the overwrite condition but adds no syntax or format detail beyond the schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States specific verb (create/replace), resource (note), and the constrained location (under Notes/ or Captures/). Explicitly distinguishes from sibling brain_capture by noting who sets the type, and rules out generated vault notes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Names the alternative (brain_capture) and the condition selecting this tool: hand-written hubs, guides, runbooks. Also states an explicit exclusion ('Generated notes elsewhere in the vault cannot be written').

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 13 tool updatesv0.4.0
    • First observedbrain_capture
    • First observedbrain_context
    • First observedbrain_delete
    • First observedbrain_edit
    • First observedbrain_graph
    • First observedbrain_identity
    • First observedbrain_move
    • First observedbrain_project
    • First observedbrain_read
    • First observedbrain_recent
    • First observedbrain_remember
    • First observedbrain_search
    • First observedbrain_write

TDQS

A4.1/5.0

Scored across 13 tools

Disambiguation4/5

Read-side tools (identity, context, search, read, project, graph, recent) each target a distinct retrieval angle, though brain_context vs brain_search overlap somewhat since both perform relevance retrieval over the vault. Write-side tools (capture, write, edit) have boundaries clarified by descriptions (capture folder vs arbitrary path vs partial edit). Overall distinct but a few pairs require reading descriptions to tell apart.

Naming Consistency4/5

Every tool shares the brain_ prefix and snake_case format, giving a strong predictable namespace. The suffix mixes verbs (search, read, write, edit, move, delete, capture, remember) with nouns (identity, context, project, graph, recent), a minor deviation from a strict verb_noun pattern but still readable and consistent in style.

Tool Count5/5

13 tools is well within the ideal 3-15 band and each earns its place across distinct retrieval and mutation concerns. No redundant or trivial tools pad the set.

Completeness5/5

Full lifecycle coverage for a personal knowledge vault: retrieval (search, context, read, graph, recent, project, identity) plus creation (capture, write, remember), partial update (edit), full overwrite, move/rename, and soft delete to trash. No obvious dead ends for the stated domain.

Maintenance

ActivityMaintained
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides semantic search capability over Obsidian vaults and exposes recent notes as resources to Claude through the MCP protocol.
    9
    -
  • A
    license
    A
    quality
    B
    maintenance
    Give Claude (and any MCP client) real agent access to your Obsidian vault — graph traversal, Dataview queries, daily-note awareness, and more.
    25
    7 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides semantic search, note retrieval, source explanation, daily digests, and health checks for a local Obsidian vault, enabling MCP clients like Claude Desktop and Claude Code to query the second brain via natural language.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    MCP server exposing fast full-text and semantic search over an Obsidian vault, plus safe structured note read and write access for Claude.
    2
    Apache 2.0