[build-system] requires = ["setuptools>=61.0", "wheel"] build-backend = "setuptools.build_meta" [project] name = "scholar-mcp" version = "0.8.4" description = "Scholar MCP: multi-source academic search, citation traversal, and deep research" authors = [{ name = "Yuxian Li" }] readme = "README.md" license = "Apache-2.0" requires-python = ">=3.10" keywords = ["mcp", "semantic-scholar", "academic", "papers", "arxiv", "citations"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Science/Research", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Scientific/Engineering", ] dependencies = [ # Tested against fastmcp 3.x / mcp 1.26 (protocol 2025-11-25). The old # floor of >=2.0.0 allowed a fresh install to resolve a major version # behind what anyone has actually run. "fastmcp>=3.0.0,<4", "feedparser>=6.0.0", "pdftext>=0.7.1,<1", "pdfplumber>=0.11.9,<1", "pypdfium2>=5.10,<6", "pillow>=11.0", "pypdf>=4.0.0", "httpx>=0.27.0", "beautifulsoup4>=4.12.0", "lxml>=4.9.0", "networkx>=3.4.2", "pyyaml>=6.0", ] [project.optional-dependencies] # Query compression. optimize_query degrades to plain keyword extraction # without these, which the 2026-05 sweep measured as materially worse. compression = [ "keybert>=0.9.0", "model2vec>=0.8.0", ] # Reranker fallback, used whenever the DashScope API is unavailable. rerank = ["flashrank>=0.2.10"] dev = ["pytest>=8.0.0", "pillow>=11.0", "ruff>=0.12.0"] [project.urls] Homepage = "https://github.com/Liyux3/scholar-mcp" Repository = "https://github.com/Liyux3/scholar-mcp" Issues = "https://github.com/Liyux3/scholar-mcp/issues" [project.scripts] scholar-mcp = "scholar_mcp.cli:main" [tool.setuptools.packages.find] include = ["scholar_mcp*"] [tool.pytest.ini_options] testpaths = ["tests"] # Integration tests call live APIs: slow, rate-limited, and prone to failing # for reasons unrelated to the code. Excluded by default so `pytest` stays a # usable feedback loop; run them with `pytest -m integration`. addopts = "-m 'not integration'" markers = [ "integration: hits live external APIs, needs network and often API keys", ] [tool.ruff] target-version = "py310" extend-exclude = ["eval"] [tool.ruff.lint] select = ["E4", "E7", "E9", "F"]