Skip to main content
Glama

mcp-ragdown

Website: cubicecho.github.io/mcp-ragdown: an overview, a walkthrough and a condensed reference.

An MCP server over folders of Markdown files. Point it at a directory and it embeds every section into a local LanceDB index and keeps that index in sync as files change. Each top-level folder is its own MCP server, off until you turn it on, and each one opens as an Obsidian vault. Agents get search tools, and a hook that calls ragdown_context before each turn adds related notes to the prompt. The tool layout follows mcp-zeromem, but the memory here is your Markdown files, not conversation turns.

Everything an agent or a hook does goes through MCP. There is no hook command and no hook HTTP route; the only other routes feed the web UI.

Everything runs locally: the default embedder is granite-embedding-small-english-r2 on ONNX Runtime. The Docker image has the model baked in; outside Docker it is downloaded once (about 50 MB) on first start. Two others are a setting away — see Choosing an embedder.

Quick start

docker-compose.yml:

services:
  ragdown:
    image: vantreeseba/mcp-ragdown:latest
    ports:
      - '3300:3000'
    volumes:
      - ~/notes:/docs          # one folder per directory in here; add :ro and RAGDOWN_READ_ONLY=true to forbid writes
      - ragdown-data:/data     # the index, so restarts only diff
    environment:
      RAGDOWN_TOKEN: ${RAGDOWN_TOKEN}
    restart: unless-stopped

volumes:
  ragdown-data:
export RAGDOWN_TOKEN=$(openssl rand -hex 32)   # keep it; clients need it too
docker compose up -d
curl localhost:3300/api/status                  # "ready": true, and the file and chunk counts

~/notes/work is now the folder work. It starts human-only: open http://localhost:3300, turn MCP on for it under Settings → Folders (or put { "mcp": true } in ~/notes/work/.ragdown.json), and Copy MCP config there gives you this line:

claude mcp add --transport http ragdown-work http://localhost:3300/mcp/work \
  --header "Authorization: Bearer $RAGDOWN_TOKEN"

The first index of a large folder takes minutes; searches answer from what is indexed so far. The web UI lists each folder's files, renders them with their wikilinks and images, and searches them. To add notes to every turn automatically, see Hooks in min-agent. Images are published for linux/amd64 to Docker Hub and ghcr.io/cubicecho/mcp-ragdown.

Without Docker

npm install
RAGDOWN_DOCS_DIR=~/notes node src/cli.ts stdio                        # what an MCP client launches
RAGDOWN_DOCS_DIR=~/notes SECURE_LOCAL_NET=true node src/cli.ts serve  # HTTP and the web UI on :3000

Requires Node 26+, which runs the TypeScript directly.

Related MCP server: Knowledge MCP Server

Claude Code setup

Against the container, the claude mcp add --transport http line above. As a local process:

claude mcp add ragdown -e RAGDOWN_DOCS_DIR=$HOME/notes/work -- node /path/to/mcp-ragdown/src/cli.ts stdio

stdio serves one folder: RAGDOWN_DOCS_DIR itself, whatever its .ragdown.json says (you chose it by launching it). Point it at an Obsidian vault and the whole vault is the folder.

Claude calls ragdown_recall and ragdown_read_doc itself when the notes might help; the server's instructions tell it to. There is no hook command to wire into Claude Code: automatic per-prompt context needs a client whose hooks call MCP tools, such as min-agent.

Folders

serve treats every top-level directory of RAGDOWN_DOCS_DIR as a folder, found as it appears; the directories inside one are subfolders. All folders share one index, one model and one watcher, but each is its own MCP server at /mcp/<folder>, named ragdown-<folder>, and sees only its own notes: paths in and out are relative to it (backups.md, not work/backups.md), and ragdown_read_doc refuses one that leaves it.

A folder's settings live in .ragdown.json at its root, and the web UI edits them:

{ "title": "Work notes", "mcp": true, "hook": { "top_k": 6, "min_score": 0.75 } }
  • title is shown in the web UI and the server's instructions; it defaults to the directory name.

  • mcp defaults to false. A folder is human-only until someone turns it on: indexed and searchable in the web UI, but no endpoint, no recall hits and no hook context. /mcp/<folder> answers a human-only folder with the same 404 as a missing one.

  • hook holds the folder's own ragdown_context defaults: any of top_k, min_score, min_ratio and max_chars. One it leaves out is the server's RAGDOWN_HOOK_* value, and an argument on the call still wins over both. It is read on each call, so an edit applies without a restart.

There is no endpoint over every folder: bare /mcp is a 404 that says to pick one. Markdown loose in RAGDOWN_DOCS_DIR, outside every folder, is not indexed; the log and the web UI list it.

The web UI creates, edits, renames and deletes folders, and Copy MCP config on each one gives the claude mcp add line and the JSON mcpServers entry for it. Under RAGDOWN_READ_ONLY a folder's title, MCP switch and search defaults can still change — they are settings, not notes — but creating, renaming and deleting cannot.

New note (the + beside Upload in a folder's list, or the button in an empty folder) asks for a title and an optional subfolder, created if missing. It starts beside the open note, writes # <title> to <subfolder>/<title>.md, and opens it in the editor. A name that is already taken offers to open that note instead.

Edit on an open note swaps the preview for a Markdown source editor (CodeMirror, loaded on first use), with a Write/Preview switch and Ctrl/Cmd+S to save. It edits the source, not rich text, so wikilinks, embeds and front matter come back exactly as written. A save is made against the version that was opened: if the file changed on disk meanwhile — in Obsidian, by an agent, by git pull — the editor says so and asks whether to save over it or discard the edit, rather than quietly losing either. Leaving with unsaved changes asks first.

A folder keeps an agent focused, not out: one token opens every folder with MCP on.

Subfolders

/mcp/<folder>/<subfolder...> narrows a folder's server to a subfolder, following the folder's MCP setting:

claude mcp add --transport http work-alpha http://localhost:3300/mcp/work/projects/alpha \
  --header "Authorization: Bearer $RAGDOWN_TOKEN"
  • ragdown_recall and ragdown_context search only files under it, and path_prefix narrows further inside it. Paths are relative to the subfolder.

  • ragdown_remember writes into the subfolder itself; on a folder's own endpoint it writes into <folder>/<RAGDOWN_NOTES_DIR>.

  • ragdown_stats counts the subfolder's files and chunks, and ragdown_context's per-session memory is kept separately for each endpoint.

  • ragdown_reindex still syncs everything.

A missing subfolder, a file, a symlink or a dot-folder is a 404.

Obsidian

Open a folder as an Obsidian vault and both see the same notes:

  • .obsidian/, .trash/ and every other dot-folder are skipped, as is .ragdown.json.

  • Tags from frontmatter (tags: [a, b] or tags: a, b) and inline #tags in the text (not in code) are indexed per note. ragdown_recall's tag filter matches a tag and the tags nested under it: project finds #project/alpha. Every hit lists its note's tags.

  • Aliases from frontmatter are found by keyword search and by wikilinks.

  • Wikilinks. ragdown_read_doc takes a link target as well as a path — Note, Note#Heading, sub/Note, an alias — and resolves it the way Obsidian does, within the folder: an exact path, then a note whose name matches (the one beside the linking note, then the shortest path), then an alias. A heading narrows the text to that section. The web UI follows [[links]], shows ![[embeds]] and images, lists the notes that link to the open one, completes [[ in the editor with the folder's notes, and rewrites the links to a note when it is renamed or moved.

Tags and aliases get their own columns; they are not added to the text that is embedded, which was measured and made retrieval worse.

Hooks in min-agent

A min-agent hook calls a tool on a connected MCP server, so ragdown needs nothing beyond its MCP endpoint. Add a server under Settings → MCP:

{
  "id": "ragdown",
  "label": "Notes",
  "transport": "http",
  "url": "http://localhost:3300/mcp/work",   // a folder with MCP on
  // Stored as-is: min-agent does not expand env vars. Leave empty with SECURE_LOCAL_NET=true.
  "headers": { "Authorization": "Bearer <RAGDOWN_TOKEN>" },
  // The model has ragdown_recall; the context tool is for the hook only.
  "hiddenTools": ["ragdown_context"],
  "hooks": [
    { "id": "notes", "on": "beforeTurn", "tool": "ragdown_context", "inject": true, "maxTokens": 800,
      "args": { "prompt": "{{prompt}}", "session_id": "min-agent:{{session.id}}", "max_chars": 3000 } }
  ]
}

Before each turn the hook sends the user's message. ragdown_context answers with the sections whose cosine similarity reaches RAGDOWN_HOOK_MIN_SCORE, wrapped in <ragdown-context>, or with empty text, which min-agent treats as nothing to add. It skips:

  • prompts under 12 characters and slash commands;

  • sections it already returned for the same session_id, so a long chat pays for each note once.

max_chars of 3,000 keeps the block near min-agent's 800-token cap, so a section is not cut in the middle. A hook that fails or takes longer than min-agent's 3 seconds only loses that turn's notes.

Tools

Tool

What it does

ragdown_context

For hooks: the sections related to a prompt as a <ragdown-context> block, or empty text. Filters by similarity, skips short prompts and slash commands, and never repeats a section for the same session_id. Takes top_k, min_score, min_ratio and max_chars to override the folder's hook settings and the RAGDOWN_HOOK_* defaults.

ragdown_recall

Hybrid search. Returns path, line range, heading breadcrumb, tags and similarity for each hit. Takes top_k, path_prefix, tag, format: text|json and max_chars.

ragdown_read_doc

Reads a file, or a line range of one, straight from disk. Never clipped. Also takes a wikilink target (Note#Heading); see Obsidian. Returns the whole file's hash, for ragdown_edit, and superseded_by when another note replaces it.

ragdown_backlinks

The notes that link to a path — by wikilink, alias or relative Markdown link — with the lines the links are on. Links in code are not links.

ragdown_list

Browses rather than searches: each note's path, title, tags, last change, and superseded_by if it has been replaced. Takes path_prefix, tag, sort: path|recent and limit.

ragdown_stats

Folder, index size, embedder, role (primary or reader), whether a sync is running, and the last sync.

ragdown_remember

Writes a new note (with frontmatter) under RAGDOWN_NOTES_DIR and indexes it before returning. Never overwrites a file. supersedes lists the notes this one replaces, which search then skips; session_id is recorded as provenance.

ragdown_edit

Changes a note at a path, or creates one. text replaces the whole file, which for an existing note needs base_hash — the hash ragdown_read_doc gave — so an agent never overwrites a version it has not read. append: true adds text at the end instead, or with heading at the end of that section. A file that changed since base_hash is not written.

ragdown_reindex

Syncs now; full: true re-embeds everything.

The write tools (ragdown_remember, ragdown_edit, ragdown_reindex) are not listed when RAGDOWN_READ_ONLY=true.

Configuration

Only RAGDOWN_DOCS_DIR is required. See .env.example.

Variable

Default

RAGDOWN_DOCS_DIR

—

For serve, the directory holding the folders; for stdio, the one folder. Walked recursively. Dot-folders and node_modules are skipped, and symlinks are not followed. Indexes .md, .markdown and .mdx.

RAGDOWN_DATA_DIR

~/.cache/ragdown/<hash of docs dir>

The index. Deleting it only costs a rebuild. serve and stdio on the same directory keep separate ones.

RAGDOWN_MODELS

~/.cache/ragdown/models

Model cache, shared by every folder.

RAGDOWN_EMBEDDER

granite-small

A local model — granite-small, bge-small or embeddinggemma — or openai:<model> (any OpenAI-compatible /embeddings endpoint, such as Ollama or llama.cpp), or hash (tests only). See Choosing an embedder.

RAGDOWN_EMBEDDING_URL / _API_KEY

OpenAI

For openai:<model>.

RAGDOWN_THREADS

half the cores

ONNX Runtime threads for the local model.

RAGDOWN_WATCH

true

Watch the folder; without a watcher, sync on start and on ragdown_reindex only.

RAGDOWN_READ_ONLY

false

Hide the write tools, and refuse uploads, deletes and folder changes other than settings.

RAGDOWN_NOTES_DIR

notes

Where ragdown_remember writes, relative to each folder (a subfolder endpoint writes into the subfolder). A relative path inside the folder, not a dot-folder.

RAGDOWN_TEXT_LIMIT

2000

Characters per hit in text output. Every cut names the ragdown_read_doc call that returns the rest.

RAGDOWN_HOOK_TOP_K

4

ragdown_context: most sections per prompt.

RAGDOWN_HOOK_MIN_SCORE

0.8

ragdown_context: lowest cosine similarity returned. Calibrated for the default embedder; another one needs another number.

RAGDOWN_HOOK_MIN_RATIO

0.95

ragdown_context: lowest share of the best hit's similarity a hit may have and still be injected; 0 disables it. Being a ratio, it carries across embedders as MIN_SCORE does not. See Design.

RAGDOWN_HOOK_MAX_CHARS

6000

ragdown_context: most characters per prompt.

PORT

3000

serve only. The HTTP port.

HTTP_KEEP_ALIVE_TIMEOUT_MS

75000

serve only. How long an idle client connection is kept open. Above the 60 s nginx and ALB hold theirs; raise it behind a proxy that holds longer. 0 never closes one.

RAGDOWN_TOKEN

—

serve only. The bearer token /mcp/<folder> and the web UI's /api routes require.

SECURE_LOCAL_NET

false

serve only. Skip the token on a trusted network. serve refuses to start with neither.

Commands and HTTP

node src/cli.ts <command>: stdio (the MCP server a client launches) or serve (HTTP, what the image runs). Searching, indexing and stats are MCP tools, not commands.

serve exposes these routes:

Route

Auth

GET /api/status

none

Liveness and index stats. ready: false while the model loads. settings holds the non-secret tuning values (RAGDOWN_WATCH, RAGDOWN_TEXT_LIMIT, RAGDOWN_HOOK_*) for the web UI's Settings page.

/mcp/<folder>[/<subfolder...>]

bearer

Streamable HTTP MCP, stateless, for a folder with MCP on. 404 otherwise, and for bare /mcp. See Folders.

GET /api/folders

bearer

Each folder's name, title, mcp, mcp_path, files and chunks, and loose_files: the Markdown outside every folder.

POST /api/folders

bearer

Create a folder: JSON { name, title?, mcp? }. 201; 409 when it exists, 400 for a bad name.

PATCH /api/folders/<name>

bearer

JSON { title?, mcp?, hook?, name? }: change its settings, or rename it with name (which re-indexes it). hook takes any of top_k, min_score, min_ratio and max_chars; null takes the folder's own value away. Unknown keys in .ragdown.json are kept.

DELETE /api/folders/<name>?confirm=<name>

bearer

Delete a folder and everything in it. 400 unless confirm repeats the name.

GET /api/docs?folder=

bearer

The indexed files, of one folder or all: path, folder, title, tags, aliases, superseded_by, mtime_ms, size, chunks.

GET /api/doc?path=

bearer

One indexed file's text, read from disk, with its tags, aliases and hash (SHA-256 of the bytes on disk). 404 for a file the index does not hold.

POST /api/doc

bearer

Upload a file: JSON { path, text, overwrite? }, body up to 4 MiB. Only .md, .markdown or .mdx inside an existing folder, somewhere the indexer reads (no .., dot-folders, node_modules or symlinked folders); subfolders are created. 201 when created, 200 when overwritten, 409 for an existing file without overwrite: true. An edit sends base_hash, the hash it was opened at, in place of overwrite: 409 with code: "changed" if the file has changed or gone since. Saved over a CRLF file, the text keeps CRLF. The answer carries the new hash.

DELETE /api/doc?path=

bearer

Delete a Markdown file. 404 when it is not there.

GET /api/search?folder=&q=&tag=&top_k=

bearer

Hybrid search in one folder, human-only ones included. top_k defaults to 10, at most 50.

GET /api/resolve?from=&link=

bearer

A wikilink target, resolved from the note from within its folder: { path, anchor? } or 404.

POST /api/move

bearer

{ from, to }: rename or move a note within its folder. Every link in the folder that pointed at it — wikilinks and relative Markdown links, its own included — is rewritten to follow it, with the shortest target that still resolves. Answers with the notes it updated.

GET /api/backlinks?path=

bearer

The notes in the same folder that link to path, with the linking lines. The UI shows them under the preview.

GET /api/file?path=

bearer

Any file inside a folder — an image, a PDF — as raw bytes, sandboxed and nosniff. Never a dot-path or a symlink out.

GET /*

none

The web UI from web/dist, with index.html for any other path.

Every path in /api includes the folder: work/notes/a.md. Writes answer after the index has synced, so the next GET /api/docs already shows them, and uploads, deletes, and creating, renaming or deleting a folder are a 403 under RAGDOWN_READ_ONLY. They are for the web UI; agents write with ragdown_remember and ragdown_edit.

The web UI asks for the token once and keeps it in the browser's local storage. Its static files hold no notes, so they need none; everything it shows comes from the bearer routes. It is built by npm run build (the image does this) and only serve serves it.

Upgrading from 4.x

5.0 splits the docs directory into folders, and nothing is migrated for you:

  1. Move loose Markdown into a folder. Files directly in RAGDOWN_DOCS_DIR are no longer indexed by serve; the log and the web UI list them.

  2. Turn MCP on for each folder agents should reach, under Settings → Folders or with "mcp": true in its .ragdown.json. Every folder starts human-only.

  3. Point clients at /mcp/<folder>. /mcp no longer serves anything. A 4.x scope URL /mcp/<folder>/<sub> keeps working once <folder> has MCP on.

  4. RAGDOWN_NOTES_DIR is relative to each folder: notes now means <folder>/notes.

stdio is unchanged in use: it serves RAGDOWN_DOCS_DIR as one folder. Both modes rebuild their index once on first start, for the new tag and alias columns.

Design

Chunks follow headings. Every heading starts a section, and the section's breadcrumb (Backups › Restore) is part of what gets embedded. That is how a paragraph that only says "run it twice" is found by a question about restoring backups. A section longer than 1,500 characters (about 400 tokens, inside the window of every embedder here) is packed paragraph by paragraph. Fenced code blocks are never split. Line numbers refer to the original file, so a hit is always one ragdown_read_doc call away from its surroundings.

Hybrid retrieval. Dense cosine search finds a paragraph that answers the question in different words. BM25 full-text search finds an exact error string or flag name that an embedding blurs. Both read the chunk with its breadcrumb in front, so a table of settings is still findable by the name of the service its heading names and never repeats. Indexing the body alone cost 22 points of top-1 recall on a benchmark of 210 questions, and left the fused ranking below dense search on its own. Both return a pool, and reciprocal rank fusion (k = 60) merges them. Ranking uses the fused score. Filtering uses cosine similarity, because a fused score is not comparable across queries.

Choosing an embedder. RAGDOWN_EMBEDDER picks one of three local models. They were measured on the same benchmark — 30 generated runbooks, 210 questions with a known answering section, identical chunks throughout — so only the model differs. Top-1 is how often the right section ranked first; the timings are one 8-thread laptop CPU indexing that corpus and embedding one query.

RAGDOWN_EMBEDDER

Model

Dim

Top-1

Recall@5

Index

Per query

MIN_SCORE

granite-small (default)

granite-embedding-small-english-r2

384

85.7%

100%

3.6 s

9 ms

0.8

bge-small

bge-small-en-v1.5

384

82.9%

100%

3.5 s

9 ms

0.7

embeddinggemma

embeddinggemma-300m

768

91.0%

100%

33 s

260 ms

0.6

granite-small is the default because it costs what bge-small costs — same dimensions, same index, 9 ms a query — and was ahead of it on every measure here, though on 210 questions that gap alone is not significant (p = 0.41). embeddinggemma is a real jump and a significant one (p < 0.001), but 260 ms is paid on every search, and a hook searches every turn. Being the default is also why granite-small is the model baked into the Docker image; the other two download on first start. gte-small, snowflake-arctic-embed-s, mxbai-embed-xsmall, bge-base, granite's 149M model and arctic-embed-m were measured too and beat the default on nothing — bigger was not better.

Changing the model rebuilds the index, and RAGDOWN_HOOK_MIN_SCORE has to move with it. Cosine is on each model's own scale, not a shared one. On the same corpus, the weakest on-topic question and the strongest unrelated prompt ("weather in Paris", "a recipe for carbonara") scored:

on-topic (10th percentile)

unrelated (worst case)

granite-small

0.86

0.75

bge-small

0.70

0.60

embeddinggemma

0.68

0.53

The last column of the table above is the value that separates the two for each model. Borrow another model's number and the hook either injects a pasta recipe into every prompt or drops the notes that answer the question.

A second, relative gate under that one. RAGDOWN_HOOK_MIN_RATIO drops a hit scoring less than 0.95 of the best hit for the same prompt, whatever MIN_SCORE let through. An absolute floor answers "is this on topic at all"; the ratio answers "is this as on topic as the thing I already found", and a chunk far below the best one is a distractor that costs accuracy, not just tokens. Being a ratio it also survives a change of embedder, which MIN_SCORE does not. On the same benchmark (granite-small, min_score 0.8, top_k 4, 210 questions plus 10 unrelated prompts):

ratio

recall

chunks/prompt

off-topic chunks

1.00

84.3%

1.00

0.16

0.98

94.8%

1.62

0.67

0.96

99.0%

2.67

1.68

0.95 (default)

99.0%

3.17

2.18

0 (off)

99.0%

3.99

3.00

Recall is flat from 0.96 down, so the default sits one step below the knee rather than on it: 0.95 keeps everything an ungated hook found while still cutting a fifth of the injected chunks.

Superseding a note. A note whose frontmatter lists supersedes: hides the notes it names from search and from hook context. Nothing is deleted or rewritten — the old file stays on disk and ragdown_read_doc still opens it, saying which note replaced it (superseded_by), and the web UI marks it superseded and links to the replacement. But a fact that changed stops coming back as confident prose next to its replacement.

---
title: "Embedder"
date: 2026-09-15
supersedes: ["2025-04-02-embedder.md"]
created_by: ragdown_remember
---

Paths are relative to the note's own folder, the way a Markdown link is, and one that climbs out of the docs folder is ignored: frontmatter is data from a file, not a path the server should follow. ragdown_remember writes the field for you from its supersedes argument and refuses a path that names no note, so an agent that gets it wrong hears about it instead of believing it replaced something. It also records created_by: ragdown_remember and the session_id, so a later reader — person or model — can tell an agent's note from one the user wrote.

The index is derived data. meta.json records the embedder and chunker version, and a mismatch drops and rebuilds the index instead of migrating it. Syncs are diffs:

  1. Files whose size and mtime are unchanged are skipped without being read.

  2. A content hash decides whether a changed file is re-embedded.

  3. Files gone from disk are dropped.

A file's chunks are replaced with one delete and one add. Syncs never overlap: changes that arrive during a sync share one follow-up. The watcher debounces for 750 ms and falls back to polling every 60 s where recursive fs.watch fails.

One primary per index. Several Claude Code windows on the same folder must not all index it. The process that binds <data dir>/primary.sock is the primary: it indexes and watches. The others are readers. They search the same LanceDB table (which sees the primary's commits) and forward syncs to the primary. Holding the socket is the lock. A crashed primary leaves a socket nobody listens on, and the next process takes it over; readers retry every 30 s.

Searches never wait for indexing. The first index of a large folder takes minutes, so until it finishes, searches answer from whatever is indexed so far. ragdown_stats shows syncing.

Why TypeScript, not Rust. The plan allowed a Rust/napi port if it paid for itself. It does not. Measured on an i9-13900H:

Model load (warm cache)

~300 ms

Query embedding

~23 ms

First index, 105 files / 1,919 chunks

180 s (~11 chunks/s)

Re-sync with nothing changed

~40 ms

Almost all indexing time is the ONNX Runtime forward pass, which is native C++. Tokenizing takes about 1 ms a chunk, and raw onnxruntime-node without transformers.js measured the same throughput. A Rust port would call the same kernels. Two changes did help, and neither depends on the language:

  • Batch chunks by length. A batch is padded to its longest member.

  • Use half the cores. Four threads beat eight on this P/E-core CPU.

For faster indexing, switch the embedder to a GPU-backed openai:<model> endpoint.

Development

npm run typecheck && npm run lint && npm test
npm run build            # the web UI, into web/dist
npm run dev:web          # Vite on :5173, proxying /api to a `serve` on :3000

The web UI in web/ is React, TanStack Query and Router, Tailwind and shadcn components from the cubeui registry (npx shadcn add @cubeui/<name> from web/).

The tests run against real LanceDB, the real socket, and MCP over the SDK's in-memory transport and real HTTP. They use the hash embedder, so they need no model download.

The numbers quoted in Design come from scripts/bench — the embedder comparison, the threshold and drop-off sweeps, the RRF check, and the retrieval and answer-accuracy runs against a synthetic corpus. They are too slow for CI and some need a local LLM, so they are run by hand; that README says how, and what each one found.

Available Tools

9 tools
ragdown_contextContext for a promptA
Read-only

For hooks that run before a turn: the notes related to a user prompt, as a ready-to-inject block, or empty text when nothing is similar enough. Unlike ragdown_recall it filters by min_score, skips short prompts and slash commands, and never returns a section twice for the same session_id.

ParametersJSON Schema
NameRequiredDescriptionDefault
top_kNoDefault RAGDOWN_HOOK_TOP_K
promptYesThe user's prompt, verbatim
max_charsNoMost characters in the block. Default RAGDOWN_HOOK_MAX_CHARS
min_ratioNoLowest share of the best hit's similarity a hit may have and still be included; 0 keeps every hit above min_score. Default RAGDOWN_HOOK_MIN_RATIO
min_scoreNoLowest cosine similarity to include. Default RAGDOWN_HOOK_MIN_SCORE
session_idNoStable id of the conversation; sections already returned for it are skipped

TDQS

A4.4/5.0
Behavior4/5

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

Annotations provide readOnlyHint=true, openWorldHint=false, and the description aligns. It adds behavioral context beyond annotations: fails gracefully to empty text, filters by min_score, skips short prompts and slash commands, and prevents duplicate sections per session. Could mention empty return format but is largely transparent.

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

Conciseness5/5

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

Two sentences, densely informative. The main purpose is front-loaded, and the differentiation from ragdown_recall comes second. No filler or redundancy.

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

Completeness4/5

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

Given moderate complexity (6 params, no output schema), the description covers the key behavior: output is a block or empty, filtering logic, and deduplication. Could mention the return format in more detail (e.g., whether it's a plain string or includes metadata), but for a read-only retrieval tool, it is nearly complete.

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

Parameters3/5

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

Schema coverage is 100%, so parameters are already well-documented. The description adds high-level context (filtering, skipping) but doesn't add detail to any specific parameter beyond what schema provides (e.g., default env vars are in schema descriptions). Baseline 3 is appropriate.

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

Purpose5/5

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

Clearly states it returns a ready-to-inject <ragdown-context> block for pre-turn hooks, and explicitly contrasts with ragdown_recall. Distinguishes its filtering behavior (min_score, skips short prompts/slash commands, no duplicates per session).

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

Usage Guidelines5/5

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

Explicitly says 'For hooks that run before a turn', and mentions it is unlike ragdown_recall, suggesting when to use this vs. that sibling. Provides clear guidance on timing and alternative avoidance.

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

ragdown_editEdit a noteA
Destructive

Change an existing note, or create one at a path you choose. By default text replaces the whole file (frontmatter included), which for an existing note needs base_hash: the hash ragdown_read_doc returned, so you never overwrite a version you have not read. append: true adds text at the end of the note, or with heading at the end of that section, leaving the rest as it is. If the file changed since base_hash, nothing is written: read it again and redo the edit.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesPath of a Markdown file relative to the notes root, e.g. 'projects/alpha.md'
textYesThe note's new Markdown, or with append, what to add
appendNo
headingNoWith append: add to the end of the section under this heading
base_hashNoThe hash from ragdown_read_doc; required to replace an existing note

TDQS

A4.7/5.0
Behavior5/5

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

Beyond the annotations' destructiveHint, the description reveals crucial behavior: whole-file replacement including frontmatter, the hash-based optimistic concurrency lock, append semantics, heading-scoped appending, and the silent no-write outcome when the file changed. This goes well beyond what the annotations alone convey.

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

Conciseness5/5

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

Three dense sentences front-load the core action, then add necessary safety and append semantics without redundancy. Every clause earns its place, and the most important constraint (whole-file replacement + base_hash) appears early.

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

Completeness5/5

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

For a destructive write tool with 5 parameters and no output schema, the description covers the main path, the append variant, the heading variant, the concurrency failure mode, and the recovery instruction. An agent has enough to call the tool correctly and handle the non-success case.

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

Parameters4/5

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

Schema coverage is 80%, so the baseline is 3, but the description adds real meaning to base_hash, append, and heading: it explains why base_hash is required (to avoid overwriting unread versions) and exactly how append/heading modify behavior. This exceeds the schema's bare field definitions.

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

Purpose5/5

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

The description opens with a specific verb and resource: 'Change an existing note, or create one at a path you choose.' It clearly distinguishes the tool's write/update role from sibling read-oriented tools like ragdown_read_doc and ragdown_list.

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

Usage Guidelines4/5

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

The description gives clear operational context: creating vs editing, when base_hash is required, when append is appropriate, and the failure-fallback instruction to 'read it again and redo the edit.' It does not explicitly contrast against other write-adjacent siblings, but the usage conditions are concrete enough for an agent to decide correctly.

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

ragdown_listList notesA
Read-only

Browse the notes rather than search them: every note's path, title, tags and last change, optionally under a subfolder or with a tag. sort: 'recent' puts the most recently changed first.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoOnly notes with this tag; 'project' also matches 'project/alpha'
sortNopath
limitNo
path_prefixNoOnly notes under this subfolder, relative to the notes root, e.g. 'projects/'

TDQS

A4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and openWorldHint=false, and the description adds output fields, filter behavior, and recent-sort semantics. However, the claim that it lists 'every note' overstates behavior because the schema defaults limit to 100 and caps at 1000, which is a notable inaccuracy in what the agent should expect.

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

Conciseness5/5

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

The description is two tight sentences that front-load the browse-vs-search decision and then pack return fields, optional filters, and sort behavior with no filler. Every clause earns its place, making it easy for an agent to parse quickly.

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

Completeness4/5

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

For a read-only list operation with no output schema, the description names the returned fields and the main filtering and sorting knobs, and the schema supplies limit bounds. It would be stronger if it acknowledged the default truncation of the result set, but nothing essential is missing for a basic browse call.

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

Parameters3/5

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

Schema description coverage is only 50%, and the description partially compensates by mentioning subfolder/tag filtering and explaining the 'recent' sort value. It adds little about the 'path' sort value or the meaning of 'limit,' which must be inferred from schema defaults rather than explicitly described.

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

Purpose5/5

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

The description opens with an explicit action—browse rather than search—and names the resource, notes, plus the concrete result shape (path, title, tags, last change). It also distinguishes itself from search-like behavior, so an agent can separate it from siblings such as ragdown_recall without inspecting schemas.

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

Usage Guidelines4/5

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

It clearly frames when to use this tool: browsing notes rather than searching for them, with optional folder and tag filtering. It does not explicitly name the search sibling as the alternative, so the when-not guidance is slightly implied, but the context is strong enough for correct routing.

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

ragdown_read_docRead a noteA
Read-only

Read a Markdown file from the notes folder, whole or by line range, straight from disk. Never clipped. Use it to see the context around a ragdown_recall hit, or to follow a [[wikilink]] in a note. The result's hash is the whole file's, for ragdown_edit's base_hash.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesPath relative to the notes root, as returned by ragdown_recall, or a wikilink target as written inside [[...]] ('Note', 'Note#Heading', 'sub/Note'); a heading narrows the text to that section
end_lineNo
start_lineNo

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, and the description goes beyond that by disclosing that reads come straight from disk, are never clipped, and that the returned hash covers the whole file rather than just the requested range. This adds meaningful behavioral context beyond the structured annotations.

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

Conciseness5/5

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

Three dense sentences, each earning its place: the core behavior, the key non-clipping guarantee, and the relationship to recall and edit. The most important scoping information 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.

Completeness4/5

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

For a read-only tool with no output schema, the description covers the main calling scenarios, line-range capability, disk behavior, and output hash semantics. Minor gaps remain around exact line-range rules and response shape, but an agent has enough to call it correctly in its primary contexts.

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

Parameters3/5

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

The path parameter is richly described in the schema (relative path, recall return value, wikilink forms, heading narrowing), and the description mentions whole-file or line-range reading. However, start_line and end_line have no schema descriptions and the description does not clarify defaults, inclusivity, or interaction with heading narrowing, leaving some ambiguity for a low-coverage schema.

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

Purpose5/5

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

Description states a specific verb and resource: read a Markdown file from the notes folder, either whole or by line range. It also distinguishes itself from siblings by naming its role relative to ragdown_recall hits and ragdown_edit's base_hash, so an agent can tell it apart from recall, list, and edit.

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

Usage Guidelines4/5

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

The description gives explicit contexts for use: seeing context around a ragdown_recall hit, following a wikilink, and obtaining a hash for ragdown_edit. It does not spell out exclusions versus every sibling, but the relevant alternatives are clearly named and the intended use is unambiguous.

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

ragdown_recallSearch notesA
Read-only

Hybrid (semantic + keyword) search over the user's Markdown notes. Returns the most relevant sections with file path, line range, heading breadcrumb and cosine similarity (above ~0.8 is usually on topic). Use it before answering anything the notes may cover; follow up with ragdown_read_doc for the surrounding text.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoOnly search notes with this tag (frontmatter tags or inline #tags); 'project' also matches 'project/alpha'
queryYesWhat to look for, as a question or keywords
top_kNo
formatNotext
max_charsNotext format: characters per hit before it is clipped (0 = never)
path_prefixNoOnly search files under this subfolder, relative to the notes root, e.g. 'projects/'

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, so no contradiction. The description adds value beyond annotations by disclosing the output format (file path, line range, heading breadcrumb, cosine similarity) and a heuristic threshold ('above ~0.8 is usually on topic'). It does not describe pagination or sorting, but for a safe read-only search this is adequate.

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

Conciseness5/5

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

Two sentences, front-loaded with the core purpose, then the usage rule. No filler or repetition of schema content. The behavioral note about similarity is concise and useful.

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

Completeness4/5

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

For a search tool with no output schema, the description covers when to use it, what it returns, and what to do next. It does not explain format json vs text or max_chars, but those are adequately described in the schema. The main gap is not mentioning whether results are sorted by score, but the similarity note implies ranking. Overall complete enough for correct invocation.

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

Parameters3/5

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

Schema description coverage is 67% (4 of 6 params have descriptions). The description itself does not add details for the undocumented top_k and format parameters, though it implies ranking relevance. It clarifies query semantics via 'hybrid (semantic + keyword)', but leaves parameter-specific meaning mostly to the schema. This is adequate, not exceptional.

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

Purpose5/5

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

The description names a specific verb ('search'), resource ('the user's Markdown notes'), and mechanism ('hybrid semantic + keyword'). It also lists what the tool returns (sections with file path, line range, breadcrumb, similarity) and distinguishes it from the sibling ragdown_read_doc, which is for surrounding text.

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

Usage Guidelines5/5

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

It states exactly when to use the tool ('before answering anything the notes may cover') and provides a follow-up action ('follow up with ragdown_read_doc for the surrounding text'). This gives the agent a clear decision rule without having to infer from sibling schemas.

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

ragdown_reindexReindex notesA

Bring the index up to date with the folder now. Changes are normally picked up automatically within a second; use this after bulk edits made while no server was running, or full: true to re-embed everything.

ParametersJSON Schema
NameRequiredDescriptionDefault
fullNo

TDQS

A4.3/5.0
Behavior4/5

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

Annotations declare a safe mutation (readOnlyHint=false, destructiveHint=false, openWorldHint=false); the description adds valuable context beyond them by explaining that indexing is normally automatic and this is a manual, idempotent corrective action. It doesn't hint at cost or duration of a full re-embed, which is the one meaningful gap for a potentially expensive operation.

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

Conciseness5/5

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

Two sentences, zero filler. The primary action and its trigger condition are front-loaded, and the parameter note comes second where it belongs.

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

Completeness4/5

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

No output schema and only one optional parameter, so little needs explaining; the description covers purpose, trigger, and parameter semantics adequately. It stops short of stating what happens on completion or how long a full reindex takes, a minor omission for an operation that may be long-running.

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

Parameters4/5

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

Schema coverage is 0% and the lone boolean has no description in the schema, but the description supplies its meaning: 'full: true to re-embed everything', implying the default false does an incremental update. That is exactly the compensation a low-coverage schema needs.

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

Purpose4/5

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

States a specific verb+resource: 'Bring the index up to date with the folder now.' An agent can distinguish this from siblings like ragdown_recall or ragdown_read_doc, which are read/query tools, though the description doesn't explicitly name any sibling to disambiguate against.

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

Usage Guidelines5/5

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

Explicitly gives both when-not and when: 'Changes are normally picked up automatically within a second; use this after bulk edits made while no server was running.' It also names the escalation path ('full: true to re-embed everything'), so the agent knows the default vs. thorough mode.

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

ragdown_rememberWrite a noteA

Save something worth keeping (a decision, a fix, a how-to) as a new Markdown note in the notes folder, indexed immediately so later searches find it. Never overwrites an existing file. When this note replaces an earlier one, pass that note's path as supersedes so searches stop returning the old version.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoFile name under the notes folder, without .md; defaults to <date>-<title-slug>
tagsNo
titleYes
contentYesMarkdown body; the title and date go in frontmatter
session_idNoStable id of the conversation, recorded in the note's frontmatter
supersedesNoPaths of notes this one replaces, as returned by ragdown_recall. They stay on disk and ragdown_read_doc still opens them, but search and hook context skip them. Use it when a fact changed, not when you are merely writing about the same topic.

TDQS

A4.6/5.0
Behavior5/5

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

Goes well beyond the sparse annotations by disclosing indexing behavior, the non-overwrite guarantee, and that superseded notes remain readable but are excluded from search/context. Adds nuanced guidance on when to use supersedes versus merely writing about the same topic.

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

Conciseness5/5

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

Three sentences, each with a distinct job: core action, safety guarantee, supersede guidance. No filler or repetition of schema details.

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

Completeness4/5

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

Strong on behavior and parameter intent; slightly lacking an explicit statement of return value or generated file path, though that is derivable from naming defaults. Overall sufficient for correct invocation.

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

Parameters4/5

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

The description adds important meaning to supersedes (search/context skipping, paths from ragdown_recall) and complements the schema's 67% coverage. It explains the note-save workflow but does not elaborate on less critical params like tags/title beyond what the schema provides.

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

Purpose5/5

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

States a precise action: saving durable knowledge as a new Markdown note in the notes folder, with key qualifiers 'never overwrites' and 'indexed immediately'. The verb-resource pair clearly distinguishes it from read/search siblings like ragdown_read_doc and ragdown_recall.

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

Usage Guidelines4/5

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

Gives clear conditions for use: saving decisions, fixes, how-tos, and when replacing an earlier note with supersedes. It does not explicitly contrast with read-only siblings, but the write/read split is evident from sibling names and context.

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

ragdown_statsIndex statusA
Read-only

The notes folder, index size (files, chunks), embedder, whether this process is the indexing primary, and the last sync. include_files lists every indexed file.

ParametersJSON Schema
NameRequiredDescriptionDefault
include_filesNo

TDQS

A3.6/5.0
Behavior4/5

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

Annotations only declare readOnlyHint and a closed-world hint, so the description adds real value: it discloses that the response includes per-process role information (whether this process is the indexing primary) and the last sync, which is meaningful multi-process context. It stops short of describing error behavior or output format, but for a read-only status call that is a minor gap.

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

Conciseness4/5

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

Two compact sentences with no filler; the reported-field list comes first and the parameter note last. The field enumeration is dense but each item earns its place by telling the agent what to expect back.

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

Completeness4/5

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

With no output schema, the description carries the return-value burden and largely does so by naming each reported field. Minor omissions remain — no note on response shape or behavior when no index exists — but the essential content is covered for a simple read-only stats call.

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

Parameters4/5

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

Schema description coverage is 0% and the single boolean parameter is undocumented in the schema, but the description compensates by explaining that include_files makes the response list every indexed file. It does not restate the default-false behavior or note the cost of enumerating all files, so it is good rather than complete.

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

Purpose4/5

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

The description enumerates exactly what the tool reports (notes folder, index size in files/chunks, embedder, indexing-primary flag, last sync), so an agent can tell it returns index status rather than notes or documents. It lacks a leading verb phrase and never names the sibling tools it differs from, so the differentiation is inferential rather than explicit.

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

Usage Guidelines2/5

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

There is no statement of when to call this versus ragdown_recall, ragdown_read_doc, or ragdown_reindex, and no prerequisites or diagnostic context. An agent must guess that this is a status/inspection tool rather than a retrieval one.

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. 3 tool updatesv5.9.0
    • Addedragdown_backlinks
    • Addedragdown_edit
    • Addedragdown_list
  2. 2 tool updatesv5.2.0
    • Changedragdown_read_doc1 field changed
      • changedInput schema / properties / path / description
        Previous value: -"Path relative to the notes root, as returned by ragdown_recall"New value: +"Path relative to the notes root, as returned by ragdown_recall, or a wikilink target as written inside [[...]] ('Note', 'Note#Heading', 'sub/Note'); a heading narrows the text to that section"
    • Changedragdown_recall2 fields changed
      • changedInput schema / properties / path_prefix / description
        Previous value: -"Only search files under this folder, relative to the notes root, e.g. 'projects/'"New value: +"Only search files under this subfolder, relative to the notes root, e.g. 'projects/'"
      • addedInput schema / properties / tag
        Added value: +{
        +  "description": "Only search notes with this tag (frontmatter tags or inline #tags); 'project' also matches 'project/alpha'",
        +  "type": "string"
        +}
  3. 2 tool updatesv4.0.0
    • Addedragdown_context
    • Changedragdown_remember2 fields changed
      • addedInput schema / properties / session_id
        Added value: +{
        +  "description": "Stable id of the conversation, recorded in the note's frontmatter",
        +  "type": "string"
        +}
      • addedInput schema / properties / supersedes
        Added value: +{
        +  "description": "Paths of notes this one replaces, as returned by ragdown_recall. They stay on disk and ragdown_read_doc still opens them, but search and hook context skip them. Use it when a fact changed, not when you are merely writing about the same topic.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
  4. 5 tool updatesv1.0.0
    • First observedragdown_read_doc
    • First observedragdown_recall
    • First observedragdown_reindex
    • First observedragdown_remember
    • First observedragdown_stats

TDQS

A4.1/5.0

Scored across 9 tools

Disambiguation4/5

Recall and context both perform similarity retrieval, but their descriptions clearly separate ad-hoc search from pre-turn hook injection; remember and edit also overlap in creating notes but are distinguished by auto-named immutable notes vs explicit path/update. The remaining tools map cleanly to distinct actions.

Naming Consistency4/5

All tools share the ragdown_ prefix and are readable, but the second part mixes verb forms like reindex, remember, read_doc, and recall with noun forms like stats, backlinks, and context. This is a minor inconsistency rather than a chaotic pattern.

Tool Count5/5

Nine tools is well within the ideal range for a notes-RAG server. Each tool covers a distinct function—indexing, adding, reading, editing, browsing, backlinks, stats, search, and context injection—so none feels redundant.

Completeness4/5

The surface covers the core notes lifecycle plus retrieval and context integration: create via remember/edit, read via read_doc/list, update via edit, search via recall/context, and note graph via backlinks. The main gap is an explicit delete/remove operation, though supersede and empty edits provide partial workarounds.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to search, read, create, and maintain a local-first knowledge base using hybrid retrieval and Markdown note management through the Model Context Protocol.
    9 npm
    1
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables local-first hybrid knowledge retrieval from authorized Markdown and plain-text files, combining full-text and vector search with reranking and traceable source references via a single search tool.
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Provides coding agents with persistent local memory by exposing tools to save, search, and retrieve decisions, bugs, and context as Markdown with hybrid keyword and semantic search.
    4
    MIT