{
  "markdown": "# scholar-rag-mcp\n\n<!-- mcp-name: io.github.notwhiteblank/scholar-rag-mcp -->\n\n> **Status: preview release (v0.4.0).** Interfaces and storage layout may change in future versions.\n\n**scholar-rag-mcp** is a publishable academic-paper knowledge-base MCP tool. Point it at a\nfolder of PDFs and it ingests each paper through a real parsing pipeline (MinerU), normalizes\nmetadata, annotates section structure, chunks and embeds the text, and stores everything in\nQdrant - after which an agent (or you) can semantically search chunks, run PubMed-style\ndocument queries, read full text section by section, add/remove single papers, and manage\nknowledge bases - all through 11 MCP tools over stdio. Embedding, annotation and re-ranking\nrun on OpenAI-compatible model services (e.g. vLLM).\n\n## Features\n\n- **Real ingestion pipeline**: MinerU PDF parsing (python/cli/api backends) -> metadata\n  extraction (local heuristics, CrossRef, optional GROBID) -> cleaning -> section annotation\n  -> deterministic chunking (configurable 300/1500/100 chars) -> embedding.\n- **Fast retrieval at scale**: embedding first-pass + cross-encoder re-rank, optional\n  metadata filtering (`doc_id`, `section`, `year`, `journal`, ...) evaluated inside the Qdrant\n  index. 100k-chunk p95 query latency < 1s (see `docs/perf-report.md`).\n- **Async jobs**: `create_kb`/`add_document` are background jobs with progress queryable via\n  `get_job`; safe to restart (interrupted jobs are recovered and skipped on re-run).\n- **Context-safe reading**: paginated `get_document_text` with hard size caps; *outline first,\n  pages on demand*.\n- **11 MCP tools** over stdio: `list_kbs`, `create_kb`, `delete_kb` (two-phase), `add_document`,\n  `remove_document`, `get_document`, `get_document_text`, `list_documents`, `search_documents`,\n  `search_chunks`, `get_job`.\n- **Self-contained storage**: knowledge bases live under a single data directory\n  (default location is platform-specific, see Data layout); Qdrant is either auto-launched\n  (single binary, version-pinned) or connected to an external instance.\n\n## Installation\n\nscholar-rag-mcp runs on Linux x64, Windows x64 and macOS (Intel and Apple Silicon).\nIt is published on PyPI; the standard way to run it is with\n[uv](https://docs.astral.sh/uv/) (a suitable Python 3.12 is fetched automatically):\n\n```bash\nuvx scholar-rag-mcp             # download and start the MCP server (stdio)\n```\n\nNo repository checkout is needed. Configure model endpoints and storage with\n`SCHOLAR_RAG_*` environment variables or `<data_dir>/config.json` (see\n`.env.example`); the Qdrant binary used for auto-launch is downloaded per\nplatform on first use.\n\n### One-click install / uninstall\n\n```bash\nuvx scholar-rag-mcp install --with-mineru # install via uv, provision managed MinerU, register MCP clients\nuvx scholar-rag-mcp install              # MCP only; bring your own parse service (see PDF parsing)\nscholar-rag-mcp uninstall                # unregister clients and remove the package\n```\n\n`uvx scholar-rag-mcp install` installs the package via `uv tool install` and interactively\nwalks through the six model-endpoint settings (`chat`/`embed`/`rerank` base URLs and model\nnames), using the defaults listed in Minimal environment unless a `SCHOLAR_RAG_*` value or a\n`--chat-base-url` / `--chat-model` / `--embed-base-url` / `--embed-model` /\n`--rerank-base-url` / `--rerank-model` flag is given; `--yes` accepts all defaults without\nprompting. It then detects the four supported MCP clients (Claude Desktop, Claude Code,\nopencode, Codex) and registers the tool by merging the `scholar-rag-mcp` entry into their\nuser-level configs, touching only that entry; pass `--client <name>` to register a single\nclient. Configs that cannot be parsed (e.g. JSON with comments) are left untouched and a\nmanual snippet is printed instead.\n\n`scholar-rag-mcp uninstall` removes the `scholar-rag-mcp` entry from the detected clients and\nruns `uv tool uninstall`; the knowledge-base data directory is kept. `--purge` additionally\ndeletes the data directory after explicit confirmation (skip the prompt with `--yes`).\n\n### From source (development)\n\nRequires [pixi](https://pixi.sh). From the repository root:\n\n```bash\npixi install                      # installs the default environment\n```\n\nThe pixi environments are locked for all four supported targets. The project\ndefines two pixi environments, each serving a different purpose:\n\n| Environment | Purpose |\n|---|---|\n| `default` | Core runtime + dev tooling (pytest/ruff/mypy). Run the MCP server and all scripts here. |\n| `mineru` | Adds MinerU (`==3.4.5`) plus its full runtime stack (pinned `transformers<5`, torch, onnxruntime, shapely, ...). Use for PDF parsing and the e2e smoke test. |\n\nVerify your environment with the built-in doctor:\n\n```bash\npixi run python scripts/doctor.py\n```\n\n## Model deployment\n\nEnvironment ('chat', 'embed' and 'rerank' clients) expects OpenAI-compatible HTTP endpoints.\n`scripts/serve_models.sh` launches three vLLM instances for the reference model set:\n\n| Service | Model | Port |\n|---|---|---|\n| chat | Qwen3.5-0.8B | 8101 |\n| embed | jina-embeddings-v5-text-small | 8102 |\n| rerank | jina-reranker-v3.5 | 8103 |\n\n```bash\n# point *_MODEL at your local model directories, then:\nbash scripts/serve_models.sh\n```\n\n`SCHOLAR_RAG_CHAT_MODEL`, `SCHOLAR_RAG_EMBED_MODEL` and `SCHOLAR_RAG_RERANK_MODEL` are\n**required** - the script exits with a message listing them if any is unset. Each value must\nbe an absolute path to a local HuggingFace model directory; vLLM serves each model under a\nshort name equal to the directory basename, so the client settings must use that short name\n(the served name no longer equals the full path). Replace the `/path/to/...` placeholders in\n`.env.example` accordingly. Ports (`CHAT_PORT`/`EMBED_PORT`/`RERANK_PORT`) and GPU ids remain\noptional with working defaults.\n\nThe script passes the vLLM flags verified for the default model set, notably\n`--trust-remote-code`, which all three models require on the pinned vLLM (0.27.1). Model load\ntakes several minutes; the script polls health until all three answer.\n\n`scripts/serve_models.sh` is **Linux-only** (bash + CUDA + vLLM; vLLM has no Windows\nsupport). On Windows/macOS point the `*_BASE_URL` settings at any OpenAI-compatible\nserver instead - for example Ollama (`http://127.0.0.1:11434/v1`), LM Studio's local\nserver, or a llama.cpp server - and set each `*_MODEL` to the model name that server\nreports. The rerank endpoint must expose `/v1/rerank` (or leave reranking to the\nembed-only fallback).\n\n### Minimal environment\n\nStart from `.env.example` and set at least the model endpoints (use the short names the\nserve script exposes, equal to each model directory's basename):\n\n```env\n# data dir is optional - defaults to the platform data directory (see Data layout)\n# SCHOLAR_RAG_DATA_DIR=\n# SCHOLAR_RAG_QDRANT_STORAGE_DIR=\n\nSCHOLAR_RAG_CHAT_BASE_URL=http://127.0.0.1:8101/v1\nSCHOLAR_RAG_CHAT_MODEL=Qwen3.5-0.8B\n\nSCHOLAR_RAG_EMBED_BASE_URL=http://127.0.0.1:8102/v1\nSCHOLAR_RAG_EMBED_MODEL=jina-embeddings-v5-text-small\n\nSCHOLAR_RAG_RERANK_BASE_URL=http://127.0.0.1:8103/v1\nSCHOLAR_RAG_RERANK_MODEL=jina-reranker-v3.5\n```\n\nThe embed model dimension is recorded in `kb_meta.json` at kb creation, so changing the\nembedding model later requires a new kb.\n\n## PDF parsing (MinerU)\n\nSince v0.4.0 the default parse backend is `api`. The recommended setup is the\nmanaged sidecar, which installs MinerU into an isolated Python 3.12 venv\n(MinerU requires Python >=3.10,<3.14) and auto-starts `mineru-api` on first\nparse:\n\n```bash\nscholar-rag-mcp install --with-mineru\n```\n\nThe first parse triggers MinerU's model download; set\n`MINERU_MODEL_SOURCE=modelscope` if you need a China-friendly mirror.\n\nSelf-managed alternative: install MinerU in any Python 3.12 environment, run\n`mineru-api --host 127.0.0.1 --port 8010`, and keep the defaults\n(`SCHOLAR_RAG_MINERU_BACKEND=api`, `SCHOLAR_RAG_MINERU_API_URL=http://127.0.0.1:8010`).\n\nThe `python` backend (in-process import) and `cli` backend (subprocess per\nfile) remain available via `SCHOLAR_RAG_MINERU_BACKEND`.\n\n## MCP client setup\n\nPoint your MCP client at the `uvx` entry point and configure the model endpoints\nin the `env` block (any OpenAI-compatible server works; see Model deployment).\nTo check that the server starts, run `uvx scholar-rag-mcp` in a terminal - it\nwaits for an MCP client on stdio (Ctrl+C to exit).\n\n### Claude (Claude Desktop / claude CLI)\n\n```json\n{\n  \"mcpServers\": {\n    \"scholar-rag-mcp\": {\n      \"command\": \"uvx\",\n      \"args\": [\"scholar-rag-mcp\"],\n      \"env\": {\n        \"SCHOLAR_RAG_CHAT_BASE_URL\": \"http://127.0.0.1:8101/v1\",\n        \"SCHOLAR_RAG_CHAT_MODEL\": \"Qwen3.5-0.8B\",\n        \"SCHOLAR_RAG_EMBED_BASE_URL\": \"http://127.0.0.1:8102/v1\",\n        \"SCHOLAR_RAG_EMBED_MODEL\": \"jina-embeddings-v5-text-small\",\n        \"SCHOLAR_RAG_RERANK_BASE_URL\": \"http://127.0.0.1:8103/v1\",\n        \"SCHOLAR_RAG_RERANK_MODEL\": \"jina-reranker-v3.5\"\n      }\n    }\n  }\n}\n```\n\n### opencode\n\n```json\n{\n  \"$schema\": \"https://opencode.ai/config.json\",\n  \"mcp\": {\n    \"scholar-rag-mcp\": {\n      \"type\": \"local\",\n      \"command\": [\"uvx\", \"scholar-rag-mcp\"],\n      \"environment\": {\n        \"SCHOLAR_RAG_CHAT_BASE_URL\": \"http://127.0.0.1:8101/v1\",\n        \"SCHOLAR_RAG_CHAT_MODEL\": \"Qwen3.5-0.8B\",\n        \"SCHOLAR_RAG_EMBED_BASE_URL\": \"http://127.0.0.1:8102/v1\",\n        \"SCHOLAR_RAG_EMBED_MODEL\": \"jina-embeddings-v5-text-small\",\n        \"SCHOLAR_RAG_RERANK_BASE_URL\": \"http://127.0.0.1:8103/v1\",\n        \"SCHOLAR_RAG_RERANK_MODEL\": \"jina-reranker-v3.5\"\n      }\n    }\n  }\n}\n```\n\nRunning from a source checkout instead: use `pixi run scholar-rag-mcp` as the\ncommand (from the repository root) and set the same variables in your shell.\n\n## Tools\n\n| Tool | Purpose |\n|---|---|\n| `list_kbs` | List knowledge bases with document/chunk counts and status. |\n| `create_kb` | Asynchronously ingest every PDF in a folder into a new kb (returns `job_id`). |\n| `delete_kb` | Two-phase kb deletion (see below). |\n| `add_document` | Asynchronously ingest a single PDF into an existing kb (returns `job_id`). |\n| `remove_document` | Synchronously delete one document (Qdrant points + catalog + files). |\n| `get_document` | Document overview: metadata, abstract, section outline, total size. |\n| `get_document_text` | Paginated full-text reading of one document or a single section. |\n| `list_documents` | Paginated browse of documents in a kb. |\n| `search_documents` | PubMed-style document-level search (FTS + title/authors/journal/year). |\n| `search_chunks` | Semantic chunk search with metadata filters and embed+rerank scores. |\n| `get_job` | Query status/progress/result/elapsed time of a background job. |\n\n## Data layout\n\n```\n<data_dir>/                     # SCHOLAR_RAG_DATA_DIR, default: platform data dir (below)\n├── kbs/<kb_name>/\n│   ├── kb_meta.json            # dimension, chunk config, schema version\n│   ├── catalog.sqlite3         # documents / authors / keywords / chunks + FTS5\n│   └── documents/<doc_id>/     # source.pdf, full_text.md, sections.json\n├── cache/parse/                # MinerU markdown cache, keyed by content hash\n├── cache/resolver/             # annotation resolver cache, keyed by content hash\n├── jobs.sqlite3                # async job history\n├── bin/                        # auto-downloaded Qdrant binary (v1.12.5)\n└── qdrant-storage/             # default QDRANT_STORAGE_DIR location\n```\n\nDefault `data_dir` per platform (override with `SCHOLAR_RAG_DATA_DIR`):\n\n| Platform | Default |\n|---|---|\n| Linux | `$XDG_DATA_HOME/scholar-rag` (falls back to `~/.local/share/scholar-rag`) |\n| macOS | `~/Library/Application Support/scholar-rag` |\n| Windows | `%LOCALAPPDATA%\\scholar-rag` |\n\nQdrant storage defaults to `<data_dir>/qdrant-storage` (override with\n`SCHOLAR_RAG_QDRANT_STORAGE_DIR`) - it must be on a local filesystem, not a 9p/network\nmount.\n\n**Upgrading from v0.1.0 on Linux**: the old defaults (`~/.scholar-rag` and\n`~/.local/share/scholar-rag/qdrant`) are migrated automatically on first start; if the\nnew location already has data, migration is skipped with a warning and the old files\nare left untouched.\n\n### Two-phase kb deletion\n\n`delete_kb` never deletes on the first call with the wrong arguments by accident:\n\n1. Call `delete_kb(kb=\"...\")` - returns kb statistics plus a 10-minute `confirm_token`.\n2. Call `delete_kb(kb=\"...\", confirm_token=\"<token>\")` to actually delete the Qdrant\n   collection, kb directory and its job history.\n\n## Development\n\n```bash\npixi run lint          # ruff check src tests\npixi run typecheck     # mypy src\npixi run test          # pytest (unit + integration, no e2e/perf)\npixi run -e mineru pytest tests/e2e/smoke.py -v -m e2e   # real end-to-end smoke\npython tests/perf/bench_query.py                          # query latency benchmark (writes docs/perf-report.md)\n```\n\n## Release notes\n\nFor known limitations and upgrade guidance see\n`docs/handoffs/release-notes-v0.4.0.md`,\n`docs/handoffs/release-notes-v0.3.0.md` and\n`docs/handoffs/release-notes-v0.2.1.md`.\n\nKnown constraints worth repeating:\n\n- **Qdrant is pinned to v1.12.5** - it is the highest version that runs on glibc 2.35;\n  auto-launch downloads it on first use. On glibc >= 2.38 you may run a newer version, but the\n  data format is not forward-compatible with older kbs in this release.\n- **MinerU runs in its own pixi environment** because its transformers version is mutually\n  exclusive with the vLLM one. PDF parsing thus prefers `pixi run -e mineru`.\n- **MinerU weights** (~3.2 GB) download on first parse into `~/.cache/modelscope/`.\n- **Metadata title heuristic**: titles are only picked locally when the MinerU markdown starts\n  with an `#`/`##` heading, so a leading `## Abstract` (etc.) can be misread as the title. This\n  affects the local-heuristic metadata tier only; the CrossRef tier (used when a DOI is found)\n  normally corrects it.\n- **Tool dispatch**: unknown extra arguments to a tool are silently ignored rather than\n  rejected.\n- **9p storage limit**: Qdrant storage must be on a local filesystem.\n- **Platform support**: Linux x64 / Windows x64 / macOS Intel+Apple Silicon. The vLLM\n  deployment script is Linux-only; Windows/macOS use any OpenAI-compatible server.\n- **Windows long paths**: deep data directories can hit the 260-char limit; keep\n  `SCHOLAR_RAG_DATA_DIR` shallow or enable Windows long path support.\n- **macOS x64 CI**: covered at code level only; GitHub x64 macOS runners require\n  larger-runner billing, so the CI matrix runs macOS arm64 (`macos-latest`).",
  "bytes": 14541,
  "sha": "514a9fa4bd0cec210c7f6c58e325c77e8b15a14a02b9f1fa77d618dbf4a21cac",
  "repo_slug": "notwhiteblank/scholar-rag-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_notwhiteblank_scholar_rag_mcp_395761f5/readme"
}