neonrecall
OfficialThis server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
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.
This server cannot be deployed
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.-