"""Federated paper sources. Concrete sources implement `PaperSource` and are registered explicitly below. `federated_search`, `_VALID_SOURCES` in the MCP server, and the `list_sources` tool all read from `REGISTRY`. Adding a new source means adding one module, one class, and one `register_source(...)` call here. The original `sources.py` module-level helper names (`_http`, `_ARXIV_BASE_URL`, `fetch_arxiv`, `fetch_pubmed`, `fetch_semantic_scholar`, the `fetch_s2_*` helpers, and `federated_search`) are re-exported so callers in `core.py` and existing tests keep working unchanged. """ from ._http import _http from .arxiv import ( ArxivSource, _ARXIV_BASE_URL, _ARXIV_CATEGORY_TOPICS, fetch_arxiv, fetch_arxiv_by_id, fetch_arxiv_multi, ) from .base import ( Capability, PaperSource, RateLimitHint, REGISTRY, _paper_dict, paper_dict, register_source, unregister_source, ) from .federated import federated_search from .openalex import ( OpenAlexSource, fetch_openalex, fetch_openalex_by_id, fetch_openalex_cross_refs, ) from .pubmed import PubmedSource, fetch_pubmed, fetch_pubmed_by_id from .semantic_scholar import ( SemanticScholarSource, fetch_s2_by_id, fetch_s2_citations, fetch_s2_recommendations, fetch_s2_references, fetch_semantic_scholar, ) # Explicit registration. No metaclass magic, no plugin discovery. register_source(ArxivSource()) register_source(PubmedSource()) register_source(SemanticScholarSource()) register_source(OpenAlexSource()) __all__ = [ "Capability", "PaperSource", "RateLimitHint", "REGISTRY", "register_source", "unregister_source", "paper_dict", "ArxivSource", "OpenAlexSource", "PubmedSource", "SemanticScholarSource", "fetch_arxiv", "fetch_arxiv_by_id", "fetch_arxiv_multi", "fetch_openalex", "fetch_openalex_by_id", "fetch_openalex_cross_refs", "fetch_pubmed", "fetch_pubmed_by_id", "fetch_semantic_scholar", "fetch_s2_by_id", "fetch_s2_citations", "fetch_s2_recommendations", "fetch_s2_references", "federated_search", ]