second-brain
A shared, persistent markdown-backed memory brain (Graph-RAG over a wikilink vault) that agents can read, write, and coordinate through.
Recall context (
brain_recall): hybrid keyword/semantic search plus wikilink hops (0–3), packed into a token budget (≤8000) and returned as a ready-to-usesystemPromptwith notes marked as reference data.Search notes (
brain_search): ranked list of matching notes (keyword + optional semantic, recency re-rank) with ids, tags, scores and previews; useful for checking duplicates before writing.Read a note (
brain_node_get): full markdown, metadata (type, tags, agent, importance, version, dates), plus outLinks and inLinks.Write memories (
brain_remember): create a new note (never overwrites; title clashes get numbered filenames) underagents/<agent>/, with type, tags, agent and importance.Update a note (
brain_node_update): append or replace body text, or change tags/importance, with version checking and one retry — the only destructive tool.Task queue (
brain_tasks_submit/brain_tasks_list/brain_tasks_update): shared markdown task list with priorities and dependency blocking; completing a task auto-releases dependents (failures cascade tofailed). It records work but does not run it.Agent messaging (
brain_messages_send/brain_messages_get/brain_messages_mark_read): per-agent inboxes for short hand-offs, with unread filtering and read marking.Health check (
brain_health): server status, version, note and link counts — the server auto-starts on first tool call.Read-only by default: all read tools carry
readOnlyHint; nothing deletes a note.
Runs sandboxed code execution inside network-disabled, resource-capped, read-only, auto-removed Docker containers.
Provides path-scoped Git synchronization and auto-commits, staging only changed vault files and serializing concurrent writes to avoid Git index lock races.
Supports NVIDIA NIM as an LLM provider in the router, allowing configured model calls to fall through to NVIDIA NIM.
Operates natively as an Obsidian vault on the filesystem, storing agent memories as Markdown notes with [[wikilinks]] that can be opened and edited in Obsidian, with hot-reloading of changes.
Supports local Ollama models as an optional LLM provider/fallback in the unified router.
Supports OpenAI-compatible LLM endpoints through the unified router for optional model-backed memory reconciliation and related tasks.
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., "@second-brainwhat database did we decide to use for Atlas, and why?"
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.
🧠 Autonomous Agent Second Brain — Graph-RAG Memory Core
A zero-dependency, offline-first Graph-RAG memory system that enables autonomous AI agents to share long-term memories, accumulate research, and coordinate workflows.
Designed to operate natively as an Obsidian Vault on the filesystem and exposed as a clean REST API and Javascript SDK. By representing memories as interconnected nodes ([[wikilinks]]) and fusing graph traversal, keyword search, optional semantic similarity, and recency into one ranked signal, it filters and delivers targeted context to LLMs, returning only the notes relevant to a query, within a token budget, instead of whole files or directories.

⚡ Quick start (MCP)
Give Claude Code, Claude Desktop, Cursor or any MCP client a shared, persistent memory in one line. Needs Node 22.5+; no install step, no API keys.
claude mcp add second-brain -- npx -y mind-mri-second-brainOther clients: add {"mcpServers":{"second-brain":{"command":"npx","args":["-y","mind-mri-second-brain"]}}} to their MCP config. Your notes are plain markdown in ~/.second-brain/vault, so you can open the folder in Obsidian and read or edit everything your agents remember. See MCP Server for the tool list and options.
What a session looks like (real output from the tools, trimmed for length):
brain_remember title "Decision - Use SQLite for the cache", type decision,
content "We chose SQLite over Redis ... See [[Project - Atlas]]."
→ { "success": true, "id": "agents/atlas/Decision - Use SQLite for the cache", "version": 1 }
brain_recall query "what database does Atlas use and why", hops 1
→ 2 notes, ~77 tokens:
### Decision - Use SQLite for the cache [DECISION]
We chose SQLite over Redis for the local cache: zero ops, one file ...
### Project - Atlas [MEMORY] ← pulled in through the [[wikilink]]
Atlas is the internal reporting service. Stack: Node, SQLite ...
brain_node_update id "agents/atlas/Decision - Use SQLite ...", content "Update: confirmed after load test, p95 read latency 3 ms."
→ { "success": true, "mode": "append" }Recall returns just the relevant notes plus the notes they link to, inside a token budget, and frames them to the model as reference data rather than instructions.
Related MCP server: io.github.Indhar01/memograph
🚀 Why This Project Stands Out (Portfolio Highlights)
This project showcases several advanced backend engineering principles and data modeling architectures:
Zero-Dependency Node.js Backend: Built using pure native Node.js ES Modules (
http,fs,path,child_process,node:sqlite,node:test). Instantly boots in milliseconds, is highly secure against dependency vulnerability chains, and is extremely portable. Every capability added since 1.0 — semantic search, dedup, task queue, messaging, sandboxed execution — follows the same rule: no required npm dependency, ever. An optional one (a cloud embedding key, Docker,@huggingface/transformers) simply degrades gracefully to "unavailable" when absent, never a crash.Graph-RAG vs. Flat-RAG: Flat RAG systems (using simple vector similarity) yield disconnected text chunks that lose context. This engine parses Obsidian-style wikilinks (
[[Page Name]]) to build an adjacency map, tracing logical connections between ideas.Hybrid Search via Reciprocal Rank Fusion:
/searchand/recallfuse a keyword arm (the original cached TF-IDF engine, untouched) with an optional semantic-similarity arm (cosine similarity over cached embeddings) using Reciprocal Rank Fusion — the same rank-based merge technique used to combine independent, non-comparable ranking signals without normalizing raw scores across them. With no embedding provider configured, this is provably identical to the original keyword-only behavior: the semantic arm short-circuits to empty and the fused result falls back to exactly what plain TF-IDF would return.Token Economics (Optimized Context): Rather than feeding raw file structures (~50k tokens) or arbitrary chunks into LLM context windows, agents query
/recallto receive a pre-assembled context payload restricted to a custom token budget (~300–2,000 tokens), preventing model attention degradation.Native File System Hot-Reloading (
fs.watch()): Automatically invalidates and refreshes the memory index in real time when files are edited (either manually in Obsidian or programmatically via the API). Built using native file system events with a debounce timer to keep queries fast against an in-memory index.Cached TF-IDF Search Engine Optimization: To keep search fast, the backend pre-tokenizes vault contents and pre-calculates inverse document frequencies (IDF) and vector magnitudes during graph cache loading, eliminating O(N) tokenization and regex parsing on every search.
SQLite-Backed Semantic Embeddings: Optional per-node vector storage via
node:sqlite(built into Node ≥22.5, no install, no native compile step) — real indexed per-row reads/writes and actual transactions, instead of a single ever-growing JSON blob. Multi-provider fetch (OpenAI, Gemini) with an optional local-model last resort, so semantic search never goes fully dark just because a cloud key ran out of quota.Optimistic Concurrency Control (OCC): Prevents concurrent write overrides. Nodes contain a
versionproperty in YAML frontmatter that increments on actual updates.PATCHcalls that include aversionmust match the current one, failing with409 Conflictif the note was modified concurrently (omitversionto skip the check).Strict Node Schema Validation: Validates incoming payloads (
titlefilename characters,typeenums,importancebounds, andtagsformat) before writing files to disk. Titles become filenames, so< > : " / \ | ? *and control characters are rejected by the API; the SDK normalizes them to-automatically.Granular Read & Write Authentication Security: When
BRAIN_KEYis configured, Bearer Token authentication is enforced across all endpoints—including search, recall, and graph views. The telemetry stream endpoint (/stream) requires a matching?token=parameter to block raw data exposure on public URLs.PII & Secrets Safeguard:
sdk/safeguard.jsis a standalone regex-based redaction utility (API keys across ~20 providers, DB connection strings, PEM private keys, JWTs, SSNs, Luhn-checked credit card numbers) any code path in the project can call before logging, storing, or echoing text back.Near-Duplicate Memory Reconciliation:
sdk/dedup.jsgates candidates with a cheap embedding-similarity check, then asks an LLM judge whether two similar notes are truly the same fact (merge, preserving every detail) or materially different (keep both). Fails open on any error — a dedup failure never blocks a normal memory write.POST /dedup/scanreports candidates vault-wide without ever auto-merging.Multi-Agent Coordination Primitives: A vault-backed task queue (status tags, dependency-based blocking/cascading release) and agent-to-agent messenger (inbox/outbox as vault nodes), plus an org chart derived read-only from persona tags/frontmatter already in the vault. These are lightweight coordination primitives — a shared, auditable, markdown-backed task list and inbox — not a full autonomous orchestrator; something else still has to watch
pendingtasks and do the work.Sandboxed Code Execution:
POST /sandbox/executeruns code in a network-disabled, resource-capped, read-only, auto-removed Docker container. Without Docker it refuses to run anything unless you explicitly setSANDBOX_ALLOW_LOCAL=1, which enables an unisolated local child process guarded only by a keyword blacklist — a blacklist is not a security boundary, so only enable that in a fully trusted environment.Resilient, Path-Scoped Git Sync:
sdk/git_sync.jsreplaces a naive "stage the whole vault folder" auto-commit with one that stages only the files a caller says actually changed (so an unrelated in-flight edit never gets swept into someone else's commit) and serializes/queues concurrent writes instead of racing on.git/index.lock.Unified Multi-Provider LLM Router:
sdk/llm_router.jscalls Anthropic, OpenAI-compatible, Gemini, NVIDIA NIM, or local Ollama behind one interface, falling through a configurable priority chain on any failure, and repairs the most common way smaller models emit almost-valid JSON (unescaped control characters inside a string).MCP Server & CLI:
mcp/server.jsis a zero-dependency, stdio JSON-RPC MCP server exposing this REST API as MCP tools to any MCP-aware client, auto-spawning the API server if it isn't already running.sdk/cli.js(npm run brain -- <command>) wraps the same API for quick terminal use.Interactive Agent Simulator UI: Features a premium sidebar form in the dashboard where you can simulate multi-agent memory writes, watching the nodes, links, and EventSource telemetry update dynamically in the D3.js visualization — now alongside a second Org Chart tab built with vendored Preact + htm (see UI Architecture).
Human-Agent-in-the-Loop Coordination: Because memories are serialized as plain Markdown files (
.md) with YAML frontmatter, a human can open the same folder in Obsidian to audit agent reasoning, edit notes, or add guidelines directly into the graph.Test Suite & CI: A
node:test-based suite (no test framework dependency either) covers every module above, isolating side effects via temp directories, mockedfetch, and env-var overrides. GitHub Actions runs it across Node 22.x/24.x on every push/PR tomain, plus a syntax sweep over every file inapi/,sdk/,mcp/.
⚙️ Technical Architecture
graph TD
subgraph Client Environments
Agent1[Research Agent] -->|SDK: remember/recall| API[🧠 Second Brain REST API]
Agent2[Pipeline Agent] -->|SDK: remember/recall| API
Human[Human Operator] -->|Edits Notes| Obs[Obsidian Editor]
MCPClient[MCP-aware Client] -->|stdio JSON-RPC| MCP[mcp/server.js]
CLI[sdk/cli.js] -->|REST| API
MCP -->|auto-spawns / proxies| API
end
subgraph API Server
API --> Engine[Graph Engine]
Engine --> Search[Hybrid Search: TF-IDF + Semantic RRF]
Engine --> Cache[In-Memory Graph Cache]
Engine --> FS[Local FS Watcher]
API --> Tasks[Task Queue]
API --> Msg[Messenger]
API --> Org[Org Chart]
API --> Dedup[Dedup Scan]
API --> Sandbox[Sandboxed Execution]
end
subgraph Storage Layer
FS -->|Reads/Writes| Vault[(Markdown Vault)]
Search -->|Vectors| EmbedDB[(SQLite: .embeddings.db)]
Obs -->|Reads/Writes| Vault
Engine -->|Optional Async Sync| Git[Path-Scoped Git Sync]
end
subgraph LLM Layer
Dedup --> Router[LLM Router: Anthropic / OpenAI / Gemini / NVIDIA / Ollama]
end
Git -->|Auto Commit & Push| GitHub[Private GitHub Repo]🎨 UI Architecture
The project contains a dynamic, high-tech dashboard with two tabs:
Graph tab (original): built with D3.js (v7) and Marked.js. Force-directed graph simulation (nodes sized by link degree, colored by type), an interactive context panel for reading a node's markdown and navigating its outlinks/backlinks, and live filters + live reload via
/reload.Org Chart tab (new): built with vendored Preact + htm (
ui/preact.min.js,ui/htm.min.js— local files, no CDN, no build step).htm.bind(preact.h)turns a plain tagged template into the same VNode tree JSX would, rendered viapreact.renderas a real component tree (OrgMember,DepartmentCard,OrgChartView) fetchingGET /org-chart. This is the recommended pattern for any new view added to this file going forward — the rest ofui/index.html(the Graph tab) intentionally stays vanilla JS/innerHTML rather than being retroactively rewritten.
📡 REST API & Interface Directory
Method | Endpoint | Payload / Query | Description |
GET |
| — | Returns server stats, port, and vault nodes/edges volume. |
GET |
| — | Gets list of all index nodes with trimmed previews. |
GET |
| — | Gets specific note body, parsed outgoing links, and incoming backlinks. |
GET |
|
| Hybrid keyword + semantic search (Reciprocal Rank Fusion), fused with the original TF-IDF ranking. |
GET |
|
| Core Agent Context: graph context assembler within a token budget, seeded by hybrid search. |
GET |
| — | Returns complete adjacency map nodes and edges. |
POST |
|
| Commits a new markdown node into the vault directory. |
PATCH |
|
| Modifies an existing file's text content or YAML frontmatter metadata (OCC via |
DELETE |
| — | Deletes a note from the disk. |
POST |
|
| Submits a task to the vault-backed task queue. |
GET |
|
| Lists tasks, optionally filtered by status tag. |
PATCH |
|
| Updates a task's status; auto-releases/cascades dependents. |
POST |
|
| Sends an agent-to-agent message. |
GET |
|
| Reads an agent's inbox. |
GET |
| — | Department/lead structure derived from persona tags & frontmatter. |
POST |
|
| Reports near-duplicate node candidates; never auto-merges. |
POST |
|
| Runs a code snippet sandboxed (Docker, or a restricted local fallback). |
POST |
|
| (Re)computes semantic vectors for the vault in the background. |
GET |
| — | Lookups by node type, tag or agent; list of all tags. |
POST |
|
| Uses Gemini to merge |
GET |
| — | Full JSON export. |
POST |
| — | Refreshes the in-memory cache manually. |
📦 SDK Quick Start & Code Quality
The Client SDK is written in clean, modern Javascript using native fetch.
import { SecondBrain } from './sdk/index.js';
// Initialize Client (Reads optional BRAIN_API & BRAIN_KEY env variables)
const brain = new SecondBrain({
agent: 'pipeline-agent',
api: 'http://localhost:3747',
apiKey: process.env.BRAIN_KEY
});
/**
* Workflow Scenario: Context Recall -> Task Execution -> Memory Write
*/
async function runAutoPipeline() {
// 1. Fetch relevant context within 1 Graph Hop and 1500 token budget
const context = await brain.recall('API rate limiting design', 1, 1500);
// 2. Inject context directly into your LLM prompt
const llmPrompt = `
${context.systemPrompt}
Task: Design rate limiter middleware for backend services.
`;
const result = await myLlmClient.generate(llmPrompt);
// 3. Save learnings back to the shared memory bank for other agents
await brain.remember(result, {
title: 'Rate Limiting Middleware Specification',
type: 'research',
tags: ['infrastructure', 'security', 'rate-limit']
});
}CLI
npm run brain -- status
npm run brain -- recall "API rate limiting design"
npm run brain -- tasks submit "Investigate rate limiting approaches" --agents=pipeline-agent
npm run brain -- org-chartMCP Server
mcp/server.js is a zero-dependency, stdio MCP server that gives any MCP client (Claude Desktop, Claude Code, Cursor, …) a shared, persistent memory. It needs Node 22.5 or newer.
Install — add this to your client's MCP config (for example claude_desktop_config.json, or .cursor/mcp.json):
{
"mcpServers": {
"second-brain": {
"command": "npx",
"args": ["-y", "mind-mri-second-brain"]
}
}
}For Claude Code: claude mcp add second-brain -- npx -y mind-mri-second-brain. On native Windows (not WSL), Claude Code needs npx wrapped in cmd /c: claude mcp add second-brain -- cmd /c npx -y mind-mri-second-brain. Run that from Command Prompt (cmd.exe): Windows PowerShell 5.1 swallows the -- separator and fails with unknown option '-y' (PowerShell 7 is fine). In a JSON config the equivalent is "command": "cmd", "args": ["/c", "npx", "-y", "mind-mri-second-brain"].
Running from a clone instead? Use "command": "node", "args": ["/path/to/repo/mcp/server.js"].
First run. On the first tool call the MCP server starts the local API (api/server.js, bound to 127.0.0.1 only) in the background and keeps it running. Notes are plain markdown files: ~/.second-brain/vault when installed from npm, or ./vault in a clone. Override with BRAIN_VAULT. Optional: BRAIN_PORT (default 3747) and BRAIN_KEY (require a Bearer token).
Tool | Purpose | Writes? |
| Graph-RAG context for a query (wikilink hops, token budget) | no |
| Ranked keyword (+ semantic, if configured) search | no |
| One note with its outlinks and backlinks | no |
| Append to or replace an existing note (version-checked, so concurrent writers don't lose edits) | yes |
| Save a new note (creates a new file; never overwrites) | yes |
| Shared markdown task queue: add tasks (with dependencies), find pending work, claim and complete tasks with a recorded result; completing a task releases the ones blocked on it | submit, update |
| Agent-to-agent inboxes | send, mark read |
| Server and vault stats | no |
Read-only tools carry the MCP readOnlyHint annotation. No tool deletes a note; only brain_node_update can overwrite existing text (in replace mode), so it alone is marked destructive and clients will ask before running it.
🔒 Security & Authentication Setup
By default, the server runs in local/development mode with authentication disabled. For cloud deployments, multi-agent networks, or when exposing the REST API endpoints publicly, you should enforce Bearer Token authentication:
Set the Secret Key: Define the
BRAIN_KEYenvironment variable on your system or server:export BRAIN_KEY="your-highly-secure-secret-token"Enforced Protection: Once
BRAIN_KEYis set, all mutative endpoints (POST /remember,POST /reload,POST /consolidate,PATCH /node/:id,DELETE /node/:id, the task/message/dedup/sandbox endpoints, etc.) will block unauthorized requests and return401 Unauthorized.Authorization Header: Incoming requests must include the token in the
Authorizationheader:Authorization: Bearer your-highly-secure-secret-tokenClient SDK Configuration: When initializing the Javascript client SDK, inject the token using the
apiKeyconfiguration option:const brain = new SecondBrain({ api: 'http://localhost:3747', apiKey: process.env.BRAIN_KEY // Or pass the token directly });Safe defaults: the server binds to
127.0.0.1, serves no wildcard CORS header, caps request bodies, never returns absolute filesystem paths, and confines note writes and static files to the vault andui/. The dashboard escapes all note text and sanitizes rendered markdown.PII/Secrets Safeguard:
sdk/safeguard.js'ssanitizeContent()is available for any code path (custom endpoints, ingestion pipelines, logging) that wants to redact API keys, DB URLs, PEM keys, JWTs, SSNs, or credit card numbers before persisting or echoing text.
🧩 Optional Capabilities (Graceful Degradation)
Every capability below is additive and opt-in — with none of it configured, the server behaves exactly as a plain zero-dependency TF-IDF/graph memory store, which remains the default.
Capability | Enable by setting | Behavior when unset |
Semantic search arm, dedup similarity gate |
| Semantic arm returns no candidates; search/recall are identical to keyword-only TF-IDF. |
LLM-judged dedup, LLM router calls | Any of | Falls through the provider chain to Ollama; if nothing is reachable, the caller (e.g. the dedup judge) fails open. |
Sandboxed execution via Docker | A running Docker daemon |
|
Auto git sync |
| No-op; nothing is committed or pushed. |
Environment Settings
Variable | Description | Default |
| The port the REST API listens on. |
|
| Address the REST API binds to. Loopback-only by default; set to |
|
| Vault folder (created if missing). |
|
| MCP server only. By default it refuses to use an already-running Second Brain whose vault differs from the one it expects (or that is too old to say), so notes never land in the wrong vault. Set to | unset |
| Allow cross-origin browser access from this origin. Off by default; the bundled dashboard is same-origin and needs nothing. | unset |
| Maximum request body size (413 above it). |
|
|
| unset |
| Optional. If set, every endpoint except |
|
| Optional. If |
|
| Optional. Enables the semantic search/dedup embeddings arm. | unset |
| Optional. Configures the LLM router's provider chain ( | unset / |
| Optional. Overrides the router's fallback priority order. |
|
🛠️ Configuration & Setup
Requirements
Node.js (>= 22.5.0 —
sdk/embeddings.jsuses the built-innode:sqlitemodule, available starting there)Web Browser (for Visualizer UI)
Installation
Clone the repository:
git clone https://github.com/ara-5/mind-mri-agent-second-brain.git
cd mind-mri-agent-second-brainStart Server
# Production start
npm start
# Development watch mode
npm run devLaunch Visualizer UI
npm run ui(Opens the dashboard served by the running API server — run npm start first. The dashboard is same-origin with the API, so no CORS configuration is needed.)
Run Tests
npm testRuns the full node:test suite (test/*.test.js) — no test framework dependency, isolates side effects via temp directories, mocked fetch, and env-var overrides. CI (.github/workflows/ci.yml) runs this across Node 22.x/24.x on every push/PR to main.
Vault Migrations
See migrations/README.md for the one-file-per-migration, idempotent, never-fabricate-data convention, and migrations/001-assign-department-leads.mjs for the first real migration (assigns org-chart leads from unambiguous persona-title keywords).
Available Tools
12 toolsbrain_healthServer healthARead-onlyIdempotent
Check that the Second Brain server is running and get basic vault statistics: status, version, and how many notes (nodeCount) and links (edgeCount) the vault holds. Read-only and cheap. Call it first if another tool fails with a connection error, or to confirm the memory is connected. The server is started automatically on the first tool call, so a healthy answer here means everything is ready.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already establish read-only, idempotent, non-destructive behavior, but the description adds useful context beyond them: it is cheap, the server auto-starts on first use, and a healthy answer confirms readiness. It also lists the returned fields, compensating for the lack of an output 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?
The description is three sentences and front-loads the purpose, then the returned data, then the usage guidance. Every sentence adds useful information without 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 zero-parameter health-check tool with no output schema, the description covers what the tool does, what it returns, when to use it, and what a healthy result means. Nothing critical is missing for correct invocation.
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?
The tool has zero parameters, so the baseline is 4. The description does not need to explain parameter semantics, and the empty schema is fully consistent with a health-check tool.
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 and resource: 'Check that the Second Brain server is running' and get vault statistics. It also names the exact statistics returned (status, version, nodeCount, edgeCount), making clear this is a health/status tool rather than a data operation.
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 explicitly says when to call it: first if another tool fails with a connection error, or to confirm the memory is connected. It also explains that the server starts automatically on the first tool call, so a healthy response means everything is ready.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_messages_getRead an inboxARead-onlyIdempotent
Read the messages addressed to an agent: unread ones by default, or the full history with unread set to false. Read-only: it does not mark anything as read; call brain_messages_mark_read with each message id once handled. All matching messages are returned at once, with no pagination and no guaranteed order. Returns { agent, count, messages: [{ id, title, type, tags, agent, content }] }. count 0 means the inbox is empty.
| Name | Required | Description | Default |
|---|---|---|---|
| agent | Yes | Whose inbox to read, using the name senders used as toAgent (case-insensitive, spaces treated as hyphens). | |
| unread | No | true (default) returns only unread messages; false returns every message including read ones. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint, idempotentHint, destructiveHint false, and openWorldHint false. The description adds meaningful context beyond those annotations: reading does not mark messages as read, all matching messages are returned at once with no pagination or guaranteed order, and a count of 0 means an empty inbox. It does not discuss access permissions, but for a read-only inbox tool the additional behavioral context is substantial.
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?
The description is dense and front-loaded: scope, read-only behavior, follow-up tool, pagination/order caveat, return shape, and empty-inbox meaning. Every sentence carries actionable information without unnecessary wording.
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?
Although there is no output schema, the description provides the full return shape, clarifies that results are unpaginated and unordered, and explains what count 0 means. Combined with the annotations, this is complete enough for an agent to call and interpret the tool 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 both parameters are already documented. The description restates that unread defaults to true and false returns the full history, but adds little parameter-specific meaning beyond the schema; its extra value is in overall return behavior rather than parameter semantics.
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 and resource: read messages addressed to an agent. It immediately clarifies the default unread scope versus full history, which cleanly distinguishes this inbox-reading tool from sibling tools like brain_messages_mark_read and brain_messages_send.
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 explicitly explains when to use the default unread view versus unread=false for full history. It also names the follow-up tool, brain_messages_mark_read, and specifies that reading does not mark messages as read, giving the agent a clear workflow.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_messages_mark_readMark message readAIdempotent
Mark one message as read so it no longer appears in the default (unread) inbox from brain_messages_get. Call it after you have handled a message. Safe to repeat: marking an already-read message again changes nothing. The message stays in the vault and in the full history. Returns { success: true, id }, or an error "Message not found" if the id is unknown or is not a message note.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Message note id exactly as returned in the id field by brain_messages_get, e.g. "messages/qa-agent/[MSG] Question". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint=true and destructiveHint=false, but the description adds substance beyond them: the message stays in the vault and in full history, so the state change is scoped to inbox visibility only. It also discloses the return contract ({ success: true, id }) and the exact error case ('Message not found' for an unknown id or non-message note).
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?
Four short sentences, front-loaded with the effect and followed by the trigger, idempotency guarantee, and return contract. No sentence is filler; each adds a distinct fact an agent needs.
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 one-parameter mutation tool with annotations and no output schema, the description covers trigger, durability of the change, repeat-safety, return shape, and failure mode. Nothing required 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% and the schema already specifies that the id comes from brain_messages_get with an example format, so the description adds no new parameter detail. Baseline 3 applies when the schema carries the parameter semantics.
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 ('Mark one message as read') plus the observable effect: it disappears from the default unread inbox returned by brain_messages_get. That explicit link to the sibling tool lets an agent distinguish it from brain_messages_get or brain_messages_send without opening a 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?
'Call it after you have handled a message' gives a clear trigger condition, which implicitly excludes marking messages as read before processing them. It stops short of naming alternatives or an explicit when-not, but for a single-purpose one-parameter tool the guidance is actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_messages_sendSend a messageA
Send a message to another agent's inbox. The recipient reads it with brain_messages_get and clears it with brain_messages_mark_read. Use it for short hand-off context that does not belong in a task or a permanent note. Nothing is delivered in real time: the recipient has to check its inbox. Any valid name works as a recipient (the inbox is created on first use and unknown names are not rejected), so check the spelling; an invalid name such as one containing a slash is rejected with the reason. Every call creates a new message, so sending the same text twice delivers it twice. Returns { success, id } where id is the message note id.
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes | The message body (markdown). | |
| subject | No | Short subject line. Defaults to "Message from <fromAgent>". | |
| toAgent | Yes | Recipient agent name, e.g. "reviewer". Inbox names are matched case-insensitively with spaces treated as hyphens. No slashes or other filename-invalid characters. | |
| fromAgent | No | Sender name so the recipient knows who wrote. Recorded as "unknown" if omitted. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare write, non-idempotent, non-destructive, closed-world, so the description adds genuinely new behavior: nothing is delivered in real time, unknown recipient names are accepted and silently create a new inbox, malformed names are rejected with a reason, and duplicate sends duplicate the message. It also documents the return shape ({ success, id }) despite no output schema existing. It does not discuss message size limits or retention/deletion of inbox contents, so it is strong but 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?
Sentences are dense and ordered usefully: purpose, consumption path, when-to-use, delivery semantics, recipient-name caveats, duplicate behavior, return value. No filler, though the recipient-name caveat is spread across two sentences that could be merged.
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 four-parameter write tool with no output schema, the description covers everything an agent needs: when to use it, that delivery is asynchronous, that names are unvalidated, that sends are not idempotent, and what the response contains. No significant decision-relevant gap remains.
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; the description still adds practical meaning by framing toAgent as a free-form name that will not be validated against existing agents ('check the spelling') and by explaining the failure mode for invalid characters. It adds little beyond the schema for content, subject, and fromAgent defaults, which the schema already states.
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 opening sentence states a specific verb and resource ('Send a message to another agent's inbox') and immediately ties it to the sibling tools that consume the message (brain_messages_get, brain_messages_mark_read), so the agent can position it in the workflow without opening a 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 an explicit inclusion criterion ('short hand-off context that does not belong in a task or a permanent note'), which implicitly routes task-shaped or durable content to brain_tasks_submit or brain_remember, and it explains the delivery model (recipient must check its inbox) that determines whether this tool is even appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_node_getGet a noteARead-onlyIdempotent
Fetch one note by id: its full markdown content, metadata (type, tags, agent, importance, version, dates), the notes it links to (outLinks) and the notes that link to it (inLinks). Read-only. Use it to read a note in full before replacing its text with brain_node_update, or to follow a link found in recalled context. The whole note is returned, so a very large note is a large response. Returns an error saying "not found" for an unknown id.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Note id exactly as returned by brain_search, brain_recall or brain_remember: the path inside the vault without ".md", e.g. "agents/atlas/Decision - Use SQLite for the cache". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive and closed-world, so the "Read-only" sentence is largely redundant. What the description does add beyond the structured data is real: the warning that a large note produces a large response, and the disclosure that an unknown id yields a "not found" error rather than an empty result.
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?
Four short sentences, front-loaded with the return shape before the usage guidance. Minor waste exists in restating "Read-only" which the annotations already cover, but nothing else 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 must describe return values and it does so field by field, plus adds the error case and the size caveat. For a single-parameter read tool, an agent has everything needed to call it and interpret the result.
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 id property already explains the exact format and its origin from brain_search/brain_recall/brain_remember. The description only says "by id", adding no new meaning beyond what the schema provides, 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?
The description opens with a specific verb and resource ("Fetch one note by id") and immediately enumerates what comes back: markdown content, metadata fields, outLinks and inLinks. An agent can distinguish it from brain_search and brain_recall without opening any schema, since those return collections rather than a single fully-expanded note.
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 two concrete use cases with the alternative named in each: read in full before overwriting via brain_node_update, or follow a link discovered in recalled context (versus brain_recall). The relationship to sibling tools is explicit rather than inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_node_updateUpdate a noteADestructive
Update an existing note in place instead of creating a near-duplicate. mode "append" (default) adds your text to the end and keeps everything already there; mode "replace" overwrites the whole body, so only use it when you have the full corrected text (read it with brain_node_get first). Tags and importance, if given, replace the existing values. Safe against concurrent edits: it checks the note version and retries once if another writer changed it in between. Returns { success: true, id, mode } (mode is omitted when only tags or importance changed). Errors: "not found" for an unknown id, "Nothing to update" if you pass only an id, and a conflict error if two other writers keep racing; in that case read the note again and retry. No credentials are needed from you: if the server was started with BRAIN_KEY, this MCP server sends it automatically.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Note id exactly as returned by brain_search, brain_recall or brain_remember, e.g. "agents/my-project/Decision - Use SQLite". | |
| mode | No | "append" (default) keeps the existing text and adds yours at the end. "replace" overwrites the whole body: read the note first with brain_node_get. | append |
| tags | No | The note's new complete tag list; it replaces the old tags rather than adding to them. | |
| content | No | In append mode, the text to add after the existing body. In replace mode, the complete new body (it overwrites everything, so include whatever you want to keep). Omit to change only tags or importance. | |
| importance | No | New importance, 1 to 10 (see brain_remember). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations, which only flag destructive/non-idempotent/non-read-only. The description spells out exactly what gets destroyed in replace mode, that tags and importance overwrite rather than merge, the optimistic-concurrency check with a single automatic retry, the return shape, three named error conditions, and that no credentials are needed when BRAIN_KEY is set. Nothing here contradicts destructiveHint=true or idempotentHint=false.
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 core distinction (update in place vs. duplicate) and then ordered by decision-relevance: mode semantics, overwrite rules, concurrency, return value, errors. Dense but a few clauses, particularly the credentials sentence, could be trimmed without loss.
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 destructive 5-parameter mutation with no output schema, the description covers everything an agent needs: mode choice, overwrite/merge behavior, concurrency and retry, response shape, error taxonomy with recovery, and auth expectations. No meaningful gap remains for correct invocation.
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; the description adds real value by tying mode to content (append vs. full-body replace), clarifying that tags/importance replace rather than merge, and noting that passing only an id yields "Nothing to update". Most of the per-parameter meaning, however, is already carried by the schema descriptions, so it edges just above baseline rather than redefining semantics.
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?
"Update an existing note in place instead of creating a near-duplicate" states the verb, the resource, and the failure mode it exists to prevent, which cleanly separates it from the sibling brain_remember (create). It also names brain_node_get as the read counterpart, so the agent can place the tool in a workflow without opening a 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?
Explicit routing guidance: default append for adding text, replace only when you have the full corrected body and have read it with brain_node_get first. It also states the alternative (creating a near-duplicate is what this avoids) and the recovery path on conflict (read again and retry).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_recallRecall contextARead-onlyIdempotent
Recall relevant memory for a query from the shared Second Brain vault. It finds the best-matching notes (keyword and recency, plus semantic similarity when embeddings are configured), then follows their [[wikilinks]] outward for the requested number of hops, and packs the result into a token budget. Call this before answering anything that earlier work may already cover: past decisions, constraints, research, project background. Read-only. Returns { nodeCount, tokenEstimate, systemPrompt, nodes }: systemPrompt is a ready-to-use context block in which the notes are marked as reference data, not instructions. Use brain_search instead when you only need a ranked list of matching notes.
| Name | Required | Description | Default |
|---|---|---|---|
| hops | No | How many [[wikilink]] steps to follow from the matching notes. 0 = matches only; 1 (default) adds directly linked notes; values above 3 are capped at 3. | |
| query | Yes | What you need to know, in plain words, e.g. "why did we choose SQLite for the cache". Specific queries recall better than broad ones. | |
| maxTokens | No | Token budget for the returned context. Notes that do not fit are left out. Values above 8000 are capped at 8000. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description goes well beyond them: it discloses the matching strategy, that hop expansion traverses [[wikilinks]], that results are packed under a token budget with overflow dropped, and the full return shape. The note that systemPrompt marks notes as reference data rather than instructions is a meaningful trust-boundary disclosure an agent cannot infer from structured fields.
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 purpose and effect, then usage guidance, then return shape, then the disambiguation sentence. Nearly every clause carries information, though the mechanism clause and the return-value enumeration make it denser than strictly necessary.
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?
No output schema exists, and the description compensates by naming the returned fields and explaining the role of the key one (systemPrompt as a ready-to-use, reference-marked context block). For a three-parameter read tool with a non-obvious retrieval pipeline, 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 coverage is 100%, so the baseline is 3, but the description adds pipeline-level meaning: it explains what hops actually do (follow wikilinks outward from matches) and what maxTokens controls (the packing budget, with omissions when exceeded). It stops short of restating defaults or caps, which the schema already handles.
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 ("Recall relevant memory for a query from the shared Second Brain vault") and then describes the retrieval pipeline: keyword/recency matching, optional semantic similarity, wikilink expansion, token packing. It explicitly names the sibling it is not (brain_search) and the condition that distinguishes 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 an explicit trigger ("Call this before answering anything that earlier work may already cover: past decisions, constraints, research, project background") plus a named alternative and the exact condition for choosing it ("Use brain_search instead when you only need a ranked list of matching notes"). Both when-to-use and when-to-use-something-else are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_rememberSave a memoryA
Write a new memory/research note into the shared Second Brain vault so future sessions, in this or any other project, can recall it later. Only for a genuine, reusable learning: a fact, pattern, constraint or decision that would change future behavior or save someone from re-deriving it. Not for routine task completions, raw output or status updates (the task queue records those). Test: would a future session be worse off without this note? If not, skip it. Prefer updating an existing relevant note over creating a near-duplicate one (use brain_search first, then brain_node_update). Creates a new note and never overwrites an existing one (a title clash gets a numbered filename). Returns { success, id, title, type, version }; keep the id to refer to the note later.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Short lowercase labels, e.g. ["database", "cache"]. Used by search and filtering. | |
| type | No | Kind of note: decision (a choice and its reason), insight (a non-obvious finding or fix), research (gathered findings), memory (general fact), note (anything else). | memory |
| agent | No | Name of the calling project or agent; the note is stored under agents/<agent>/, which keeps each project's notes together. Same filename rules as title, so no slashes. If omitted, the note is stored at the vault root and its agent is recorded as "unknown". | |
| title | Yes | Specific, searchable title that becomes the note's filename, e.g. "Decision - Use SQLite for the cache". Must not contain : / \ ? * " < > | , start or end with a space, or end with a period; invalid titles are rejected with the reason. | |
| content | Yes | Markdown body. Link related notes with [[Note Title]] so recall can follow the graph. Never include secrets, credentials or personal data: notes are plain files and may be synced to git. | |
| importance | No | How long the note stays prominent in recall, 1 to 10. Recency only re-ranks, so old notes are never hidden, but 8-10 fades over months, 5-7 (default) over weeks, and 1-4 within days. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare a non-read-only, non-destructive, non-idempotent mutation; the description adds real value on top by confirming it never overwrites (title clashes get a numbered filename), disclosing the return shape { success, id, title, type, version }, and warning that notes are plain files that may be synced to git so secrets must be excluded. The only minor gap is that it does not mention any permission or auth requirement before writing.
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?
Purpose is front-loaded in the first sentence, then gating criteria, then the alternative-path instruction, then behavioral/return details. The length is justified by the amount of decision-relevant content and the "Test:" framing keeps the qualification crisp rather than rambling.
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?
A mutation tool with no output schema, yet the description compensates by stating the exact return fields and advising the agent to retain the id for later reference. Combined with the no-overwrite behavior, the duplicate-avoidance workflow, and the secrets warning, an agent has everything needed to call 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 coverage is 100%, so tags, type, agent, title, content and importance are all fully documented in the schema already, which sets the baseline at 3. The description adds only marginal parameter meaning — that a title clash yields a numbered filename — and does not explain importance or type trade-offs beyond what the schema states.
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 ("Write a new memory/research note into the shared Second Brain vault") plus the downstream purpose (recall in future sessions or other projects). It distinguishes itself from siblings by naming brain_search and brain_node_update as the preferred path for existing 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?
Gives explicit inclusion criteria (genuine reusable learning: fact, pattern, constraint, decision), explicit exclusions (routine task completions, raw output, status updates — pointing at the task queue), and a concrete self-test question. It also routes to alternatives: search first, then update an existing note rather than duplicating.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_searchSearch notesARead-onlyIdempotent
Search the vault for notes matching a query: keyword search over titles, tags and content, combined with semantic similarity when embeddings are configured, then lightly re-ranked by recency. Use it to check whether a note already exists (before brain_remember) or to find a note id for brain_node_get / brain_node_update. Read-only. Returns { query, results: [{ id, title, type, tags, agent, score, preview }] }, best first; an empty list means nothing matched. Use brain_recall instead when you want assembled context to answer a question.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of results to return (default 10). | |
| query | Yes | Words to look for, e.g. "sqlite cache decision". Matches titles, tags and note text. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantive behavior beyond the readOnly/idempotent annotations: hybrid keyword+semantic matching, recency re-ranking, and that an empty list means no match. "Read-only" merely repeats the annotation, and ordering/pagination behavior under the limit is not elaborated, so it stops short of 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?
Front-loads the search mechanism, then routing, then return shape in a logical order with no filler. The standalone "Read-only." sentence duplicates the annotations and could be dropped, which keeps it from a 5.
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, and the description compensates by spelling out the returned object shape and the meaning of an empty result. Combined with explicit routing to siblings, an agent has everything needed to call and interpret this 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 description coverage is 100%, so both parameters are already documented. The description only reinforces that the query matches titles, tags, and content, and adds no syntax or format detail for limit beyond the default already in the schema.
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 ("Search the vault for notes") plus the exact matching mechanism (keyword over titles/tags/content, semantic similarity when embeddings are configured, recency re-ranking). It distinguishes itself from brain_recall, brain_remember and brain_node_get, which are named directly.
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 explicit when-to-use cases (check for an existing note before brain_remember, obtain a note id for brain_node_get / brain_node_update) and names the alternative brain_recall with the condition that selects it (assembled context to answer a question).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_tasks_listList tasksARead-onlyIdempotent
List the tasks in the shared queue, optionally only those in one state. Use status "pending" to find work waiting for you, "blocked" to see what is waiting on dependencies. Read-only. Returns every matching task with no pagination and no guaranteed order: { count, tasks: [{ id, title, tags, content, createdAt }] }, where content holds the prompt and any result written so far, and id is what brain_tasks_update takes. An empty list means no tasks match. Add tasks with brain_tasks_submit; change the state of a task, or record its outcome, with brain_tasks_update.
| Name | Required | Description | Default |
|---|---|---|---|
| status | No | Only return tasks in this state. Omit to list all tasks. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds what they cannot say: no pagination, no guaranteed order, an empty list means no matches, and 'content' holds the prompt and any partial result. That is behavior an agent needs and cannot get from structured fields.
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?
Scope and filter come first, then return shape, then sibling routing. Every sentence carries distinct information and nothing is repeated from the schema verbatim.
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 available, the description supplies the response shape inline (count, tasks with id/title/tags/content/createdAt) and clarifies that 'id' is the key brain_tasks_update expects, leaving no call-shaping ambiguity.
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 baseline is 3, but the description adds real meaning by explaining what the 'pending' and 'blocked' enum values imply for the caller's workflow rather than just restating the enum.
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 ('List the tasks in the shared queue') plus an optional filter, and explicitly separates itself from brain_tasks_submit and brain_tasks_update by function.
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 guidance tied to filter values ('pending' to find work waiting for you, 'blocked' to see what is waiting on dependencies) and points to the sibling tools for adding tasks or changing state.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_tasks_submitSubmit a taskA
Add a task to the shared, markdown-backed task queue so another agent (or a later session) can pick it up. A task with dependencies starts as "blocked" and moves to "pending" automatically when all of them complete; otherwise it starts as "pending". This only records the task: it is a coordination list, not a runner, so something else must watch for pending tasks (brain_tasks_list) and report back (brain_tasks_update). Returns { taskId, nodeId, status } where status is "pending" or "blocked". Write the prompt so it is self-contained: goal, relevant files, constraints and what "done" means.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | Short title. If omitted, one is made from the first 60 characters of the prompt, prefixed "Task - ". | |
| agents | No | Names of the agents this task is for, e.g. ["reviewer"]. Defaults to ["coordinator"]. | |
| prompt | Yes | Complete, self-contained description of the work to be done. | |
| priority | No | Urgency, 1 (lowest) to 10 (highest). | |
| dependencies | No | Node ids (nodeId values returned by earlier brain_tasks_submit calls) that must complete first. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare the mutation profile (readOnly=false, destructive=false, idempotent=false, openWorld=false), so the description is not required to restate safety, but it does add real behavior: dependency-driven initial status, automatic transition from blocked to pending, and a concrete return shape { taskId, nodeId, status } in the absence of an output schema. It stops short of stating whether duplicate submissions create duplicates, which is the one behavior an agent still has to guess given idempotentHint=false.
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?
Four sentences, each doing distinct work: purpose, status lifecycle, the not-a-runner constraint with named alternatives, and the return value plus prompt-authoring advice. The scoping constraint is front-loaded and nothing is redundant.
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 create tool with no output schema, the description covers the mutation's effect, the status lifecycle, the return shape, and the division of labor with sibling tools. An agent has everything needed to submit a well-formed task and to know what to do next.
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 schema already documents all five parameters and a baseline of 3 applies. The description adds meaning beyond it by telling the agent how to compose the required prompt (goal, relevant files, constraints, definition of done) and by framing dependencies as nodeId values from earlier submits, which reinforces the schema rather than merely repeating it.
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 opens with a specific verb and resource ("Add a task to the shared, markdown-backed task queue") and immediately names the purpose (another agent or later session can pick it up). It explicitly distinguishes itself from the sibling tools brain_tasks_list and brain_tasks_update, so an agent can separate recording from watching and reporting.
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 states the key boundary explicitly: "This only records the task: it is a coordination list, not a runner," and names what must handle the rest (brain_tasks_list to watch, brain_tasks_update to report back). It also gives authoring guidance for the required prompt field, so the when and how are both covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
brain_tasks_updateUpdate a taskAIdempotent
Change the status of a task and, optionally, record its outcome. Use it to claim a task ("running"), finish it ("completed" or "failed") or withdraw it ("cancelled"). Completing a task releases the tasks that were blocked on it: once all the dependencies of a blocked task are completed it becomes "pending"; if a dependency failed or was cancelled, the dependent task is marked "failed" too. The result text is written to the Final Result section of the task, replacing any earlier result; the prompt and sub-results are kept. Setting the same status again is harmless. Returns { success, id, status, releasedDependents } where releasedDependents counts the blocked tasks that moved. Errors: "Task not found" for an id that is not a task note. Find ids with brain_tasks_list; create tasks with brain_tasks_submit.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Task note id: the id field from brain_tasks_list, or the nodeId returned by brain_tasks_submit, e.g. "tasks/Task - Review the migration". | |
| result | No | What was done or why it failed, in markdown. Stored in the Final Result section of the task. Omit to change only the status. | |
| status | Yes | The new state. Use "running" when you start, "completed" or "failed" when you finish. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, it discloses the dependency cascade (dependents become "pending" on completion, "failed" if a dependency failed or was cancelled), that the result text replaces any earlier result while prompt and sub-results are kept, and the exact error string for an unknown id. It also confirms idempotency, consistent with idempotentHint=true. The only slight gap is that it doesn't discuss authorization or concurrency, which are likely non-issues here.
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?
The core action and status intents are front-loaded, followed by side effects, return shape, errors, and sibling routing in a logical order. Every sentence carries information, though the dependency-cascade sentence is dense enough that a slight trim would improve scanability.
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?
Even without an output schema, the description specifies the return fields ({ success, id, status, releasedDependents }) and their meaning, plus the failure mode. For a three-parameter mutation tool this leaves nothing important unexplained.
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 adds real meaning beyond the schema: it explains that `result` overwrites the Final Result section while preserving the prompt and sub-results, and that omitting it changes status only. The status enum is also given intent-level semantics rather than left as a bare list.
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 opens with a specific verb and resource ("Change the status of a task and, optionally, record its outcome") and enumerates the concrete transitions it performs. It is clearly separable from siblings, which are named for their distinct roles (brain_tasks_list for ids, brain_tasks_submit for creation).
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 states exactly which status value corresponds to which intent ("running" to claim, "completed"/"failed" to finish, "cancelled" to withdraw) and routes the agent to brain_tasks_list for ids and brain_tasks_submit for creation. There is no ambiguity about when this tool is the right choice.
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 tool update
v1.7.0- Added
brain_tasks_update
11 tool updates
v1.6.1- First observed
brain_health - First observed
brain_messages_get - First observed
brain_messages_mark_read - First observed
brain_messages_send - First observed
brain_node_get - First observed
brain_node_update - First observed
brain_recall - First observed
brain_remember - First observed
brain_search - First observed
brain_tasks_list - First observed
brain_tasks_submit
TDQS
Scored across 12 tools
Each tool targets a distinct resource plus action: notes (remember/search/node_get/node_update/recall), the task queue (submit/list/update), messaging (send/get/mark_read), and health. The only naturally confusable pair, brain_search vs brain_recall, is explicitly separated in the descriptions (ranked note list vs assembled context block within a token budget), and remember vs update is likewise clarified. No two tools appear to do the same thing.
All names are snake_case under a uniform `brain_` prefix, and most follow a resource-then-verb form (brain_tasks_submit, brain_messages_mark_read). Minor deviations exist: bare verbs (brain_remember, brain_search, brain_recall, brain_health) and a singular/plural resource split (brain_node_get vs brain_tasks_list). Readable and predictable overall, but not a single rigid pattern.
Twelve tools is well inside the healthy range and each one maps to a real operation across the three sub-domains (memory, task queue, messaging). Nothing looks like filler, and the surface is small enough that an agent can enumerate it easily.
The memory lifecycle (create, read, update, search, recall) and the task-queue and inbox lifecycles are covered end to end, including dependency release on completion. Gaps remain: no way to delete or archive a note or message, and no single-task fetch (you must list and filter), though status changes via brain_tasks_update give a partial workaround.
Maintenance
Related MCP Connectors
Token-efficient MCP memory for Markdown vaults. Tiered search, GraphRAG, AI memories.
Persistent memory, knowledge graph, task management and more for AI agents via MCP.
Persistent, portable memory for AI assistants — your private memory graph, from any MCP client.
Hosted memory for AI agents over MCP. One memory shared by all your agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceLocal-first knowledge backend for AI agents that connects MCP hosts to an Obsidian-compatible vault with indexed retrieval, token-budgeted memory recall, and secure ingestion.1MIT
- AlicenseNot gradedqualityDmaintenanceEnables LLM assistants and agents to query and manage a personal markdown vault as a graph-based knowledge base using hybrid retrieval, with tools for searching, editing, tagging, and recalling memories across MCP-compatible clients.30 PyPI4MIT
- AlicenseAqualityBmaintenanceProvides a shared, persistent memory layer for AI assistants, letting them read and write to a local Obsidian vault through MCP with validation, secret rejection, and deduplication.8Apache 2.0
- FlicenseNot gradedqualityBmaintenanceServes as a unified MCP gateway to an Obsidian vault, enabling AI agents to perform hybrid lexical/vectorial semantic search, explore note graphs, and write through consent-based intent batches with conflict detection.-