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.

    • Follow links (off by default, retrieval.graph): a section of a note linked with the top hits (hub and topic pages included, with a boost when several top hits link to the same note) can take a reranker place from the weakest fused entry it beats, and the reranker reads the sentence that links them. A section the last step would trim is kept anyway when it is linked with a kept hit.

    • 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 the reranker's floor, answer "nothing relevant"; otherwise return the strong hits and at least the five best, 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. Like brain_write and brain_edit, its reply lists existing notes the text names without linking, so the caller can link them in the sentence that says how they relate.

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-ranking.mjs  # the ranker with stand-in models: empty shortlist, notes without sections, agreeOverride, the link graph
node scripts/verify-policy.mjs   # notes a connection may not read never rank, appear or get named in a links line
node scripts/verify-graph.mjs    # link kinds, every way of writing a link target, duplicate names, the window each link sits in
node scripts/verify-mentions.mjs # write replies name existing notes mentioned without a link, never private or already-linked ones
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     # 29 harder questions: paraphrase, typo, identifier, date, two-note, alias, off-topic
node scripts/debug-rank.mjs "your question"   # trace one query: each list, the reranker shortlist and why entries were cut
node scripts/graph-stats.mjs     # your link graph: links by where they sit, links written between content notes, unresolved names

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, 29 harder questions, 11 of them needing two notes and 7 off-topic:

Ranker

Right note first

Right note in top 5

Off-topic questions refused

Two-note questions with both notes in the context pack

Keyword only

77%

100%

2 of 7

–

Hybrid (default)

73%

86%

6 of 7

9 of 11

The script follows every note an answer needs through the ranker. On this vault all of them reach the reranker's shortlist; what used to lose them was the last step, which trimmed the second note of a two-note answer and refused some real questions. Two settings fix most of that: a "nothing relevant" floor calibrated per reranker model (bge-reranker-base 0.02, ms-marco-MiniLM 0.001; the two score on very different scales), and keeping at least the five best hits (minKeep). Before them the same set scored 82% in the top 5 and 7 of 11. A third, agreeOverride, is off: answering instead of refusing when keyword and meaning search put the same section first rescues the money-tracker paraphrase here, but also answers off-topic questions that share one rare word with a note, such as "python snake species in india". The off-topic question still answered, "which of Ines's projects runs on Kubernetes", is a near miss: the vault holds related notes, so no floor can tell it apart from a real question. Paraphrase is still the weak spot (issue #3), and a faster reranker is issue #10.

To score your own vault, write cases with the notes each answer needs (required) and the sentences that prove it (evidence: a list of groups, each holding alternative spans of which one must be in the context pack), then run node scripts/eval-hybrid.mjs --config <your config> --cases <your cases>. --set key=value tries another setting (--set rerankN=8), --sweep key=a,b,c compares several in one run, --repeat 2 checks that two runs agree exactly, and --json keeps every result.

Graph visualizer

See your vault the way search sees it. npm run graph exports the link graph, and visualizer/ draws it in an Obsidian-style 2D view or in 3D:

  • Notes are coloured by meaning (their embeddings), so topics shade into each other.

  • Line thickness is the bond strength the ranker uses when it follows links.

  • Hovering a note lights its strongest neighbours in green and fades the rest.

  • Clicking a note lists its bonds with the sentence that makes each link.

npm run graph
cd visualizer && python3 -m http.server 4750 --bind 127.0.0.1   # open http://127.0.0.1:4750/

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]], [[Folder/Note]]) and in frontmatter become graph edges. Each link is recorded with where it sits, because that says how much the author meant it: inside a sentence, in a list item that explains it, as a bare list entry, in a heading or table, in frontmatter, or in a generated ## Connections trailer. Links inside code and embeds of images or other attachments are not links. A target resolves by path (or its end, as in [[Notes/Plan]]), title, file name or alias, ignoring case, .md, extra whitespace, and hyphens or underscores versus spaces; when several notes share a name, the one in the linking note's folder wins, then the shortest path. brain_graph, the links line of brain_read and the warnings of brain_move and brain_delete all follow these rules. In frontmatter, project, topics, related and part-of are links for every tool, plain names included; a [[link]] under any other key counts for the link graph only. A link's strength weighs where it sits, whether it is repeated or written both ways, and how many notes link to its target (a hub linked from everywhere says little); those counts include every note, private ones too, like the word statistics of keyword search, and reveal no note or text. 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), firstPicks (also rerank each search's own best hit), blend (fused rank vs reranker), floor (below it, "nothing relevant"; calibrated per reranker model unless you set it), goodAt (coverage "good" from here up), keepRatio, minKeep (always keep this many hits), agreeOverride (off; on, no refusal when keyword and meaning search put the same section first), earlyExit, aliases for your own shorthands, and graph, the link graph in ranking: enabled (off), slots (most reranker places linked sections may take, a ceiling), seeds, linksPerSeed, minWeight, swapWeight (above 1 forces linked sections in, for experiments), prefix (show the linking sentence), keepLinked and keepMinWeight (keep a trimmed section linked with a kept hit), and the link weights kinds and keys. BRAIN_MCP_GRAPH=0 or 1 and BRAIN_MCP_GRAPH_SLOTS override. 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? The floor is now calibrated per reranker and refuses plainly off-topic questions. Near misses, where the vault holds related notes but not the answer, still score like real questions: telling them apart needs a check that a passage actually answers the question. (#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, graph export
├── visualizer/           the graph visualizer: one HTML page and its vendored libraries
├── 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

14 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). The reply lists existing notes the body names without linking.

NameRequiredDescriptionDefault
bodyYesMarkdown body. Link related notes inside the sentence that says how they relate, e.g. 'The restore steps are in [[Restore the ledger database]]'; a bare list of links carries little weight.
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.1/5.0
Behavior3/5

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

The description is consistent with the annotations (write, non-destructive, non-idempotent) and adds useful context: notes land in the capture folder with generated frontmatter, and the reply lists named-but-unlinked notes. With annotations already declaring the safety profile and no output schema, this is helpful but thin — it does not warn about duplicate titles despite idempotentHint=false, nor explain overwrite or failure behavior.

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: what it does, when to use it, when not to. The scoping constraint is front-loaded and no sentence is wasted.

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

Completeness3/5

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

No output schema exists, and the description only partially covers the return value (naming the 'existing notes named without linking' detail). For a 5-parameter write tool that creates files, it lacks any mention of naming collisions, folder resolution, or what happens when the capture folder 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 coverage is 80%, so the schema already documents body, title, topics, and project. The description adds no per-parameter guidance beyond the general 'graph-ready frontmatter' framing, and the 'kind' enum is left to the schema's enum and default. 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 a specific verb and resource ('Write a new note into the vault's capture folder') plus the distinguishing trait of graph-ready frontmatter. It explicitly separates itself from brain_remember, which is also in the sibling list.

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 concrete use cases (plans, decisions, ideas, meeting notes, session logs) and an explicit exclusion with the alternative: 'Not for one-line facts (use brain_remember).' Nothing is left to inference.

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).

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.

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. The reply lists existing notes the new text names without linking.

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.5/5.0
Behavior5/5

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

Goes well beyond the destructiveHint=true annotation: it explains that old_text must occur exactly once, that new_text may be empty, that section replacement spans up to the next same-or-higher heading while the heading itself survives, and that generated notes/memory are off limits. It even discloses return behavior (the reply lists existing notes the new text names without linking).

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: scope first, then the three mutually exclusive modes, then the exclusions and reply note. No redundancy and nothing buried.

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?

Six parameters with one required, no output schema, and the description covers modes, exclusions, and return summary well. Minor gaps remain: what happens when old_text matches zero or multiple times (error vs no-op) and whether the target note must already exist.

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

Parameters5/5

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

The schema documents 83% of parameters, but the critical mutual-exclusivity rule ('Give exactly one of...') exists nowhere in the schema, and neither does the section boundary semantics or the permission for an empty new_text. These are exactly the constraints an agent needs to avoid a wrong invocation.

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 ('Change part of a note') plus a hard scope restriction (only under Notes/ or Captures/), and the phrase 'without rewriting it' implicitly separates it from brain_write. It never names a sibling, so the differentiation 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 Guidelines4/5

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

Gives crisp positive selection rules ('Give exactly one of: old_text + new_text, section + content, or append') and negative ones ('Generated notes and the memory file cannot be edited'). It stops short of routing to alternatives, e.g. pointing at brain_write for full rewrites or brain_read to inspect before editing.

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

brain_factsFacts and how they changedA
Read-onlyIdempotent

Facts recorded with brain_remember and when each was true. By default, the facts true now. as_of returns the facts true at another time (a bare date means the end of that day); history lists every version, oldest first, with what replaced it or when it expired; subject narrows to one thing, e.g. a project; query filters by words. The ids are the ones brain_remember's replaces takes.

NameRequiredDescriptionDefault
as_ofNoYYYY-MM-DD or YYYY-MM-DD HH:MM (UTC). Default: now.
limitNo
queryNoWords the fact should mention
historyNoEvery version, including replaced, expired and not-yet-valid facts
subjectNoOnly facts recorded with this subject, e.g. 'JobMail'
categoryNo

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, so the bar is lower; the description still adds non-obvious behavior: default is current truth, a bare date resolves to end-of-day, history is ordered oldest-first and includes replacements/expiry. It omits pagination/limit behavior and result shape, keeping it at 4.

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?

One dense paragraph, front-loaded with the default behavior, then each mode in the order an agent would consider them. Every clause carries information; 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 read-only, no-required-param list tool with no output schema, the description covers the query modes and the id linkage to brain_remember's `replaces`, which is the crucial cross-tool detail. Only the `category` enum and limit semantics are left unreconciled.

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 67%, and the description adds real semantics the schema lacks (e.g. a bare date means end of that day, history includes not-yet-valid versions). However, `limit` and especially the `category` enum are never explained in the description, leaving a gap.

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 resource (facts recorded via brain_remember) plus the temporal dimension (when each was true), and names the sibling that creates them. An agent can distinguish this from brain_search/brain_read without opening any 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?

Explicitly explains the default mode (facts true now) and the condition that selects each alternative mode: as_of for point-in-time, history for all versions, subject for narrowing, query for keyword filtering. It stops short of naming a sibling alternative (e.g. when to prefer brain_search over this), so 4 rather than 5.

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.

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. Captured facts are only the ones true now; brain_facts has their history. Pass topic (a few words about what the conversation is about) to get a smaller bundle with only the memory notes that apply.

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

TDQS

A4.9/5.0
Behavior5/5

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

Beyond the readOnly and idempotent annotations, the description discloses that the bundle should be adopted as persona and working context, that captured facts are current-only, and that passing topic returns a smaller bundle with only applicable memory notes. These are meaningful behavioral traits not captured by annotations or schema.

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?

The description is front-loaded with the critical instruction to call it first, then explains returns, usage posture, sibling distinction, and parameter effect. Every sentence is useful and appropriately sized for a one-parameter startup tool.

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 simple, optional-parameter, read-only tool with annotations and no output schema, the description covers purpose, expected return content, ordering requirement, persona adoption, historical-facts alternative, and topic behavior. Nothing essential 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 schema already documents topic and the omit-for-full-bundle behavior. The description adds useful semantic detail by clarifying that topic is a few words about the conversation and that it narrows the result to applicable memory notes.

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?

The description specifies a clear verb and resource: load the owner's identity and standing context. It enumerates the returned content (owner identity, preferences, feedback rules, projects, recent activity) and explicitly distinguishes itself from brain_facts by noting that brain_facts holds historical facts.

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?

It gives a direct usage rule: 'Call this FIRST in every conversation.' It also states when to use the optional topic parameter and implies the alternative for historical facts by naming brain_facts.

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.

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.

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.

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.

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. When it changes an earlier fact, pass replaces with that fact's id (the stamp in its heading, e.g. '2026-09-22 18:21'): the old fact stays in the file as history and leaves brain_identity. For a fact with one current value, pass subject and attribute (e.g. 'JobMail' and 'database'); a later fact with the same pair replaces it on its own. Use valid_until for something temporary and valid_from when it became true earlier than now. Near-duplicates of current facts are refused, and a fact that looks like it changes a current one is held back until you say whether it replaces it; pass force=true to store it as is. Do not store session trivia.

NameRequiredDescriptionDefault
whyNo
factYes
forceNoStore even if it looks like a duplicate or a change to a current fact
subjectNoWhat the fact is about, e.g. 'JobMail' or 'the owner'. Pass with attribute.
categoryYesuser = who they are; feedback = how to work with them; project = ongoing work; reference = pointer
replacesNoIds of current facts this one makes outdated, e.g. ['2026-09-22 18:21']
attributeNoWhich property of the subject, e.g. 'database' or 'employer'. Pass with subject.
valid_fromNoWhen it became true, if earlier or later than now: YYYY-MM-DD or YYYY-MM-DD HH:MM (UTC)
valid_untilNoWhen it stops being true, for temporary facts: YYYY-MM-DD (holds through that day) or YYYY-MM-DD HH:MM (UTC)
how_to_applyNo

TDQS

A4.2/5.0
Behavior3/5

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

Strong disclosure of non-obvious behavior that annotations cannot express: near-duplicates are refused, apparent changes are held back pending confirmation, superseded facts remain in the file as history but leave brain_identity, and new facts take effect immediately. However it does not describe what a call returns (e.g. the new fact's id), which an agent needs for later `replaces` calls; the hint that ids appear as heading stamps is indirect.

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?

Purpose is front-loaded in the first clause, and nearly every sentence carries a rule or condition. It is dense to the point of being a wall of rules, with parameter guidance interleaved rather than grouped, which slightly hurts scanning.

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?

Covers the full write-path behavior for a 10-parameter, non-idempotent mutation with no output schema: dedupe, history retention, temporal bounds, and override. The one gap is the response shape and how to obtain a fact id, which matters because `replaces` depends on it.

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

Parameters5/5

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

Adds genuine meaning beyond the 70%-covered schema: the `replaces` value format and its history-preservation effect, the subject+attribute pairing that makes later facts self-replacing, and the temporal semantics of valid_from/valid_until. Even the undocumented `why` and `how_to_apply` fields are given intent.

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?

Specific verb and resource ('Append one durable fact about the owner to their memory file') plus an enumeration of the kinds of facts it accepts, which pins down scope precisely. It does not name a sibling to route against (e.g. brain_capture vs brain_write), so differentiation is implied rather than stated.

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?

Explicit conditions for each mode of use: pass `replaces` when superseding an earlier fact, use subject/attribute for single-valued facts, `valid_until` for temporary facts, `valid_from` for backdating. It also gives an explicit exclusion ('Do not store session trivia') and explains the force override path.

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. The reply lists existing notes the body names without linking.

NameRequiredDescriptionDefault
bodyYesMarkdown body, without frontmatter or the # title heading. Link related notes inside the sentence that says how they relate.
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.5/5.0
Behavior4/5

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

Annotations already declare destructiveHint and idempotentHint, so the safety bar is lower; the description still adds real context beyond them: the path-root restriction, that overwrite replaces an existing note, and the non-obvious return behavior (existing notes named without linking, with no output schema to convey it). It doesn't spell out what is lost on overwrite (frontmatter/body replacement), which is the one gap.

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?

Front-loaded with the create/replace action and followed by usage, differentiation, and return behavior in four tight sentences. Every sentence carries information; the hub sentence is slightly dense but not wasteful.

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-parameter mutation tool with no output schema, the description covers the path constraint, overwrite semantics, type/hub behavior, and partial return information. Remaining details (order, topics, summary) are handled by high schema coverage, so nothing critical 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 89%, so the baseline is 3, but the description adds meaning the schema lacks: the 'hub' type's semantics (groups notes whose frontmatter project matches its title) and the overwrite replace behavior. It says less about order, topics, and summary, but those are documented in the schema.

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 the specific verb and resource ('Create a note at a path... or replace one with overwrite=true') and scopes it to Notes/ or Captures/. It explicitly distinguishes itself from brain_capture by noting the caller sets the type, so an agent can choose between the two without opening the schemas.

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 positive usage ('use it for hubs, guides and runbooks maintained by hand'), names the alternative it supersedes (brain_capture) with the differentiating condition, and states an exclusion ('Generated notes elsewhere in the vault cannot be written'). When/when-not/alternative are all present.

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. 4 tool updatesv0.5.2
    • Changedbrain_capture1 field changed
      • changedInput schema / properties / body / description
        Previous value: -"Markdown body. Link concepts inline with [[Concept]] on first mention."New value: +"Markdown body. Link related notes inside the sentence that says how they relate, e.g. 'The restore steps are in [[Restore the ledger database]]'; a bare list of links carries little weight."
    • Addedbrain_facts
    • Changedbrain_remember6 fields changed
      • addedInput schema / properties / attribute
        Added value: +{
        +  "description": "Which property of the subject, e.g. 'database' or 'employer'. Pass with subject.",
        +  "maxLength": 120,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • changedInput schema / properties / force / description
        Previous value: -"Store even if it looks like a duplicate"New value: +"Store even if it looks like a duplicate or a change to a current fact"
      • addedInput schema / properties / replaces
        Added value: +{
        +  "description": "Ids of current facts this one makes outdated, e.g. ['2026-09-22 18:21']",
        +  "items": {
        +    "maxLength": 30,
        +    "type": "string"
        +  },
        +  "maxItems": 10,
        +  "type": "array"
        +}
      • addedInput schema / properties / subject
        Added value: +{
        +  "description": "What the fact is about, e.g. 'JobMail' or 'the owner'. Pass with attribute.",
        +  "maxLength": 120,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / valid_from
        Added value: +{
        +  "description": "When it became true, if earlier or later than now: YYYY-MM-DD or YYYY-MM-DD HH:MM (UTC)",
        +  "maxLength": 40,
        +  "type": "string"
        +}
      • addedInput schema / properties / valid_until
        Added value: +{
        +  "description": "When it stops being true, for temporary facts: YYYY-MM-DD (holds through that day) or YYYY-MM-DD HH:MM (UTC)",
        +  "maxLength": 40,
        +  "type": "string"
        +}
    • Changedbrain_write1 field changed
      • changedInput schema / properties / body / description
        Previous value: -"Markdown body, without frontmatter or the # title heading"New value: +"Markdown body, without frontmatter or the # title heading. Link related notes inside the sentence that says how they relate."
  2. 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 14 tools

Disambiguation4/5

Most tools target clearly distinct operations (read, edit, delete, move, graph, recent), and the descriptions actively steer selection, e.g. brain_context says to use it before brain_search, and brain_capture vs brain_write is spelled out as templated-capture vs hand-maintained note. The remaining fuzzy pairs are retrieval (brain_context vs brain_search) and fact storage (brain_remember vs brain_capture), which are close enough that an agent may still occasionally pick wrong despite the guidance.

Naming Consistency4/5

Every tool shares the same `brain_` prefix and snake_case, which makes the set easy to scan. The stem after the prefix mixes verbs (search, read, write, edit, delete, move, capture, remember) with nouns (context, identity, facts, project, graph, recent), a minor inconsistency but still predictable and readable.

Tool Count5/5

14 tools is squarely in the well-scoped range, and each one maps to a distinct vault operation rather than a variant of another. Nothing looks redundant or padding-like; the memory, note, and retrieval surfaces all earn their entries.

Completeness4/5

The note lifecycle is essentially covered: create (capture/write), read, edit, move, delete-to-trash, plus search, graph, recency, project briefings, and fact history. Gaps are modest but real — several descriptions mention notes being named 'without linking' yet there is no link-creation tool, there is no restore-from-trash operation despite delete pointing to one, and there is no way to enumerate or browse the vault by folder or tag.

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
    14 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
    B
    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