ai-papers-mcp
# AI Papers Helper
> Search, index, and read academic AI/ML papers β from the terminal or directly inside your AI coding assistant.
AI Papers Helper crawls top-tier AI/ML conference proceedings, indexes them in a local SQLite database with FTS5 search, queries arxiv, and converts paper PDFs into clean markdown for in-depth reading. It ships as both a **CLI** (`papers`) and an **MCP server** (`ai-papers-mcp`), so you can use it standalone or wire it into Claude Code / any MCP-compatible client.
---
## β¨ Features
- **π Conference crawling** β Fetch papers from NeurIPS, ICML, ICLR, CVPR, ICCV, WACV, AAAI, IJCAI, MLSys, ACL, EMNLP with parallel workers and incremental crawl state.
- **π Local search** β SQLite + FTS5 with BM25 ranking (title-weighted) and relevance/date ordering. Missing-abstract penalty keeps results meaningful.
- **π‘ arxiv search** β Live arxiv search via web scraping (default) or the Atom API backend, with date filters (past 12 months, specific year, date range).
- **π PDF β Markdown** β Parse papers through the [MinerU](https://mineru.net) API with content-addressable caching, so each PDF is only parsed once.
- **π TOC & grep** β Extract a paper's table of contents and `grep` specific sections/equations from its full markdown.
- **π€ MCP server** β Expose everything as 4 tools to Claude Code or any MCP client: search the local library, search arxiv, get a paper's TOC, and grep paper content.
- **π§ Smart resolution** β Paper lookup falls back progressively: exact DB match β fuzzy match (`SequenceMatcher`, 0.8 threshold) β arxiv search.
---
## π¦ Installation
Requires **Python 3.12+**.
```bash
# Clone
git clone https://github.com/<your-org>/ai_papers_helper.git
cd ai_papers_helper
# Install as a global tool (exposes `papers` and `ai-papers-mcp` on PATH)
uv tool install --force .
```
This exposes two console scripts:
| Command | Description |
| --------------- | ------------------------------------ |
| `papers` | The CLI app |
| `ai-papers-mcp` | The MCP server |
### Environment variables
| Variable | Default | Description |
| --------------------- | ------- | ------------------------------------------------------------------------ |
| `MINERU_API_KEY` | β | **Required** for PDFβmarkdown parsing. Get one at mineru.net. |
| `ARXIV_BACKEND` | `web` | arxiv backend: `web` (scraping) or `api` (Atom API). |
| `ARXIV_MIN_INTERVAL` | `10.0` | Minimum seconds between arxiv API calls (rate limiting). |
All data lives under `~/.ai_papers_helper/`:
```
~/.ai_papers_helper/
βββ papers.db # SQLite database (FTS5 index)
βββ crawl_state.json # Incremental crawl state
βββ cache/ # HTTP response cache
βββ arxiv_cache/ # arxiv result cache (24h TTL)
βββ papers/ # Parsed markdown (content-addressed by URL hash)
```
---
## π Quick start
### 1. Initialize the database
```bash
papers init
```
### 2. Crawl conference papers
```bash
# Crawl everything new (incremental β skips already-crawled years)
papers update
# Crawl a specific conference and year
papers update --conference acl,emnlp --year 2024
# Force re-crawl a specific source/year
papers update --force --conference cvpr --year 2023
# Tune parallelism
papers update --workers 16
```
### 3. Search
```bash
# Search the local library (default: titles only)
papers search-library "diffusion model"
papers sl "graph neural network" --order-by date
# Titles + full abstracts
papers sl "transformer attention" --full-abs
# Paginate
papers sl "reinforcement learning" --page 2
papers sl "reinforcement learning" --from 31
# Search arxiv
papers search-arxiv "mixture of experts"
papers sa "vision transformer" --sort-by date --date-filter-by past_12
papers sa "llm" --date-filter-by specific_year --date-year 2024
papers sa "diffusion" --date-filter-by date_range --date-from 2024-01 --date-to 2024-06
```
### 4. Read a paper
```bash
# Get the full markdown (creates a /tmp/<title>.md symlink to the cached file)
papers content "Attention Is All You Need"
# Show the table of contents
papers content "Attention Is All You Need" --toc
```
---
## π§© Skill (for AI coding agents)
The repo ships a ready-made [Agent Skills](https://agentskills.io) skill at [`papers-skill/SKILL.md`](./papers-skill/SKILL.md). It teaches AI coding agents ([pi](https://pi.dev/), Claude Code, etc.) how to drive the `papers` CLI: when to prefer the local library vs arxiv, the `search -> content -> grep` workflow, and the full option reference.
The agent loads the skill on-demand when a task matches, then runs `papers` itself via the shell - no server process required. This is the lightest-weight way to let an agent search and read papers.
### Install the skill
Point your agent at the `papers-skill` directory. For pi:
```bash
# Global (available in every project)
ln -s "$(pwd)/papers-skill" ~/.pi/agent/skills/papers
# Or project-level
mkdir -p .pi/skills && ln -s "$(pwd)/papers-skill" .pi/skills/papers
```
> **Skill vs MCP:** The skill is just instructions (the agent runs the CLI via shell); the MCP server below exposes typed tools. The skill needs nothing running, the MCP server gives more structured tool calls - pick whichever fits your agent.
---
## π€ Using the MCP server
The same functionality is exposed as an MCP server for use inside Claude Code or any MCP-compatible client.
### 4 tools
| Tool | Description |
| ----------------------- | --------------------------------------------------------------------------- |
| `search_library_papers` | Search the local indexed database by keywords. |
| `search_arxiv_papers` | Search arxiv for the latest papers, with date filters. |
| `get_paper_toc` | Get a paper's table of contents. **Call this first** before reading. |
| `grep_paper_content` | `grep` patterns in a paper's full markdown (e.g. read a whole section). |
---
## π Architecture
```
src/ai_papers_helper/
βββ cli.py # Typer CLI: init, search-library, search-arxiv, update, content
βββ mcp_server.py # FastMCP server exposing 4 tools
βββ config.py # Paths, env vars, page-size constants
βββ core/
β βββ models.py # Pydantic v2: Author, Paper
β βββ database.py # SQLite + FTS5 singleton, BM25 ranking, auto-sync triggers
βββ crawler/
β βββ base.py # BaseCrawler ABC + parallel detail-page fetching
β βββ http.py # Shared requests.Session w/ retry + file cache
β βββ state.py # CrawlState (per-source crawled years, JSON)
β βββ cvf.py # CVPR / ICCV / WACV
β βββ aaai.py # AAAI
β βββ ijcai.py # IJCAI
β βββ icml.py # ICML URL helpers
β βββ acl_anthology.py # ACL / EMNLP (ACL Anthology)
β βββ json_api.py # Generic JSON API crawler (NeurIPS, ICML, ICLR, MLSys)
βββ search/
β βββ library_search.py # Local FTS5 search, relevance/date ordering
β βββ arxiv_search.py # arxiv dispatcher (web vs api backend)
βββ retrieval/
β βββ resolver.py # Progressive lookup: exact β fuzzy β arxiv
β βββ parser.py # MinerU API client (async polling, content-addressed cache)
β βββ content.py # Markdown TOC extraction + section slicing
β βββ lookup.py # End-to-end: title β paper β markdown
βββ helper/ # arxiv web/api internals, pagination, rate limiting
```
### How search works
- **Local library**: FTS5 with `porter unicode61` tokenizer. BM25 with title weight `10.0`, abstract weight `1.0`. Results with missing abstracts are penalized (`* 0.9`) so well-documented papers surface first.
- **Date ordering**: BM25 rank is bucketed into relevance tiers; within a tier, newer papers come first β so you don't lose relevance entirely.
- **arxiv**: Web scraping by default (no API key, gentler). Switch to the Atom API with `ARXIV_BACKEND=api` for query-syntax power (field prefixes, boolean operators).
### How PDF reading works
1. Resolve the paper by title (DB exact β fuzzy β arxiv).
2. Resolve a PDF URL (`paper.pdf_url`, else arxiv lookup, backfilling the DB).
3. Send to MinerU; poll until `done`; download & unzip the result.
4. Cache under `~/.ai_papers_helper/papers/{sha256(url)[:16]}/full.md` β content-addressed, so re-reads are instant.
---
## π§ͺ Development
```bash
uv sync # install deps
pytest # run the full suite
pytest tests/test_database.py # single file
pytest -k "fuzzy" # by name pattern
```
Tests use temp databases, mock network calls (`patch.object(crawler, "_fetch_url", ...)`), and HTML/JSON fixtures in `tests/fixtures/`. See [`CLAUDE.md`](./CLAUDE.md) for the full contributor guide.
### Conventions
- Python 3.12+, `from __future__ import annotations` in every file
- No async; parallelism via `ThreadPoolExecutor`
- Standard-library `sqlite3` (no ORM), `requests` for HTTP
- Logging via `logging.getLogger(__name__)`
---
## π License
MIT
TDQS
Scored across 4 tools
The two search tools (search_library_papers and search_arxiv_papers) are clearly differentiated by their source (local vs arxiv), and the paper-reading tools (get_paper_toc and grep_paper_content) serve distinct purposes. Minor potential for confusion exists between the two search tools, but descriptions clarify the difference.
All tool names follow a consistent verb_noun pattern using snake_case (search_library_papers, get_paper_toc, search_arxiv_papers, grep_paper_content). The verbs vary but the structure is uniform and predictable.
Four tools is well-scoped for the server's purpose: two search tools cover different paper sources, and two tools support reading specific paper content. The count is neither sparse nor bloated.
The core workflow of finding papers and reading their content is covered. Minor gaps exist, such as lack of a tool to retrieve the full paper text directly (only grep-based section extraction) or list all papers in the local library, but these are workable limitations.