brain-mcp
Provides tools for searching, reading, writing, and managing notes in an Obsidian vault, including identity bundles, context retrieval, project briefings, graph navigation, recent notes, note capture, and memory facts. It indexes Markdown notes with frontmatter and wikilinks, and keeps the index current via a file watcher.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@brain-mcpbrief me on my current projects and recent focus"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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.
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_rememberandbrain_captureturn 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)" .-> VIndex. 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.Retrieve. A question goes through five steps:
Understand: expand shorthands (
pg→ PostgreSQL) and fix typos against the vault's own words.Search four ways: keywords per section (BM25), meaning (embeddings), exact dates, and note titles.
Fuse the four lists with reciprocal rank fusion.
Rerank the best candidates with a cross-encoder (
bge-reranker-base), always including each list's first pick, so fusion cannot bury a hit only one search found. When keyword and meaning search agree on the top hit and fusion keeps it in the top 3, only those 3 are reranked.Decide: if even the best passage scores below a floor, answer "nothing relevant"; otherwise return the strong hits, cited by note, with a coverage label (good, thin, none).
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.
Remember and write.
brain_rememberappends durable facts and refuses near duplicates. A fact can replace an earlier one, expire, or start at a given date;brain_identityserves only the facts true now, andbrain_factskeeps 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.
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 |
| 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 |
| 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. |
| Hybrid search (keywords, meaning, reranker, spelling correction) with project, type, topic and date filters. Returns ranked notes with snippets. |
| One note, or one section of it, with metadata, topics and resolved links. |
| Briefing on a project: description, latest progress, decisions, recent changes and notes grouped by type. With no argument it lists projects. |
| Links out, backlinks grouped by project, and notes that share topics. |
| Notes modified in the last N days, newest first. |
| Writes a new note with graph-ready frontmatter into the capture folder. |
| Appends a fact to the memory file; it joins |
| Captured facts and when each was true: the current ones, the ones true at an |
| Creates a note at a chosen path in a writable folder ( |
| 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 |
| Moves or renames a note within the writable folders. Never overwrites, and names any notes whose links stop resolving. |
| Moves a note into |
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 initIt 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 --stdiohermes mcp add brain --command npx --args -y debawho-brain-mcp --stdioClaude 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.mjsThe 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 setupThe same setup as init, for a clone. It asks for your name (it suggests the one from git config) and where your notes are. Point it at an existing Obsidian vault, or press Enter for a starter vault in my-vault/ with a profile note to fill in. It writes brain.config.local.json, which git ignores and the server uses from then on, with its own index so your notes never mix with the example. It ends by printing the claude mcp add command for your machine: run it, then ask Claude "what do you know about me?"
Delete brain.config.local.json to go back to the example vault. The checks and evals always run against the example vault, so they keep passing after setup.
npm run typecheck
node scripts/verify.mjs # redaction, file watcher, HTTP bearer auth, audit log
node scripts/verify-facts.mjs # fact windows: dates, replacements, expiry, bad references
node scripts/verify-memory.mjs # brain_remember dedupe and replacements, brain_facts, identity, brain_context
node scripts/verify-write.mjs # write, edit, move and delete on a throwaway vault
node scripts/verify-oauth.mjs # the full OAuth 2.1 flow against a throwaway auth database
node scripts/verify-hybrid.mjs # hybrid search: refusal, spelling, identifiers, context
node scripts/verify-setup.mjs # npm run setup, in a temp folder
node scripts/verify-package.mjs # the npm package as a new user gets it: pack, install, init, serve
node scripts/verify-smart-search.mjs # the smart-search add-on: this OS's runtime only, hybrid ranking, remove
node scripts/eval-retrieval.mjs # 12 questions, keyword vs hybrid
node scripts/eval-hybrid.mjs # 15 harder questions: paraphrase, typo, identifier, date, multi-hop, alias, off-topic
node scripts/debug-rank.mjs "your question" # trace one query through every ranking stepIf 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 --buildThe compose file publishes 127.0.0.1-friendly port 3737, mounts brain.config.json and example-vault read-only, and keeps data/ and logs/ on the host. Health is checked at GET /healthz.
Keep the service private. The container binds 0.0.0.0 only so Docker can publish the port. Publish it on loopback (127.0.0.1:3737:3737) or a private network such as Tailscale — do not expose it to the public internet. Anything public should use OAuth (--oauth) behind a TLS proxy, as in the security model below.
To use your own vault, point vaultPath at a host mount (or replace the example-vault volume) and keep BRAIN_MCP_CONFIG on a config file whose vaultPath matches that mount.
Retrieval eval
Two scripts score retrieval on the example vault, keyword and hybrid side by side. Results are deterministic and reproducible from a fresh clone.
eval-retrieval.mjs, 12 everyday questions:
Ranker | Right note first | Right note in top 5 | Expected note in the context pack | Time per question (laptop CPU) |
Keyword only | 42% | 100% | 100% | 2 ms |
Hybrid (default) | 83% | 100% | 100% | about 1.1 s |
eval-hybrid.mjs, 15 harder questions:
Ranker | Right note first | Right note in top 5 | Off-topic questions refused |
Keyword only | 67% | 100% | 2 of 3 |
Hybrid (default) | 67% | 75% | 3 of 3 |
Hybrid search puts the right note first far more often and refuses questions the vault cannot answer. Its weak spot is paraphrase: on the harder set it still misses some real questions asked in other words, such as "why is the bird audio never sent to an online service". Calibrating the "nothing relevant" floor is issue #3, and a faster reranker is issue #10. When you point the server at your own vault, replace the cases with questions about your notes.
Use your own vault
npx debawho-brain-mcp init, or npm run setup in a clone, does this for you. To do it by hand, copy brain.config.json to brain.config.local.json (or ~/.brain-mcp/config.json for the npm package) and change what differs:
{
"vaultPath": "../my-vault",
"dataDir": "./data/local",
"owner": "Your Name",
"privatePaths": ["Private/**", "Journal/**"],
"identity": {
"profileNote": "About me",
"memoryProject": "Assistant Memory",
"skillsProject": "Assistant Skills"
}
}vaultPath and dataDir are resolved relative to the config file. The server uses the first config it finds: --config <path>, then BRAIN_MCP_CONFIG, then brain.config.local.json, then ~/.brain-mcp/config.json (npm package only), then brain.config.json. Run npm run reindex to check the note count; the first log line names the config in use.
Any Markdown file in the vault is indexed. Frontmatter makes it richer:
Field | Used for |
| Display name and title matching. Falls back to the file name. |
|
|
| The project a note belongs to, usually a wikilink to its hub: |
| Concepts the note is about, as wikilinks. Drives the topic filter and shared-topic neighbours. |
| Extra links, added to the graph like body wikilinks. |
| Other names |
|
|
| Date used for recency, |
| Shown next to each hub in the identity bundle. |
Wikilinks in the body ([[Note]], [[Note#Heading]], [[Note|alias]]) become graph edges. A leading # Title that repeats the title is dropped from what clients read, and a generated ## Connections trailer after a --- rule is left out of search and context.
Profile: the note named by
identity.profileNote, matched by title, alias, path or file name.Memory: every note whose
projectisidentity.memoryProject. Write each one with a How to apply line; the bundle tells the client to follow them.Captured facts: the facts in
memoryFilethat 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.focusWindowDaysdays.
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:10and2026-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. ASupersedesline 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 |
| Vault folder, relative to the config file. |
| Folder for the search index and the OAuth database, relative to the config file. Default: |
| Name used in the server instructions and the identity bundle. |
| The only folder the server writes to. |
| File |
| Top-level folders that are never indexed. Any path segment starting with |
| Globs that are never served to anyone. |
| Project names and globs that need the |
|
|
| Profile note, memory and skills projects, focus window and size caps. |
| Hybrid ranking: |
| Folders the write, edit, move and delete tools may change. Default: the capture folder and |
| Host, port and path for HTTP modes. The shipped config uses |
| 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 --stdioFrom 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 toolsThe 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/mcpBRAIN_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-mcpThen 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-mcpConnect 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/mcpand 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-totpKeep 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 markedvisibility: private, or matched byprivateProjectsorprivatePaths, need the private scope.denyPathsare never served. The example vault keeps one note underPrivate/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 DockerImporters for other note tools (#6)
Passkey sign-in (#7)
Facts that change over time: replacements, expiry and history (#8)
Contributing
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 |
|
Hybrid search: BM25, embeddings, rank fusion |
|
Running embedding and reranker models on a CPU |
|
Turning wikilinks and frontmatter into a knowledge graph |
|
OAuth 2.1 with PKCE, token rotation and TOTP |
|
Scopes and secret redaction |
|
Evaluating retrieval honestly |
|
Open research questions
Each of these is an open issue with a suggested approach and a definition of done:
When should retrieval abstain? Hybrid search refuses all off-topic questions, but also some real ones. Calibrating the floor is open. (#3)
Which reranker gives the best accuracy per millisecond on a CPU? A model six times faster finds the right note in 58% of everyday questions instead of 75%. (#10)
Can the graph a vault already has replace an LLM-built one for multi-hop questions? (#2)
How should AI memory notice that a fact changed? The memory file now records replacements and expiry, and
brain_factsanswers 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
Pick something. Browse good first issues, research questions or help wanted, or open an issue with your idea.
Run the checks. Everything runs against the bundled example vault, so no personal data is needed.
Measure. If your change touches ranking, run
node scripts/eval-retrieval.mjsbefore and after and paste both into the pull request. Good ideas win on numbers.Open a pull request. CI builds, typechecks and runs every verification script.
Read CONTRIBUTING.md for the details, and please follow the code of conduct.
Citing
If you use brain-mcp in research or teaching, please cite it. GitHub's Cite this repository button uses CITATION.cff.
Project structure
brain-mcp/
├── src/
│ ├── index.ts entry point: init, stdio, --http, --oauth, --reindex
│ ├── tools.ts the 14 MCP tools, resources and prompts
│ ├── context.ts brain_context: fusion and packing under a budget
│ ├── identity.ts the persona bundle
│ ├── memory.ts the memory file's blocks and near-duplicate checks
│ ├── facts.ts facts with validity windows: replacements, expiry, history
│ ├── policy.ts scopes and secret redaction
│ ├── vault/ parsing notes, the SQLite index, hybrid ranking
│ │ └── dense.ts local embeddings and the reranker
│ └── auth/ OAuth 2.1 server, login page, TOTP, token store
├── scripts/ setup, smoke test, verification scripts, retrieval eval
├── templates/ the starter vault init and npm run setup create
├── example-vault/ a fictional vault used by every script
├── deploy/ Linux and Windows setup, Cloudflare Tunnel template
└── brain.config.json the example vault's config; npm run setup writes yours beside itLicense
MIT. Created by Debashish Thakur.
Available Tools
13 toolsbrain_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).
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | Markdown body. Link concepts inline with [[Concept]] on first mention. | |
| kind | No | note | |
| title | Yes | Specific noun phrase, not a filename | |
| topics | No | Concept names, e.g. ['OAuth', 'RAG'] | |
| project | No | Project hub name this belongs to, e.g. 'Website Redesign' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, destructiveHint=false, idempotentHint=false and openWorldHint=false, so the write/safety profile is covered. The description adds where the note lands (capture folder) and that frontmatter is generated, but says nothing about duplicate-title handling or whether an existing file of the same name is overwritten or rejected.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with zero filler: what it writes, the destination, when to use it, when not to. Purpose and destination are front-loaded before the exclusion.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description could have stated what the caller gets back (created path/link or confirmation), and it says nothing about duplicate handling for a non-idempotent writer. Everything else an agent needs to select and call the tool is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 80%, so the schema already documents title, body, topics and project. The description's use-case list ('plans, decisions, ideas... logs') loosely maps onto the kind enum, but it adds no syntax, format, or constraint detail beyond what the schema provides. Baseline 3 fits.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (write/create) and resource (a new note) plus the destination (the vault's capture folder) and the extra behavior (graph-ready frontmatter). It explicitly differentiates itself from the sibling brain_remember for the one-line-fact case.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete when-to-use triggers ('plans, decisions, ideas, meeting notes, or session logs the owner wants to keep') and an explicit exclusion with the alternative named ('Not for one-line facts (use brain_remember)'). An agent can route between the two without opening either schema.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_contextGet the vault sections that answer a questionARead-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).
| Name | Required | Description | Default |
|---|---|---|---|
| project | No | Restrict to one project | |
| question | Yes | The question or topic, in plain words with specific nouns | |
| budget_chars | No | Size cap for the returned pack (default from config, ~18000) |
TDQS
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.
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.
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.
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.
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.
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)ADestructive
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.
| Name | Required | Description | Default |
|---|---|---|---|
| note | Yes | Note id (vault path), title or [[wikilink]] |
TDQS
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.
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.
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.
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.
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.
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 noteADestructive
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.
| Name | Required | Description | Default |
|---|---|---|---|
| note | Yes | Note id (vault path), title or [[wikilink]] | |
| append | No | Markdown to add at the end of the note | |
| content | No | New text for that section | |
| section | No | Heading text of the section to replace, without the # marks | |
| new_text | No | ||
| old_text | No | Exact text to replace; must occur exactly once |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=false, so safety is partly covered. The description adds valuable behavior beyond them: the exactly-once precondition on old_text (a concrete failure mode), the heading-level replacement rule ('up to the next heading of the same or higher level; the heading itself stays'), and explicit exclusions. It omits any permission/auth requirements, hence not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with purpose before the operational rules. Every clause carries information (scope, modes, preconditions, exclusions) with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-param mutation tool with no output schema and annotations already covering the safety profile, the description covers modes, preconditions, and exclusions. It doesn't state what happens on precondition failure (e.g., ambiguous old_text) or any return shape, but nothing critical for invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 83%, so baseline is 3, and the description clearly exceeds it by explaining mode exclusivity and mode-specific semantics: old_text must occur exactly once, new_text may be empty, section replaces content up to the next same-or-higher heading while keeping the heading, and append adds at the end.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Change part of a note') and immediately scopes it to Notes/ or Captures/ and distinguishes it from a full rewrite, which implicitly separates it from brain_write. An agent can tell it does partial edits, not whole-note replacement, without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit usage rules: 'Give exactly one of' three mutually exclusive modes, and states what cannot be edited (generated notes, the memory file). It doesn't name a sibling tool directly, but the 'without rewriting it' framing routes the agent away from brain_write.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_graphExplore the link graphARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| note | Yes | Note id, title, concept name, or [[wikilink]] | |
| limit | No |
TDQS
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.
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.
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.
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.
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.
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 contextARead-onlyIdempotent
Call this FIRST in every conversation. Returns who the owner is, their preferences and feedback rules, the projects they run, and what they touched recently. Adopt it as your persona and working context. Pass topic (a few words about what the conversation is about) to get a smaller bundle with only the memory notes that apply.
| Name | Required | Description | Default |
|---|---|---|---|
| topic | No | What this conversation is about, e.g. 'interview prep' or 'database backups'. Omit for the full bundle. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this is a safe, idempotent, closed read, so the description is free to add behavioral meaning beyond safety: the bundle is a persona/working-context payload meant to be adopted, and passing `topic` changes the payload composition. It doesn't state format, size, or latency of the full bundle, but the added context is substantive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the imperative invocation rule, then the return contents, then the optional narrowing parameter. Four tight sentences with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing what comes back, and it enumerates the payload well (identity, preferences, feedback rules, projects, recent activity). It omits payload size/format expectations, which is the only real gap for a bundle of this scope.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already says "Omit for the full bundle," so 3 would be the baseline. The description earns above baseline by explaining the tradeoff the parameter actually controls — a smaller bundle containing only the memory notes that apply — which clarifies the filtering effect on returned content.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Returns) and enumerates the exact resource contents: owner identity, preferences and feedback rules, projects, recent activity. This is distinctly different from read/search siblings like brain_search or brain_read, so an agent can route to it without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Call this FIRST in every conversation" gives a clear, strong usage condition, and the description explains when to narrow with `topic`. It stops short of naming alternatives or a when-not condition (e.g., what to use for later queries in the same conversation), so it isn't fully explicit about the sibling choice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_moveMove or rename a hand-written noteADestructive
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.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | New vault path, e.g. 'Notes/Harbor Ledger.md' | |
| note | Yes | Note id (vault path), title or [[wikilink]] |
TDQS
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.
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.
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.
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.
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.
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 briefingARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| project | No | Project / hub name, e.g. 'Website Redesign'. Omit to list projects. | |
| recent_days | No |
TDQS
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.
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.
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.
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.
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.
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 noteARead-onlyIdempotent
Return one note in full (or one section of it) by note id, title, or wikilink target. Includes frontmatter metadata, topics, and links.
| Name | Required | Description | Default |
|---|---|---|---|
| note | Yes | Note id (vault path), exact title, or [[wikilink]] | |
| section | No | Heading text to return only that section | |
| include_connections | No | Keep the generated '## Connections' trailer |
TDQS
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.
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.
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.
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.
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.
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 recentlyARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | ||
| limit | No | ||
| project | No | ||
| include_structural | No |
TDQS
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.
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.
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.
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.
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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives concrete usage contexts via example questions ('what am I working on', 'what did I do last week'), which tells the agent when this tool is the right pick. It stops short of stating when NOT to use it or naming the alternative tool for filtered/full-history queries.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_rememberRemember a durable factA
Append one durable fact about the owner to their memory file: a preference, a correction on how to work, a project constraint, or a reference. It becomes part of brain_identity immediately. Include why it matters and how to apply it. Near-duplicates of existing memory are refused; pass force=true to store anyway. Do not store session trivia.
| Name | Required | Description | Default |
|---|---|---|---|
| why | No | ||
| fact | Yes | ||
| force | No | Store even if it looks like a duplicate | |
| category | Yes | user = who they are; feedback = how to work with them; project = ongoing work; reference = pointer | |
| how_to_apply | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish write/non-destructive/non-idempotent, but the description adds behavior not visible in structured fields: near-duplicates are refused by default, force overrides that refusal, and the fact propagates to brain_identity immediately. These are substantive operational traits (dedup semantics, side-effect timing) that an agent cannot infer from the schema or hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Five short sentences, all load-bearing: action, content to include, override mechanism, and exclusion. The core action is front-loaded in the first clause and nothing is repeated from the schema or title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 5-parameter mutation tool with no output schema, the description covers purpose, required content guidance, duplicate handling, and scope limits. No output schema exists, so return-value explanation is not needed, and the annotations carry the safety profile.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 40% (only force and category are documented), so the description must compensate. It does: 'Include why it matters and how to apply it' explains the why and how_to_apply fields, and the enumeration of fact kinds maps onto the category enum. It adds real meaning beyond the schema, though it never explains the 2000-character limit or the fact minLength constraint.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Append one durable fact about the owner to their memory file') and enumerates what counts as such a fact (preference, correction, project constraint, reference), which mirrors the category enum. The 'durable fact' framing plus the explicit exclusion of 'session trivia' effectively separates it from capture-style siblings without needing to name them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a positive use case (durable facts), an explicit exclusion ('Do not store session trivia'), and a procedural alternative for the duplicate case ('pass force=true to store anyway'). It stops short of naming or routing to sibling tools for adjacent operations, so it is clear context rather than full when/when-not/alternative guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_searchSearch the vaultARead-onlyIdempotent
Full-text search across every note with optional filters. Returns ranked hits with snippets and note ids for brain_read. Keywords or a short question both work (hybrid keyword + semantic search with spelling correction); the reply states its coverage.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | ||
| limit | No | ||
| query | Yes | Keywords to search for | |
| since | No | Only notes modified on/after this date | |
| topic | No | Restrict to notes tagged with a concept, e.g. 'OAuth' | |
| project | No | Restrict to one project, e.g. 'Website Redesign' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly, idempotent, closed-world), and the description adds genuinely useful behavior beyond that: hybrid keyword+semantic retrieval with spelling correction, ranked results with snippets, and a self-reported coverage statement. It doesn't mention result volume limits or truncation behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the core purpose and search semantics, then the return shape. The parenthetical is dense but each clause carries information; nothing is padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description steps in to describe the return payload (ranked hits, snippets, note ids) and the search semantics. It is adequate for a 6-param search tool, though it leaves filter semantics and the limit ceiling undocumented.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 67% and the description only gestures at 'optional filters' without explaining type, topic, project, since, or the limit cap of 50. In particular the type enum with 12 values is left entirely to the schema, so the description adds little beyond baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (search) and resource (every note) with scope (full-text, optional filters), and it distinguishes itself from brain_recent by saying 'every note' rather than recency-based listing. It also names brain_read as the downstream consumer of returned note ids.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains accepted input styles ('keywords or a short question both work') and what to do with the results (note ids for brain_read), which gives clear context for use. It stops short of naming when to prefer a sibling like brain_recent or brain_graph, so it lacks exclusions.
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 noteADestructiveIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | Markdown body, without frontmatter or the # title heading | |
| path | Yes | Vault path, e.g. 'Notes/Harbor Ledger.md' | |
| type | No | note, hub, moc, guide, runbook, plan, decision, ... | note |
| order | No | Position among Notes/ guides on Start Here | |
| title | Yes | ||
| topics | No | Concept names, e.g. ['OAuth', 'RAG'] | |
| project | No | Hub this note belongs to, e.g. 'Harbor Ledger' | |
| summary | No | One line; Start Here shows it next to Notes/ guides | |
| overwrite | No | Replace the note if the path already exists |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and idempotentHint=true; the description adds real value by disclosing the path constraint and the overwrite=true condition that triggers replacement. Does not mention permission requirements or what a failed overwrite returns, but covers the destructive surface adequately.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the create/replace action, then constraints and the sibling differentiation. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-param mutation with destructive and idempotent annotations and a rich schema, the description covers scope, the hub behavior, the overwrite path, and the sibling boundary. It leaves return-value and permission specifics unstated, but the schema and annotations carry those.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 89%, so the schema already documents all nine parameters including the overwrite and type semantics. Description reinforces the overwrite condition but adds no syntax or format detail beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States specific verb (create/replace), resource (note), and the constrained location (under Notes/ or Captures/). Explicitly distinguishes from sibling brain_capture by noting who sets the type, and rules out generated vault notes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative (brain_capture) and the condition selecting this tool: hand-written hubs, guides, runbooks. Also states an explicit exclusion ('Generated notes elsewhere in the vault cannot be written').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
13 tool updates
v0.4.0- First observed
brain_capture - First observed
brain_context - First observed
brain_delete - First observed
brain_edit - First observed
brain_graph - First observed
brain_identity - First observed
brain_move - First observed
brain_project - First observed
brain_read - First observed
brain_recent - First observed
brain_remember - First observed
brain_search - First observed
brain_write
TDQS
Scored across 13 tools
Read-side tools (identity, context, search, read, project, graph, recent) each target a distinct retrieval angle, though brain_context vs brain_search overlap somewhat since both perform relevance retrieval over the vault. Write-side tools (capture, write, edit) have boundaries clarified by descriptions (capture folder vs arbitrary path vs partial edit). Overall distinct but a few pairs require reading descriptions to tell apart.
Every tool shares the brain_ prefix and snake_case format, giving a strong predictable namespace. The suffix mixes verbs (search, read, write, edit, move, delete, capture, remember) with nouns (identity, context, project, graph, recent), a minor deviation from a strict verb_noun pattern but still readable and consistent in style.
13 tools is well within the ideal 3-15 band and each earns its place across distinct retrieval and mutation concerns. No redundant or trivial tools pad the set.
Full lifecycle coverage for a personal knowledge vault: retrieval (search, context, read, graph, recent, project, identity) plus creation (capture, write, remember), partial update (edit), full overwrite, move/rename, and soft delete to trash. No obvious dead ends for the stated domain.
Maintenance
Related MCP Connectors
Token-efficient MCP memory for Markdown vaults. Tiered search, GraphRAG, AI memories.
Notes and memory assistant: one Markdown vault that Claude, ChatGPT and any MCP client can share.
Search and reason over your Obsidian-style Markdown vault, right from ChatGPT.
- TaprootOAuthcom.taproothq
Persistent memory layer for AI tools. Save and recall notes across Claude and other MCP clients.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides semantic search capability over Obsidian vaults and exposes recent notes as resources to Claude through the MCP protocol.9-
- AlicenseAqualityBmaintenanceGive Claude (and any MCP client) real agent access to your Obsidian vault — graph traversal, Dataview queries, daily-note awareness, and more.257 npm1MIT
- AlicenseNot gradedqualityDmaintenanceProvides 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
- AlicenseNot gradedqualityAmaintenanceMCP server exposing fast full-text and semantic search over an Obsidian vault, plus safe structured note read and write access for Claude.2Apache 2.0