neonrecall
OfficialClick 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., "@neonrecall Which gas makes a neon sign glow blue?"
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.
NEONRECALL
░▒▓ N E O N R E C A L L ▓▒░
─────────────────────────────
╲ ╲ ╲ │ ╱ ╱ ╱
╲ ╲ ╲ │ ╱ ╱ ╱
───────────────┼───────────────Retrieval-augmented answers from your own docs, with citations. Drop in Markdown, ask questions, get answers that point back at the source. It runs on a local model at 2 AM with the Wi-Fi off, or on a hosted API.
Ingest Markdown and plain text, split into heading-aware chunks with overlap
Embed with any OpenAI-compatible endpoint (OpenAI, Ollama, vLLM, LM Studio), or the built-in offline hashing embedder
Store vectors in PostgreSQL + pgvector (HNSW), or SQLite / in-memory
Retrieve with hybrid search: dense vectors + BM25, fused with Reciprocal Rank Fusion, plus optional reranking
Answer with numbered
[n]citations through any OpenAI-compatible chat API, or an offline extractive fallbackServe over FastAPI, a CLI, and an MCP server (
search_docs,ask)Measure retrieval with a recall@k / MRR eval harness on a checked-in QA set
Everything has an offline default, so the tests and evals need no network, no GPU and no API keys.
▸ Quickstart
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]" # add ,postgres for the pgvector backend
neonrecall ingest evals/corpus --base evals/corpus
neonrecall ask "Which gas makes a neon sign glow blue?"Argon with a drop of mercury glows blue. [1]
[1] neon-sign-care.md › Neon Sign Care > How the colors workWith no configuration this runs fully offline: SQLite file neonrecall.db, the hashing
embedder, and extractive answers.
Related MCP server: rag-mcp
▸ Plugging in real models
Neonrecall talks to anything that speaks the OpenAI /v1/embeddings and
/v1/chat/completions APIs. With Ollama:
docker compose up -d db # Postgres 16 + pgvector
docker compose --profile ollama up -d # optional: Ollama in a container
ollama pull nomic-embed-text && ollama pull llama3.1
cp .env.example .env && set -a && . ./.env && set +a
neonrecall ingest docs/
neonrecall ask "How do we archive the tape masters?"Settings are read from NEONRECALL_* environment variables (see src/neonrecall/config.py):
Variable | Default | Notes |
|
|
|
|
|
|
|
| matches |
|
| use one table per embedding model |
|
|
|
| Ollama, | |
|
|
|
| Ollama, | |
|
|
|
|
| characters |
|
| RRF weights |
| current dir |
|
Switching embedding models changes vector dimensions. Re-ingest into a fresh SQLite file or a new
NEONRECALL_PG_TABLE; the pgvector store refuses mismatched dimensions.
▸ Interfaces
CLI
neonrecall ingest PATH... [--base DIR]
neonrecall search "ground loop hum" -k 5 --mode hybrid|vector|bm25 [--rerank]
neonrecall ask "How do I stop the 60 Hz hum?" [--json]
neonrecall stats
neonrecall serve --port 8000 # FastAPI
neonrecall mcp # MCP over stdio
neonrecall eval --min-recall 0.9 # retrieval eval; non-zero exit below threshold--db PATH overrides the SQLite file for any command.
HTTP API
neonrecall serve
curl -s localhost:8000/ingest -H 'content-type: application/json' \
-d '{"documents": [{"source": "grid.md", "text": "# Grid\nThe horizon grid is magenta."}]}'
curl -s localhost:8000/query -H 'content-type: application/json' \
-d '{"query": "What color is the grid?", "k": 5}'Endpoint | Body | Returns |
|
| counts and sources |
|
| answer, citations, contexts (or |
| status and backend info |
Interactive docs live at /docs.
MCP
Two tools, search_docs(query, k, mode) and ask(question, k). Example client config:
{
"mcpServers": {
"neonrecall": {
"command": "/path/to/neonrecall/.venv/bin/neonrecall",
"args": ["mcp", "--db", "/path/to/neonrecall.db"]
}
}
}▸ How retrieval works
query ─┬─► embed ──► vector top-N (cosine) ─┐
│ ├─► RRF fuse ─► [rerank] ─► top-k ─► answer + [n] cites
└─► BM25 top-N ──────────────────────┘Chunking. Markdown is split at headings (code fences are respected), and each chunk keeps a breadcrumb such as
Tape Archiving > Sticky-shed syndrome. Sections are packed paragraph by paragraph, then sentence by sentence, into ~800-character chunks that overlap by ~120 characters on word boundaries. The breadcrumb is prepended at embed time.Hybrid search. Dense and BM25 candidates are fused with Reciprocal Rank Fusion, so no score calibration is needed. Exact terms like part numbers, error codes and
24 PPQNare caught by BM25; paraphrases are caught by the vectors.Reranking (optional).
lexicalscores query-term coverage and proximity offline;httpcalls a cross-encoder such asbge-rerankerbehind a/rerankendpoint.Answering. Passages are numbered and the model is told to cite them. Citations are parsed back out of the text and mapped to source, heading and snippet. The offline extractive answerer picks the most query-relevant sentences and cites each one.
The BM25 index is built in-process from the store and rebuilt when the store's revision counter changes. That suits corpora up to tens of thousands of chunks. Beyond that, move keyword search into Postgres.
▸ Evals
evals/corpus/ holds a small fictional night-shift studio handbook (CRTs, synths, tape,
neon). evals/qa.jsonl holds 28 questions labelled with their relevant documents.
neonrecall eval -k 5config recall@5 MRR hit@5 n
───────────────────────────────────────────────
bm25 1.000 1.000 1.000 28
vector 0.982 0.964 1.000 28
hybrid 1.000 1.000 1.000 28
hybrid+rerank 1.000 1.000 1.000 28These numbers use the offline hashing embedder. CI fails if recall@5 drops below 0.9 or MRR
below 0.85. The set is small on purpose: it's a regression tripwire, not a benchmark. Add
your own corpus and QA file with --corpus and --qa to measure your setup.
▸ Development
pip install -e ".[dev,postgres]"
pytest # offline; the pgvector test is skipped without a database
ruff check . && ruff format --check .
docker compose up -d db
NEONRECALL_TEST_PG_DSN=postgresql://neonrecall:neonrecall@localhost:5432/neonrecall pytest -m postgressrc/neonrecall/
chunking.py heading-aware chunker with overlap
embeddings.py OpenAI-compatible + hashing embedders
store/ sqlite.py (also :memory:), pgvector.py
bm25.py Okapi BM25
retrieval.py hybrid retriever + RRF
rerank.py lexical and HTTP rerankers
generation.py chat + extractive answerers, citation parsing
service.py NeonRecall facade used by every interface
api.py · cli.py · mcp_server.py · evals.py▸ License
MIT. See LICENSE.
Available Tools
2 toolsaskB
Answer a question from the indexed documents. The answer cites passages as [n]; each citation lists its source document.
Inputs: question (required), k. Returns: object
search_docsB
Search the indexed documents. Returns the top-k passages with source, heading and relevance score.
Inputs: query (required), k, mode. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 2 tools
Both tools take a query against the same index, but descriptions clearly separate raw passage retrieval (search_docs) from a synthesized cited answer (ask). The boundary is understandable, though an agent may still hesitate over which to pick for a simple lookup.
search_docs follows a verb_noun pattern while ask is a bare verb, a minor deviation across a two-tool set. Both are lowercase and readable, so the inconsistency is cosmetic rather than confusing.
Two tools is thin for a document recall server; there is no way to browse or fetch a full document. The surface is narrowly scoped but feels under-built for the stated purpose.
Query coverage is good (retrieval plus cited answering), but there is no list_documents or get_document to inspect sources or pull full text, and no ingestion path. These are notable gaps that could cause dead ends when an agent needs a whole document rather than a passage.
Maintenance
Related MCP Connectors
Team docs served to AI agents over MCP - search, Markdown reads, version pinning, read audit.
Query any docs site via MCP. Submit a URL, ask questions, get cited answers.
Query your own PDFs and documents from any MCP client. Every answer cites the page it came from.
Agentic search over your Dewey document collections from any MCP-compatible client.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables grounding AI responses in a local document corpus by exposing MCP tools to list, search, and summarize documents, and generating answers using OpenAI.-
- FlicenseNot gradedqualityDmaintenanceProvides read-only MCP tools for hybrid semantic and keyword search over locally indexed PDF documentation, with citations and context retrieval for LLM agents.-
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to query and manage a document knowledge base via MCP, with RAG-powered search and grounded answers with citations.MIT
- FlicenseNot gradedqualityBmaintenanceEnables users to ingest documentation from URLs or sitemaps, embed it into a searchable vector index, and expose authenticated MCP tools so AI clients can search and retrieve documentation content directly.-