librarian
This MCP server gives an AI assistant a searchable local index of curated specialist docs and forum threads, with citable results.
Search the index (
search): hybrid keyword + semantic query with reranking; returns chunk IDs, dates, versions, source/kind, authority flags (official, accepted, vendor staff, expert, top-voted), score, token estimate, URL and snippet.Pass a product
version(e.g. "11.3") to boost (or filter) matching results.Narrow by
source,source_type(docs, kb, bug, forum), anddate_from/date_to.Use
explainfor a per-signal scoring breakdown.
Read the source material (
fetch): full markdown of a result at chunk, document, or whole-thread scope, honouring a token budget — threads come back accepted answer first, then staff/experts/top-voted.Learn the index's scope (
outline): sources, boards/tags, date ranges and version coverage, optionally for a single source.Get raw statistics (
index_info): document counts, date ranges, version tag counts.Cite chunk IDs back to the original page or post in answers.
Crawls and indexes Esri Community, Esri documentation, knowledge base, and bug database content to provide hybrid search over Esri ArcGIS Enterprise architecture, administration, and practitioner knowledge.
Crawls and indexes GIS Stack Exchange Q&A content, including votes, accepted answers, dates, and version metadata, for keyword and semantic search and full thread/document retrieval.
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., "@librarian search for ArcGIS Enterprise federation errors after upgrading to 11.3"
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.
niche-librarian
Give your AI assistant a librarian for one niche: a local search index of the docs and forums that practitioners actually use, served to the agent over MCP.
General web search and a model's own memory are weakest exactly where specialist work lives: version-specific details, error messages, "this broke after the upgrade", and the difference between an official fix and a forum guess. niche-librarian crawls a hand-picked set of sources for one topic, through official APIs wherever they exist. It records who said what, on which version, with what standing (vendor docs, staff reply, accepted answer, or just a post), then ranks results with that in mind. Every result is citable back to the original post or page.
This repo ships the recipe (code, configs and source lists), never crawled content. You
run the crawl yourself, and the data stays on your machine in data/, which git ignores.
Topic packs included
Pack | What it covers | Sources | Good first pack? |
| Running your own home server: Proxmox VE, TrueNAS and ZFS, Docker and Compose, and the Linux underneath | Proxmox docs and wiki, TrueNAS docs and forums, Docker docs and forums, Arch Wiki, Level1Techs, LinuxServer.io | Yes: broad audience, all public APIs, no keys needed |
| Esri ArcGIS Enterprise administration: installs, upgrades, federation, Data Store, Web Adaptor | GIS Stack Exchange, Esri Community, Esri docs, knowledge base and bug database | For GIS administrators |
Each pack is independent: its own database, its own MCP server, its own ranking. Writing a pack for your own niche is the point. See Writing your own pack.
Related MCP server: loci-mcp
Quick start (home server pack)
You need Python 3.11+ and Ollama, which provides the local embeddings for semantic search. Without Ollama, search still works in keyword-only mode.
1. Install (Linux / macOS):
git clone https://github.com/Nullislander0/niche-librarian.git
cd niche-librarian
python3 -m venv .venv
.venv/bin/pip install -e ".[dev,rerank]"
ollama pull nomic-embed-text
.venv/bin/pytest # optional: should passOn Windows (PowerShell), use py -3 -m venv .venv and .venv\Scripts\ in place of
.venv/bin/ throughout.
2. Pick the pack and check its sources:
export LIBRARIAN_PACK=homelab # or pass --pack homelab to each command
.venv/bin/librarian sources # how each source is accessed, and when that was checked3. Crawl a sample first. --sample 50 stops each source after 50 threads or pages: a
walk around the block that proves every source works, in about 15 minutes. Run the full
crawl once you're happy with it.
.venv/bin/librarian crawl --sample 50 # quick end-to-end test of the pack
.venv/bin/librarian crawl # full first crawl (see "What to expect" below)4. Search from the terminal, to see what you got:
.venv/bin/librarian outline
.venv/bin/librarian search "Proxmox VE 8 GPU passthrough to VM not working" --explain5. Connect your AI assistant, as covered under Connect an agent (MCP) below. Then ask your assistant real questions. It searches the index, reads the best threads and cites them.
What to expect from a first crawl
Time: the docs and wikis take an hour or two. The forums take most of a night, because the crawler paces itself (
min_interval_secondsin the pack'ssources.yaml). Leave it running. It keeps the machine awake while it works, and it resumes where it stopped if interrupted.Disk: packs end up in the hundreds of megabytes up to about 1 GB each, plus a raw response cache in
data/cache/.Later runs only fetch what changed: new topics, edited wiki pages, new posts in threads you already have.
How it works
sources ──► parsers ──► version tagging ──► chunks ──► SQLite (FTS5 + sqlite-vec) ──► rerank ──► MCP
(per site) (versions.yaml) (one .db per pack) (ranking.yaml)The engine (
engine/) is generic: a polite fetcher, parsers, storage, hybrid search, ranking and the MCP server.A topic pack (
packs/<name>/) is configuration: the source list, version patterns, synonyms, ranking weights and any site-specific parser overrides. To add a topic, write a pack. The engine shouldn't need changes.
Search combines keyword search (SQLite FTS5, BM25) with semantic search (Ollama
nomic-embed-text vectors in sqlite-vec), merged with reciprocal rank fusion. A small
cross-encoder then re-reads the top candidates against the query (FastEmbed, ONNX Runtime,
no PyTorch). On the Esri pack's 200-question test, that raised top-1 accuracy from 73% to
about 80%. Last, results are reranked using the pack's signals:
Version match with the version being asked about, e.g.
pve 8.2ortruenas 24.10.Recency, only when the question is version-sensitive.
Authority: vendor docs, knowledge base and bug reports outrank forum opinion.
Accepted answers, vendor staff, recognized experts, and votes or likes.
First-hand evidence: logs, configs, "after upgrading…", "this fixed it".
Author reputation and account age, where the site provides them.
These signals scale relevance rather than replace it, so a popular answer to a different question can't outrank the right one. There's deliberately no backlink weighting, no keyword-stuffing reward and no blanket freshness bias.
Setup details
Platforms. It's developed on Linux, and the tests run on Linux, Windows and macOS in CI.
Sleep: long jobs (
crawl,rebuild,embed,eval) keep the machine awake while they run, and the machine sleeps normally afterwards. On Linux this uses a desktop idle inhibit plussystemd-inhibit, on WindowsSetThreadExecutionState, and on macOScaffeinate. SetLIBRARIAN_NO_STAY_AWAKE=1to turn this off.macOS: the usual macOS Pythons (python.org's installer, Apple's, GitHub's) can't load SQLite extensions, which semantic search needs. On macOS the install therefore adds
sqlean.py, a drop-in SQLite build that can, and the engine switches to it automatically: nothing to configure, and any Python works. If it ever can't load either, the index runs keyword-only (full-text search plus the reranker) and logs a warning. CI checks that vector search loads on Linux, Windows and macOS.
Settings come from environment variables:
Variable | Default | Purpose |
|
| Default pack for every command |
|
| Databases, caches, models, test sets |
|
| Ollama server |
|
| Embedding model. Run |
| (empty) | A URL or email appended to the crawler's user agent |
| (none) | Optional, for the Esri pack: raises the Stack Exchange quota from ~300 to 10,000 requests a day (register an app) |
Keep keys in your shell environment, never in the repo.
Everyday commands
librarian crawl [--source ID] [--sample N] [--max-requests N] # fetch and index; resumable
librarian check # sources.yaml typos: unknown keys and options
librarian sources # sources and their access records
librarian outline # what the index covers: sources, boards, tags, versions
librarian search "query" [--version 11.3] [--explain]
librarian fetch "<chunk_id>" [--scope chunk|document|thread] [--max-tokens N]
librarian rebuild # re-parse saved responses (no network)
librarian retag # reapply versions.yaml to the whole index (seconds)
librarian eval-build / eval # build and run the pack's retrieval testEvery raw response is kept in data/cache/, so rebuild can re-parse everything after you
change a parser or the chunking, without touching the network.
Each crawl also checks what it parsed. If most documents from a source come out empty,
untitled, undated or authorless, or most threads share one title (a site banner instead of the
thread's name), the crawl report lists parse_warnings: usually a sign the site's layout
changed and its parser needs a look.
Saved searches and alerts
Save a query once, and get only what's new since you last checked:
librarian watch add pve-upgrades "Proxmox VE upgrade problems" --min-score 0.6
librarian crawl --watch --notify # crawl, then report new matches (desktop notice)
librarian watch run # or on its own; writes a report to data/watches/
librarian watch list | remove NAME
librarian search "query" --new-since 2026-11-01 # ad hoc: only recently indexed materialEach document records when it first entered the index, so "new" means genuinely new, not
re-crawled. Watches are personal and live in data/watches/, outside the repo. Agents can ask
the same thing through MCP: search(..., new_since="YYYY-MM-DD").
Web watches run a query against the live web instead of your index, catching rare mentions on sites you don't crawl:
export BRAVE_API_KEY=... # https://api-dashboard.search.brave.com
librarian watch add vfio "GPU passthrough regression" --web --freshness pw --site forum.proxmox.com
librarian watch run --web-onlyRelease alerts use Brave's news index: list your products under web.releases in the
pack's sources.yaml, and get one watch per product for new versions, patches, security
advisories and end-of-support notices:
web:
releases:
- {name: Proxmox VE, match: 'Proxmox'} # match: must appear in the title or snippet
- {name: TrueNAS, match: 'TrueNAS'}librarian watch add-releases # creates/updates release-proxmox-ve, release-truenas
librarian watch run --web-only --notify
librarian watch add fw "OPNsense firmware" --web --backend brave-news --require 'OPNsense'Brave's API terms don't allow storing results, so web results are shown, never saved. Only fingerprints of URLs already seen are kept, so later runs show only new links. Your plan's monthly limit is read from Brave's response headers (see the quota line below).
Beyond the index: web search and single pages
Your index holds what you could crawl. For the rest (very recent posts, sites that block crawlers, one-off pages) the agent gets three more MCP tools:
Tool | What it does | Writes anything? |
| live Brave search ( | no |
| fetches one page politely (paced, block and challenge detection; public addresses only, so an agent can't reach your local network) and returns markdown for this answer | no |
| proposes a page for the index | a queue entry only |
Nothing an agent finds goes into your index until you approve it:
librarian pages list # what agents proposed, and why
librarian pages approve [URL ...] # approve (all pending by default) and index
librarian pages reject [URL ...] # won't be proposed again
librarian pages add URL --note "..." # add one yourself
librarian pages remove URL
librarian web "query" --site reddit_gis # search the web yourself; prints the quotaApproved pages become the web_pages source, ranked below the vendor docs and forums your
recipe crawls. Pages under a part of a site one of your sources already crawls are refused,
because that source's parser keeps richer metadata. What's stored comes from the page's own
site, never from search results.
Each pack can name site shortcuts and hosts never to fetch in sources.yaml:
web:
sites: {reddit_homelab: reddit.com/r/homelab, reddit_proxmox: reddit.com/r/Proxmox}
blocked_hosts: [example-forum.com] # e.g. sits behind a bot challengeQuota: agent searches stop when the month's remaining Brave quota falls below a quarter,
so your watches always have room (LIBRARIAN_WEB_AGENT_SHARE=0.75 to change it), and at 50
per server session (LIBRARIAN_WEB_SESSION_CAP). Keys can live in
~/.config/niche-librarian/env (export NAME=value lines): the engine reads that file
itself, so MCP clients that don't start from your shell still find them.
Trend signals
For "how much is X being talked about, and about what?" rather than "what's the answer?",
a pack can list signals: in its sources.yaml: terms to track and categories to sort
mentions into, each with a weight.
signals:
terms:
- {name: proxmox-backup, match: 'proxmox backup server|\bpbs\b'}
categories:
data_loss: {weight: 1.0, description: "lost or corrupted backups", keywords: 'corrupt|lost data'}
pricing: {weight: 0.5, description: "subscription and licensing cost", keywords: 'subscription|price'}librarian signals run # label new documents (local LLM via Ollama, or keywords)
librarian signals report --by month # counts per term, category and periodLabeling runs on your machine (qwen3:4b by default; --keywords-only without Ollama).
Only labels are stored: no text and no authors. Agents get the same table from the MCP
signals tool.
Sources whose documents carry numbers (source_type: data, with extra.metrics) appear as
measures beside the counts instead of being labeled. Two parsers produce them, both for
public-domain US government data:
openfda: FDA adverse event reports per drug per month, drug shortages and recallsnadac: CMS NADAC, the weekly price pharmacies pay per unit, and each week's price changesmedicaid_sdud: Medicaid outpatient prescriptions per drug per quarter (CMS State Drug Utilization Data), nationally or by statepartd_formulary: Medicare Part D coverage per quarterly release: share of plans covering a drug and how many require prior authorization or step therapy. CMS ships this as a 2.5 GB ZIP; the parser reads only the two files it needs (~9 MB) with HTTP range requests
Packs about people: pseudonymized authors
A pack can set privacy: {authors: pseudonymize}. Each author is then stored as a stable
pseudonym (P-7f3a91, a keyed hash: the same person every week, the handle never stored),
handles are scrubbed from quotes, @mentions, greetings and attributions in the text, emails and
phone numbers are removed, and profile numbers are coarsened. The signals report then counts
posters as well as posts, and shows switch flows: posters who mentioned one term and later
another. librarian privacy apply converts documents already in the index; librarian rebuild
re-scrubs from the cache with every handle known. librarian privacy audit checks the index for
anything left (handles, profile links, emails, phone numbers) without printing the handles; it
also runs after every crawl of a pseudonymized pack. The key is created in data/secrets/ (back
it up: a new key means new pseudonyms). Pseudonymized isn't anonymous: post text and URLs can
lead back to the original post, and the local page cache keeps the raw pages for rebuilds.
Connect an agent (MCP)
Each pack is its own MCP server (librarian serve --pack <pack>), so register one per topic
you want an assistant to use. Use absolute paths.
Claude Code
# Linux / macOS
claude mcp add homelab-librarian --scope user -- /ABS/PATH/.venv/bin/librarian serve --pack homelab
# Windows
claude mcp add homelab-librarian --scope user -- C:\ABS\PATH\.venv\Scripts\librarian.exe serve --pack homelabThen start a new session. To make the assistant reach for it without being asked, add a
line like this to your CLAUDE.md: "For home server, Proxmox, TrueNAS or Docker questions,
search the homelab-librarian MCP before answering, and cite chunk IDs."
Claude Desktop. Edit claude_desktop_config.json (Settings → Developer → Edit Config).
The file lives in ~/Library/Application Support/Claude/ on macOS, %APPDATA%\Claude\ on
Windows, and ~/.config/Claude/ on Linux.
{
"mcpServers": {
"homelab-librarian": {
"command": "/ABS/PATH/.venv/bin/librarian",
"args": ["serve", "--pack", "homelab"]
}
}
}On Windows, use "command": "C:\\ABS\\PATH\\.venv\\Scripts\\librarian.exe". JSON needs the
backslashes doubled.
Tools the agent gets:
Tool | What it returns |
| Map of the index: sources, boards, tags, date ranges, version coverage. Read this first |
| Compact results: chunk_id, date, versions, source, flags (official, accepted, staff, expert), score, approximate tokens, URL, snippet |
| Full markdown with citation metadata. |
| Raw statistics |
The tool descriptions coach the agent: one topic per search, pass the user's version, stop after a few empty searches, and say when sources disagree.
Private packs and reports
Packs are looked up in two places, first match wins: your private packs folder,
~/.config/niche-librarian/packs/, then the repo's packs/. Keep any recipe you don't want
published (client topics, internal sources) in the private folder: it lives outside the repo,
so it can't be committed or pushed. A private pack with the same name as a repo pack replaces
it locally. Set LIBRARIAN_PACKS to a :-separated list of folders (; on Windows) to change
the search path.
Reports and other results belong under data/ (e.g. data/reports/<pack>/), which git
ignores. Two guards back this up: tools/pre-push is a git hook that refuses a push containing
reports, data, secrets or a pack that also exists in your private folder (install it with
cp tools/pre-push .git/hooks/pre-push), and a test fails in CI if any such file is tracked.
For reports, librarian memo-data (also the MCP memo_data tool) computes every number once:
latest and previous value, change, periods and the document to cite, with incomplete FDA
months left out, so a writing agent never does arithmetic.
Writing your own pack
A pack is a folder under packs/ holding a few YAML files. Copy packs/homelab/ as a
starting point. The full field guide, covering access rules, scoping and platform quirks,
is docs/SOURCING.md.
Building a recipe, step by step
Pick a narrow niche. "Home servers" or "one product's administration" works; "all of tech" doesn't. Write one sentence on who the pack is for. It becomes the pack's
description, which agents read.List where practitioners actually go: vendor docs, the vendor's community, the independent forum everyone recommends, the relevant Stack Exchange tags, a wiki. Ask someone who does the work.
Check each site's access before writing any config: one plain request (real content or a block?), whether there's an API or sitemap, and its rough size. See the checklist. Drop anything that blocks or challenges the crawler.
Match each source to a parser (table below). If one fits, the source is config only. If none does, write a parser (see below) and test it against a hand-written fixture.
Scope each source: categories or tags, a
since:date, slug filters, caps for megathreads. Estimate requests × pacing before you run anything.Write
versions.yamlandsynonyms.yamlfor the niche's version numbers, codenames and abbreviations. Check them withlibrarian retagand a few searches.Run
librarian crawl --sample 50. About 15 minutes proves every source works end to end. Read a few results withlibrarian search ... --explainandlibrarian fetch.Measure, then tune. If a source has accepted answers, build a retrieval test (
eval-build,eval) and change ranking or synonyms only when the numbers improve.Run the full crawl, then share the recipe. The repo never includes the data.
File | What it holds |
| Pack name and description, example queries for agents, request pacing, and the sources: each with a |
| How to spot versions. Use a single |
| Query expansion. |
| Signal weights, which source types count as authoritative, first-hand evidence patterns, reranker settings |
Parsers already available. If your sources run on one of these, a new pack is config only:
Parser | For |
| Any Discourse forum, through its built-in JSON API |
| Any MediaWiki site, through |
| Docs sites: pages from sitemaps, explicit URLs or an index page, with a content selector |
| Any Stack Exchange site, through the official API |
| Vanilla Forums communities, through API v2 |
| XenForo 1.x forums (HTML) |
| XenForo 2.x forums (HTML): forum listings by latest activity, thread pages, staff and user-panel fields |
Record how you checked access. Every source gets an access: block. A source whose
verdict is blocked or needs-key is never crawled:
access: {checked: 2026-11-05, robots: allowed, method: Discourse JSON API, auth: none, verdict: ok}Before adding a site, check whether a plain request gets real content or a bot challenge, and whether you've accepted any terms that cover it. Prefer an official API or export. If a site challenges or blocks the crawler, mark it blocked and move on; never work around it.
Test your pack's search quality. librarian eval-build picks threads that have accepted
answers and rewrites each question in different words. By default it uses a local Ollama
model (LIBRARIAN_EVAL_MODEL), which should be one that answers directly rather than
"thinking" at length; --rewrite none leaves the queries blank so you can write them
yourself. librarian eval then reports how often search re-finds the original thread
(top-1, top-5, top-10). Run it before and after any ranking or synonym change. A pack needs
a source with accepted answers for this.
A new kind of site needs a parser
Copy engine/parsers/stackexchange.py, the most thoroughly commented example, or the closest
existing parser:
# engine/parsers/mysite.py (or packs/<pack>/parsers/mysite.py for a pack-only parser)
from engine.parsers.base import CrawlContext, Document
class Parser:
POSITION_KEY_PREFIXES = ("cursor",) # state keys that hold crawl position
def __init__(self, ctx: CrawlContext):
self.ctx = ctx # ctx.options = this source's options
def crawl(self):
st = self.ctx.state.get("cursor") or {"page": 1} # resumable position
while True:
self.ctx.check_budget() # respects --max-requests
data = self.ctx.fetcher.get_json("https://api.example.org/posts",
{"page": st["page"]}) # pacing/cache/UA/blocks
for post in data["posts"]:
yield Document(
doc_id=f"{self.ctx.source.id}:{post['id']}", # stable forever
source=self.ctx.source.id, source_type=self.ctx.source.source_type,
kind="post", url=post["url"], title=post["title"],
content_md=post["markdown"], post_date=post["created"],
author=post["author"], score=post.get("votes"),
)
if not data["has_more"]:
break
st["page"] += 1
self.ctx.state.set("cursor", st) # save progress after each pageRules for parsers:
Make every request through
ctx.fetcher, which handles pacing, caching, block detection and the user agent.doc_idmust be stable. Chunk IDs (<doc_id>#c<n>) are what agents cite.Return content as markdown, plus whatever metadata the site really provides (votes, accepted answers, staff status, reputation). Leave a field
Nonerather than guess.Replies set
parent_idto the thread root. That makesfetch(scope="thread")work, and replies inherit the thread's version tags.Parsers don't do version tagging, chunking or ranking. The engine handles those from pack config.
Add a test under
tests/with a hand-written fixture for the cases you care about, and a structure-only fixture from real pages: after a small crawl, runpython tools/make_fixture.py PACK SOURCE NAME. It replays the parser against your cache and keeps the real markup, JSON keys, numbers and dates, but replaces every word, username, host and API key with stand-ins (through a mapping that's never saved, so it can't be undone).tests/test_real_fixtures.pythen checks the parser still reads that real structure.
Rules this project follows
Polite, honest access. It paces requests (including any robots.txt Crawl-delay) and identifies itself with an honest user agent. It honours the agreements you actually accept, such as API terms; robots.txt
Disallowrules aren't legally binding in the US and are enforced only for EU/EEA sites (configurable; see docs/SOURCING.md).It never works around a block: no bypassing bot challenges, CAPTCHAs or login walls. A blocked source is reported and skipped.
Recipe, not data. Crawled content is never committed or redistributed.
Nothing private in the repo: no client data, hostnames, internal URLs or credentials, in code, configs or fixtures.
The reasoning behind these rules, the access-check checklist, scoping advice and per-platform notes are in docs/SOURCING.md.
Layout
engine/
crawl/fetcher.py polite HTTP: pacing, cache, retries, block detection
parsers/ base.py, stackexchange (worked example), vanilla, discourse, mediawiki,
sitemap_html, xenforo1, html_md (HTML -> markdown)
index/ store (FTS5 + sqlite-vec), chunking, Ollama embeddings
rank/ rerank.py (fusion + pack signals), cross.py (cross-encoder)
versions.py version tagging from versions.yaml
synonyms.py query expansion from synonyms.yaml
indexer.py crawl -> tag -> chunk -> store -> embed
search.py hybrid search, fetch, outline (shared by CLI and MCP)
evaluate.py retrieval test: build and run
awake.py keep the machine awake during long jobs
mcp_server/server.py MCP tools
cli.py the `librarian` command
packs/
homelab/ esri_enterprise/
tests/License
MIT. See LICENSE. This covers the code and configs only: crawled content belongs to its authors and sites, and is never part of this repository.
Available Tools
4 toolsfetchA
Full text of a result as clean markdown, with citation metadata.
Args: chunk_id: id from search results, e.g. "gis_se:a:12345#c0". scope: "chunk" (just that passage), "document" (the whole post or page, default), or "thread" (question plus replies: accepted answer, vendor staff, experts and top-voted first). max_tokens: approximate output budget (default 6000). Content beyond it is listed by id so you can fetch specific parts; raise it only when you need the whole thread.
Inputs: chunk_id (required), scope, max_tokens. Returns: result
index_infoB
What this index covers: sources, document counts, date ranges, version tag counts.
Inputs: no named parameters. Returns: result
outlineA
Map of the index: sources, boards/tags, date ranges and version coverage. Read this first to learn what the index can answer and which terms and versions it covers.
Args: source: limit to one source id.
Inputs: source. Returns: result
searchA
Hybrid keyword + semantic search over the local index, reranked for quality and version.
Write one specific question or symptom per call; include error text and product names. If the user's question spans several distinct topics, make one call per topic. Good: 'webgisdr backup fails unable to generate token 11.3'; 'federate ArcGIS Server with Portal certificate error'; 'Data Store upgrade 11.5 to 12.1 validation fails'. Bad: 'portal'; 'upgrade, federation, SSL and backups in 11.x'. If two or three rephrased searches find nothing relevant, stop and say so rather than searching indefinitely.
Returns compact results: chunk_id (stable, citable), date, versions, source/kind, flags (official, accepted, top_voted, vendor_staff, expert), score, approximate tokens, URL, snippet.
Args:
query: the question or symptom, e.g. an error message plus the component involved.
limit: max results (1-50).
version: the user's product version, e.g. "11.3" or "10.9.1" ("11" = any 11.x).
Pass it whenever known: matching versions rank higher.
version_mode: "boost" (default) ranks matching versions higher; "filter" keeps only them
(drops the many posts that never state a version, so use sparingly).
date_from / date_to: ISO dates (YYYY-MM-DD) bounding the post date.
source_type: e.g. "docs", "kb", "bug", "forum" (see outline).
source: a source id from outline.
explain: include the per-signal scoring breakdown.
Inputs: query (required), limit, source, date_to, +5 more. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 4 tools
search and fetch are clearly distinct (find vs. read), but outline and index_info overlap heavily — both are described as telling you 'what the index covers' (sources, dates, version coverage), with only counts vs. boards/terms differentiating them. An agent can plausibly pick the wrong one of the pair when it just wants to know what's available.
Two tools are bare verbs (search, fetch), one is a standalone noun (outline), and one uses a noun_noun form with an underscore (index_info). All are readable and snake_case-compatible, but there is no single consistent pattern across the set.
Four tools is lean and appropriate for a retrieval server: discover, search, fetch, plus one metadata helper. The only quibble is that the metadata helper is duplicated (outline vs. index_info), so one slot is arguably wasted.
The core retrieval lifecycle — orient on the index, search with filters, fetch full documents/threads with citation metadata — is fully covered with no dead ends. Minor gaps: no way to enumerate chunks within a document or browse a source without a query, though search filters partially compensate.
Maintenance
Related MCP Connectors
Multi-engine search for AI agents. Trust scoring, local corpus, MCP-native. Self-hostable, BYOK.
Agent-driven search: build, import, tune, search, and score result quality — all over MCP.
Agentic search over your Dewey document collections from any MCP-compatible client.
Search and inspect source-pinned agent skills, plugins and tools through a free public MCP.
Related MCP Servers
- FlicenseNot gradedqualityAmaintenanceEnables AI agents and MCP hosts to query locally indexed notes, docs, chat logs, and other files via hybrid vector/BM25 retrieval with section-level citations. Exposes tools, resources, and prompts for searching and asking over the indexed content.-
- FlicenseNot gradedqualityAmaintenanceEnables AI hosts and agents to query a local hybrid index of scattered notes and documents, retrieve section-level citations, and access resources and prompts through MCP.-
- FlicenseNot gradedqualityAmaintenanceEnables MCP-compatible AI agents to search, ask, and retrieve section-level cited answers from a local hybrid index over scattered notes, documents, and chat logs.-
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to search local text and Markdown collections using keyword BM25, semantic vector search, and reranked hybrid retrieval, with full-document retrieval and collection status over MCP.1,009 PyPIMIT