$ show openags/paper-search-mcp
This repository implements a Model Context Protocol (MCP) server and CLI for searching, downloading, and reading academic papers across ~20 scholarly platforms (arXiv, PubMed, Semantic Scholar, CrossRef, OpenAlex, Google Scholar, etc.). It is primarily an applicationβa Python package distributed via PyPIβthat exposes two entry points: an MCP server (stdio-based, compatible with Claude Desktop and other MCP clients) and a command-line interface. The architecture follows a clean two-layer design: a unified tool layer (search_papers, download_with_fallback) that orchestrates concurrent multi-source searches with deduplication, and a modular connector layer where each platform is implemented as a self-contained class inheriting from a common PaperSource abstract base. The system emphasizes a 'free-first' strategy, relying on open public APIs and optional API keys for enhanced access. It includes a fallback chain for PDF downloads (native source β OA repositories β Unpaywall β Sci-Hub) and supports full-text extraction via pypdf. The codebase is well-structured with consistent patterns (Paper dataclass, env config, retry/backoff), comprehensive test coverage (unit and e2e), and CI/CD publishing. However, some connectors are skeletons (IEEE, ACM) or not wired (ChemRxiv), and HTML scraping components are fragile to upstream changes. The last commit date is anomalously in the future (2026-08-17), but the repository shows active issue triage and community engagement.
The LLM identified 5 files worth highlighting for reuse:
Defines the PaperSource abstract base class that standardizes the interface for all academic platform connectors. It declares three methods: search(), download_pdf(), and read_paper(), with default implementations that raise NotImplementedError for unsupported capabilities. This pattern enables uniform treatment of diverse APIs (REST, XML, HTML scraping) and simplifies the addition of new sources. The class is self-contained, depends only on the Paper dataclass, and can be extracted as a reusable contract for any multi-source search system.
Implements the Paper dataclass with fields for paper_id, title, authors, abstract, doi, published_date, pdf_url, url, source, and optional metadata. Provides a to_dict() method for consistent JSON serialization used by both the CLI and MCP server. This normalized model decouples internal representation from output format and is easily reusable in any project that needs to represent scholarly articles.
Handles environment configuration with a get_env() function that supports prefixed keys (PAPER_SEARCH_MCP_*) with legacy unprefixed fallback, and automatic .env file loading from a standard path (~/.config/paper-search-mcp/.env) or a custom path via PAPER_SEARCH_MCP_ENV_FILE. This pattern is self-contained, idiomatic for Python applications, and can be reused in any project needing structured env-based configuration.
Provides the extract_doi() function that uses a regex pattern to extract DOIs from text (abstracts, URLs). It is used pervasively across connectors to recover DOIs when APIs do not return them directly. The function is small, well-tested, and can be extracted as a standalone utility for any project that needs to parse DOIs from unstructured text.
Implements a generic OAI-PMH searcher (OAIPMHSearcher) that queries repositories using the OAI-PMH protocol with ListRecords and GetRecord verbs. It handles resumption tokens, date-based filtering, and parses Dublin Core metadata into Paper objects. This class is used by the BASE connector and can be reused for any OAI-PMH-compliant repository with minimal configuration (endpoint URL, metadata prefix).