rag-paper
Exports citation graphs as Mermaid Markdown for use in Obsidian, enabling visualization of paper relationships within the Obsidian note-taking environment.
Provides integration with Ollama embedding models for generating paper embeddings locally, supporting models like qwen3-embedding:4b.
Supports OpenAI-compatible embedding endpoints for generating paper embeddings, allowing use of OpenAI's embedding models or compatible services.
Allows indexing PDFs from Zotero storage and export directories, integrating with Zotero reference management workflow.
Click on "Install 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., "@rag-papersearch for 'retrieval augmented generation'"
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.
rag-paper
Local-first paper RAG for PDF research workflows.
rag-paper helps you build a private, local, searchable paper library from PDF files. It parses PDFs, chunks paper text, creates embeddings, stores vectors in local Chroma, and exposes retrieval through a CLI and MCP server for tools such as Codex CLI and Claude Code.
It is designed for researchers, students, engineers, and LLM power users who want to read papers efficiently while saving tokens and using affordable models such as DeepSeek, Qwen, local Ollama embeddings, or OpenAI-compatible embedding services.
Keywords
paper RAG, local RAG, PDF RAG, academic search, Chroma, MCP server, Codex CLI, Claude Code, Zotero, Obsidian, citation graph, Mermaid, DOI enrichment, CrossRef, OpenAlex, semantic deduplication, local vector database, research assistant, low-cost LLM workflow
Related MCP server: paper-intelligence
Why rag-paper
Token-efficient paper reading: retrieve only relevant chunks instead of sending whole PDFs to an LLM.
Local-first storage: vectors and metadata are stored locally in Chroma.
MCP ready: expose paper search tools to Codex CLI, Claude Code, and other MCP clients.
Low-cost model friendly: use local Ollama embeddings by default, or an OpenAI-compatible embedding endpoint.
Zotero friendly: point
root_pathto one or more Zotero storage/export directories.Obsidian friendly: export citation graphs as Mermaid Markdown.
Privacy controls: use
skip_marker_fileto prevent sensitive folders from being indexed.
Requirements
Python 3.10+
A local or remote embedding provider
Default embedding setup: Ollama with
qwen3-embedding:4b
ollama pull qwen3-embedding:4bInstallation
git clone https://github.com/your-name/rag-paper.git
cd rag-paper
python -m venv .venv
source .venv/bin/activate
pip install -e .Windows PowerShell:
git clone https://github.com/your-name/rag-paper.git
Set-Location rag-paper
py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -e .Quick Start
Create a config file:
rag-paper init-config --path ./config.jsonPut PDFs under ./papers, or edit config.json and point papers[].root_path to your own directories.
Index PDFs:
rag-paper indexSearch locally:
rag-paper search "retrieval augmented generation evaluation" --top-k 5Inspect indexed papers:
rag-paper list-indexed-papers
rag-paper show-indexed-paper "attention" --limit 3Delete a bad indexed record:
rag-paper delete-indexed-paper "10.55277/researchhub.x9vnpm0y.1"
rag-paper build-citation-graphStart the MCP server:
rag-paper serveBy default this starts the MCP service with streamable-http on http://127.0.0.1:8765/mcp.
For stdio clients, start it with rag-paper serve --transport stdio.
Tech Stack
Python 3.10+: typed CLI application and local service runtime.
Click + Rich: cross-platform command-line interface, confirmation prompts, and terminal tables.
PyMuPDF: PDF text extraction and PDF metadata reading.
ChromaDB: local persistent vector database for paper chunks.
Ollama embeddings: default local embedding provider using
qwen3-embedding:4b.OpenAI-compatible embeddings: optional remote embedding backend.
Rank BM25: keyword retrieval path for hybrid search.
httpx: CrossRef/OpenAlex metadata requests with HTTP, HTTPS, and SOCKS5 proxy support.
SQLite: metadata enrichment cache to reduce repeated provider requests.
MCP Python SDK: exposes paper search and inspection tools to Codex CLI, Claude Code, and other MCP clients.
Pydantic: configuration validation and migration for older config shapes.
structlog: structured logs for indexing, enrichment, search, and failures.
Modules
Indexing
rag-paper index scans configured PDF roots, respects skip_marker_file, extracts text, chunks papers, creates embeddings, and writes chunks to Chroma. Before vectorization it shows the number of files and the root paths they came from unless --yes or indexing.assume_yes is enabled.
Indexing is incremental. rag-paper stores size + mtime_ns in the manifest and only computes SHA256 when the quick file signature changes. Failed files are recorded in a JSONL log and can be retried with rag-paper index --retry-failed.
rag-paper index --update-metadata-only does not re-vectorize. It refreshes each indexed chunk's metadata (title, DOI, authors, …) from paper_metadata.json in place, so changes from enrich-metadata become visible to search without recomputing embeddings. Run it after enrich-metadata; chunk text (including abstract-chunk text) is not changed.
Search and Retrieval
rag-paper search performs local hybrid retrieval over indexed chunks. It combines vector similarity from Chroma with BM25 keyword matching, then returns compact source-aware excerpts that are suitable for sending to an LLM instead of whole PDFs.
Search supports filters such as author, year, tag, and file name. The same retrieval engine powers the MCP tools.
Optionally enable a reranker (reranker.enabled) to re-score the top candidates by a continuous P(yes) relevance score read from the model's yes/no token logprobs (Qwen3-Reranker style, e.g. dengcao/Qwen3-Reranker-4B via Ollama); relevant chunks are promoted above spurious lexical/vector matches. It adds latency proportional to the candidate count, so keep reranker.top_k modest.
Indexed Paper Inspection
rag-paper list-indexed-papers shows the current Chroma library as a terminal table, including total paper count, chunk count, title, DOI, year, and source path.
rag-paper show-indexed-paper supports fuzzy selectors over title, file name, source path, and DOI. It shows merged metadata and the first 5 chunk IDs by default; use --all-chunks to show every chunk ID.
rag-paper delete-indexed-paper deletes matching papers from Chroma and the index manifest. Without --yes, every matched paper must be confirmed one by one before deletion. After deleting indexed papers, run rag-paper build-citation-graph to refresh citation graph exports.
Metadata Enrichment
rag-paper enrich-metadata enriches indexed papers with DOI and bibliographic metadata. It supports CrossRef and OpenAlex, provider fallback, rate limiting, custom User-Agent, contact email, and HTTP/HTTPS/SOCKS5 proxies.
The enrichment module is decoupled from vectorization. It can run per indexed file, after indexing finishes, or manually. Results are written to paper_metadata.json and provider responses are cached in SQLite.
Title quality checks reject obvious spam, URLs, ad-like strings, and symbol-heavy PDF metadata titles. When a PDF title is not trusted, rag-paper prefers a title inferred from the first page, a provider title, or the file name.
Deduplication
rag-paper dedupe-papers reports duplicate candidates before indexing. It can compare DOI/title-year metadata and optional semantic signatures built from paper text or abstracts. Depending on configuration, duplicates can be reported or skipped.
Citation Graph
rag-paper build-citation-graph builds a graph from enriched DOI/OpenAlex metadata and exports JSON plus Mermaid Markdown. The Mermaid output is designed to work well in Obsidian for browsing paper relationships.
MCP Server
rag-paper serve starts an MCP server so external tools can query the local paper library. The server is query-only: clients can search chunks, find chunks by metadata, list and inspect indexed papers, fetch chunks by id, and export context. Importing, enriching, deduplicating, deleting, and citation-graph builds are CLI-only — the MCP server never mutates the library.
Typical Workflows
Use with Zotero
root_path is an array, so you can point rag-paper at multiple paper folders, including Zotero storage/export folders:
{
"papers": [
{
"root_path": [
"D:/Zotero/storage",
"D:/Zotero/exports/LLM"
],
"skip_marker_file": ".rag-paper-skip",
"tags": ["zotero"]
}
]
}rag-paper recursively scans these roots and indexes only .pdf files.
Protect private folders with skip_marker_file
If a directory contains the configured marker file, rag-paper skips that directory and all of its children.
This is useful for privacy protection. For example, you can place .rag-paper-skip in folders containing unpublished papers, private notes, or papers that should not be exposed through MCP search.
{
"papers": [
{
"root_path": ["./papers"],
"skip_marker_file": ".rag-paper-skip"
}
]
}When a marker is detected, rag-paper highlights the warning and asks whether to continue unless --yes or indexing.assume_yes is enabled.
Back up and restore work
By default, core runtime data is stored under:
rag_paper_data/
chroma_db/
paper_metadata.json
cache/
citation_graph/
logs/Copying rag_paper_data/ is enough to back up the local Chroma vectors, metadata, cache, failure logs, retrieval stats, and citation graph exports when default paths are used.
To restore work on another device:
Install rag-paper.
Copy
rag_paper_data/into the project directory.Copy your
config.jsonif you customized paths.Run
rag-paper list-indexed-papersto verify the restored index.
Build a citation graph for Obsidian
After metadata enrichment, build a citation graph:
rag-paper build-citation-graphrag-paper exports:
JSON graph:
rag_paper_data/citation_graph/citation_graph.jsonMermaid Markdown:
rag_paper_data/citation_graph/citation_graph.md
The Mermaid file can be opened directly in Obsidian or any Markdown tool with Mermaid support.
Metadata Enrichment
rag-paper can enrich indexed papers with DOI and bibliographic metadata.
Supported providers:
CrossRef
OpenAlex
Default order:
{
"metadata_enrichment": {
"providers": ["crossref", "openalex"]
}
}If the first provider fails or returns no match, rag-paper falls back to the next provider.
Run enrichment manually:
rag-paper enrich-metadataRefresh existing metadata:
rag-paper enrich-metadata --forceRefresh one indexed PDF:
rag-paper enrich-metadata --file /path/to/paper.pdf --force--file first checks whether the PDF has already been indexed in local Chroma. If not, rag-paper exits and asks you to index it first.
Re-check DOIs already in metadata and correct mismatches:
rag-paper enrich-metadata --reverify--reverify re-checks every paper that already has a DOI. The stored DOI is treated as unverified and re-checked against the paper's title and year (see below); if it no longer matches, it is dropped and a fresh title search tries to replace it. If no confident replacement is found, the untrusted enrichment fields are cleared (DOI/title/authors/… removed, file/tags kept) instead of being left wrong — the run reports a Cleared files count. Corrections and clears are logged (metadata.reverify_corrected, metadata.cleared_unmatched). --force does the same re-derivation unconditionally for every paper (it re-derives, not just refreshes). Run either after upgrading, or whenever you suspect wrong associations.
Title verification and association safety
To avoid grafting a citation's metadata onto the wrong paper, every lookup is checked against the document's title:
DOIs typed into
paper_metadata.json(doi/url/external_url) are trusted as-is.DOIs mined out of PDF body text are speculative — they are kept only if the returned work's title is similar enough to the paper's title.
Title-search best matches from CrossRef/OpenAlex, and every cache hit, are checked the same way; a low-similarity match is rejected rather than written.
During
--reverify/--force, the reference title is taken from the filename (ZoteroAuthors - Year - Title.pdf), falling back to the PDF first page — never from the stored title (that would be circular). The filename year is cross-checked against the matched work's year (≈2-year slack for preprint→published lag), which rejects near-namesakes (e.g. BERT vs Spectrum-BERT) when the years diverge.If a stored DOI fails these checks and no confident replacement is found, the enrichment fields are cleared (see
--reverifyabove) so wrong data does not persist.
Residual limitation: a different paper with a deliberately similar title and a close or missing year (a true near-namesake) can still slip through and may need a manual edit.
Relevant thresholds (see Configuration Reference):
min_title_similarity(default0.6): title-similarity threshold for accepting a match.min_title_score(default3.0): minimum CrossRef relevance score.min_openalex_score(default0.5): minimum OpenAlex relevance score.
Metadata enrichment uses a SQLite cache by default:
rag_paper_data/cache/metadata_enrichment.sqlite3This avoids repeatedly calling CrossRef/OpenAlex for the same DOI or title query.
When a provider returns an abstract (OpenAlex), it is indexed as its own searchable chunk alongside the paper's body chunks, so abstract-level matches surface in search_papers / rag-paper search. Abstracts are written during indexing (per-file/after-index enrichment) and via enrich-metadata; papers enriched before this feature need a re-index or re-enrich to pick up the abstract chunk.
MCP Usage
Start the MCP server:
rag-paper serverag-paper supports both MCP transports below:
streamable-http: enabled by default throughmcp.transportinconfig.json; use this for long-running HTTP MCP clients.stdio: supported for process-managed MCP clients such asagent-infra/mcp-hub; pass--transport stdioso startup status is written to stderr and stdout remains reserved for MCP protocol messages.
Streamable HTTP configuration example:
{
"mcpServers": {
"rag-paper": {
"url": "http://127.0.0.1:8765/mcp"
}
}
}stdio configuration example:
{
"mcpServers": {
"rag-paper": {
"command": "rag-paper",
"args": ["serve", "--transport", "stdio"]
}
}
}Available MCP tools (all read-only):
search_papers— hybrid BM25 + vector search over chunks; supportsgroup_by_paper(best chunk per paper) andmax_text_chars(compact snippets)search_by_metadata— find chunks by author/year/tag/file name; supportsgroup_by_paperandmax_text_charslikesearch_papersget_chunk— fetch one chunk by idexport_context— export selected chunks as a Markdown context blocklist_indexed_papers— list indexed papersshow_indexed_paper— inspect a paper's metadata and chunk idsget_paper_citations— locally-resolved references (outgoing + incoming) for one paperservice_info— service configuration
The server exposes no write tools. Use the CLI (rag-paper index, enrich-metadata, dedupe-papers, delete-indexed-paper, build-citation-graph) for anything that mutates the library.
CLI Commands
rag-paper init-config
rag-paper index
rag-paper index --force
rag-paper index --file /path/to/paper.pdf
rag-paper index --only-new
rag-paper index --retry-failed
rag-paper enrich-metadata
rag-paper list-indexed-papers
rag-paper show-indexed-paper "selector"
rag-paper delete-indexed-paper "selector"
rag-paper search "query"
rag-paper dedupe-papers
rag-paper build-citation-graph
rag-paper serveNotes on Indexing
rag-paper stores indexing state in:
rag_paper_data/chroma_db/index_manifest.jsonIt uses a two-stage change check:
Compare
size + mtime_ns.Compute SHA256 only when the quick check changed.
If indexing fails for a PDF, rag-paper records the failure in:
rag_paper_data/logs/index_failed.jsonlRetry failed files:
rag-paper index --retry-failedIf you press Ctrl+C, completed files are already persisted in Chroma and the manifest, so the next run continues from the remaining files.
Development
pip install -e ".[dev]"
python -m pytest -qLicense
This project is licensed under the MIT License. See LICENSE.
Configuration Reference
Common options:
data_dir: core runtime data directory. Default:./rag_paper_datapapers[].root_path: array of PDF root directories. Useful with Zotero folders.papers[].skip_marker_file: marker filename used to skip private directories.papers[].tags: default tags for papers under the root paths.chroma.persist_dir: Chroma persistence directory.indexing.metadata_path: paper metadata JSON path.indexing.assume_yes: skip interactive confirmation.indexing.max_files: maximum PDFs to index.indexing.failed_path: index failure JSONL path.metadata_enrichment.enabled: enable DOI and metadata enrichment.metadata_enrichment.providers: provider order, e.g.["crossref", "openalex"].metadata_enrichment.timing:per_file,after_index, ormanual.metadata_enrichment.user_agent: User-Agent for CrossRef/OpenAlex requests.metadata_enrichment.mailto: contact email for provider etiquette.metadata_enrichment.openalex_email: OpenAlex email parameter.metadata_enrichment.requests_per_second: provider request rate limit.metadata_enrichment.http_proxy: HTTP proxy.metadata_enrichment.https_proxy: HTTPS proxy.metadata_enrichment.socks5_proxy: SOCKS5 proxy.metadata_enrichment.cache_path: SQLite enrichment cache path.metadata_enrichment.min_title_score: minimum CrossRef relevance score for a title match. Default:3.0.metadata_enrichment.min_openalex_score: minimum OpenAlex relevance score for a title match. Default:0.5.metadata_enrichment.min_title_similarity: minimum title similarity (0–1) for accepting a DOI/title match and preventing wrong associations. Default:0.6.reranker.enabled: enable cross-encoder reranking of search results. Default:false.reranker.model: reranker model (Ollama), e.g.dengcao/Qwen3-Reranker-4B:Q5_K_M.reranker.top_k: number of first-stage candidates to rerank per query. Default:20.reranker.concurrency: parallel reranker requests. Default:4(raise Ollama'sOLLAMA_NUM_PARALLELto match).reranker.top_logprobs: number of top candidate tokens sampled for the P(yes) score. Default:10.retrieval.fusion: how vector and BM25 results are fused —rrf(default; reciprocal rank fusion, robust to score distributions) orlinear(weighted score, usesvector_weight/bm25_weight).retrieval.rrf_k: RRF smoothing constant. Default:60.dedup.enabled: enable duplicate report before indexing.dedup.action:reportorskip.dedup.similarity_threshold: semantic duplicate threshold.citation_graph.path: citation graph JSON output.citation_graph.mermaid_path: Mermaid Markdown output for Obsidian.display.datetime_timezone: display timezone formetadata_enriched_at.display.datetime_format:strftimeformat for displayed datetimes.logging.level: log level.logging.stats_path: retrieval stats JSONL path.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityAmaintenanceA local-first MCP server that analyzes research papers, maps citation graphs, and surfaces insights with verbatim-verified contradictions, all while keeping data private on your machine.Last updated1MIT
- Alicense-qualityCmaintenanceA local MCP server for intelligent PDF management that converts papers to markdown and enables hybrid grep and semantic search, allowing token-efficient exploration of academic documents.Last updated6MIT
- Flicense-qualityDmaintenanceAn MCP server for searching and citing research papers using RAG, enabling semantic search, citation finding, and question answering over a collection of PDF papers.Last updated
- Alicense-qualityBmaintenanceLocal-first MCP server for indexing and searching research materials (papers, notes, logs, READMEs) using SQLite FTS, with tools for memory management and evidence retrieval.Last updatedMIT
Related MCP Connectors
Local-first RAG engine with MCP server for AI agent integration.
Academic research MCP server for paper search, citation checks, graphs, and deep research.
Search arXiv/Semantic Scholar/OpenAlex + medical evidence (PubMed/Europe PMC) + LaTeX/PDF tools.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/i1ight/ragPaper'
If you have feedback or need assistance with the MCP directory API, please join our Discord server