Metadata-Version: 2.4
Name: paper-tools-mcp
Version: 0.1.4
Summary: Standalone MCP server: deterministic paper identity resolution + PDF retrieval
Author: zhangsh1416
License: MIT
Keywords: mcp,doi,openalex,unpaywall,pdf,citations,research
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Science/Research
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp[cli]
Requires-Dist: httpx
Requires-Dist: pyyaml
Requires-Dist: curl_cffi
Requires-Dist: beautifulsoup4
Requires-Dist: browser_cookie3
Requires-Dist: patchright
Dynamic: license-file

# paper-tools (MCP)

A standalone [MCP](https://modelcontextprotocol.io) server that turns "find a
paper" into a **deterministic** capability. Two tools:

- **`resolve_paper(query)`** — any input (DOI, arXiv id/URL, SSRN, a bare title, a
  messy citation string) → decide whether it points to **one real paper** and
  return that paper's **unique identifier** (DOI, else OpenAlex Work ID), or
  `ambiguous` / `not_found`. Never guesses a binding.
- **`get_pdf(ids)`** — that identifier → **actually downloads the open-access PDF**,
  trying arXiv → Unpaywall → OpenAlex OA/green/SSRN. Returns the saved path, or an
  honest `downloadable=false` with human follow-up leads (SSRN, OA Button) when no
  open-access copy exists.

Built by an unattended Ralph loop from [`GOAL.md`](./GOAL.md). Status and
remaining work live in [`PROGRESS.md`](./PROGRESS.md). This project is fully
independent — it has no dependency on any other repository.

## Setup
```bash
conda env create -f environment.yml
conda activate paper-tools-mcp
pytest -q            # offline golden-set suite
pytest -q -m live    # live smoke (hits real APIs)
```

## Institutional access (your own subscription)

When a paper has no open-access copy, `get_pdf` tries the caller's own subscription
(disable with `institutional=False`). Two legitimate mechanisms:

- **Elsevier full-text API** (covers `10.1016/...`): export your own key —
  `export ELSERVIER_API_KEY=...` (optional `ELSERVIER_INSTTOKEN=...`). Uses the
  Elsevier Article Retrieval API, entitled via your institutional network/token.
- **Publisher fetch** (curl_cffi): follows the DOI to the publisher and grabs the
  PDF; works for publishers that grant access by IP when run on campus/VPN.

- **Your Chrome login cookies** (curl_cffi): the publisher fetch reuses your existing
  Chrome session via `browser_cookie3` — stay logged into the publishers in Chrome.
  Works for publishers without a JS bot-wall. Disable with `PAPER_TOOLS_NO_BROWSER_COOKIES=1`.

- **Strong layer (ON by default): one-click institutional fetch** for publishers behind
  a Cloudflare human-check + SSO (SAGE → POMS/JMR/JM, OUP → JCR, INFORMS). Runs whenever
  a desktop display is present (chromium auto-installs on first use); opt out with
  `PAPER_TOOLS_NONINTERACTIVE=1` (e.g. on headless servers, where it degrades to leads).
  When the automated cascade can't get a gated paper, `get_pdf` pops ONE browser window
  — already seeded with your Chrome login cookies — you clear the one-time "are you
  human" check (and sign in if needed) once per publisher, and the tool downloads that
  paper and reuses the session for every later paper from the same publisher. The human
  check is solved by you (never auto-defeated); everything else is automatic.

## Install = environment solved (no manual setup)

Installing the package pulls **all** Python dependencies; the chromium browser for
the strong layer **auto-installs on first use** — no separate `conda`/`pip`/
`patchright install` steps.

Zero-setup registration (uv creates an isolated env and installs on first run):
```jsonc
// .mcp.json
{
  "mcpServers": {
    "paper-tools": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/<you>/paper-tools-mcp", "paper-tools-mcp"],
      "env": { "PAPER_TOOLS_INTERACTIVE": "1", "ELSERVIER_API_KEY": "<optional>" }
    }
  }
}
```
Or with pip: `pip install git+https://github.com/<you>/paper-tools-mcp` then use
`"command": "paper-tools-mcp"`. (A desktop display is required only for the strong
interactive layer; the OA/API layers run anywhere.)

**Cross-platform:** Linux, macOS, and Windows. The OA/API layers run anywhere. The
strong interactive layer uses your local Chrome cookies (`browser_cookie3` decrypts
per-OS: Linux keyring / macOS Keychain / Windows DPAPI) and pops a desktop window, so
it needs a logged-in Chrome + a desktop session. Launch flags are auto-selected per
OS (`--no-sandbox` only on Linux). Note: very recent Chrome on Windows uses app-bound
cookie encryption that `browser_cookie3` may not read — sign in once in the popped
window if cookie reuse misses.

## Register with Claude Code (dev / conda)
<!-- the loop fills in the concrete command/path; this anchors the DoD grep -->
```jsonc
// .mcp.json / Claude Code MCP config
{
  "mcpServers": {
    "paper-tools": {
      "command": "conda",
      "args": ["run", "-n", "paper-tools-mcp", "python", "-m", "paper_tools.server"]
    }
  }
}
```
