Skip to content

feat: Add Scopus search with ScienceDirect full-text support (optional) - #89

Draft
mildwall wants to merge 3 commits into
openags:mainfrom
mildwall:feat/scopus-sciencedirect
Draft

feat: Add Scopus search with ScienceDirect full-text support (optional)#89
mildwall wants to merge 3 commits into
openags:mainfrom
mildwall:feat/scopus-sciencedirect

Conversation

@mildwall

Copy link
Copy Markdown

Summary

Adds an optional Scopus (Elsevier) connector with ScienceDirect full-text support. It follows the same opt-in pattern as the existing IEEE/ACM connectors: with no API key configured, no tools are registered and the rest of the server is completely unaffected.

Activated by setting PAPER_SEARCH_MCP_SCOPUS_API_KEY (legacy SCOPUS_API_KEY also accepted).

Motivation

Scopus is one of the largest curated abstract & citation databases. Adding it lets users run advanced field/boolean/proximity queries, filter and sort by citation count or date, and pull full text for entitled ScienceDirect articles — all through the existing search_papers aggregate and CLI.

New MCP tools (registered only when a key is present)

Tool What it does
search_scopus Scopus Search API with advanced query syntax (TITLE/ABS/KEY/AUTH/AFFILORG, boolean + proximity operators, wildcards), sort (relevance / coverDate / citedby-count / creator) and publication-date filters. Uses the COMPLETE view (Elsevier caps this at 25 results/request; enforced client-side).
read_scopus_paper Resolves the paper via the Scopus Abstract Retrieval API, then fetches full text via the ScienceDirect Search v2 + Article Retrieval APIs for entitled articles.
download_scopus Returns an explanatory message — the Scopus API does not offer direct PDF downloads.

All three participate in the search_papers aggregate and the CLI when enabled.

Design & safety

  • Zero impact when disabled — no key → no tool registration, no import side effects.
  • Honest client User-Agent (no browser spoofing).
  • Request timeouts on every call; exponential backoff on 429 honoring Retry-After. Weekly-quota-exhausted 429s (X-RateLimit-Remaining: 0) fail fast instead of retrying.
  • Clear authorization messaging on 401/403: Elsevier grants subscriber views by network/IP, so the error suggests the institutional network/VPN rather than surfacing a bare HTTP error.
  • Input hardening: paper IDs validated as numeric before URL interpolation; query values URL-quoted; empty-result sentinel entries filtered out so a zero-hit search returns [] rather than a garbage record.
  • Open-ended date ranges (2024-, -2020) are normalized to closed ranges, which the Scopus API requires (open forms silently return nothing).

Configuration

# .env
PAPER_SEARCH_MCP_SCOPUS_API_KEY=your_elsevier_api_key

Documented in README.md, .env.example, and smithery.yaml.

Testing

  • 19 unit tests, fully mocked — no network, no real keys — so they run anywhere (including CI) without an Elsevier subscription.

  • Live-verified against the real Scopus API (2026-06-12, COMPLETE view entitled, quota healthy):

    • basic search returns requested count, numeric IDs, non-empty titles, source == scopus
    • date-filtered search constrained to the requested year range
    • citation sort returns non-increasing citedby-count
    • max_results > 25 capped at 25 with no HTTP 400
    • nonsense query returns []
    • malicious paper_id (../../article/pii/EVIL?x=1) rejected before any request fires
    • abstract-retrieval details lookup returns title for a fresh ID

    Full-text retrieval (read_scopus_paper) is covered by the mocked unit tests; live availability depends on the caller's per-article ScienceDirect entitlement.

Reviewer notes

  • The connector is invisible without a key, so it cannot affect existing behavior or CI.
  • The mocked tests need no subscription to pass; the live behavior above is provided as evidence since the API can't be exercised without entitlement.

Commits

  • feat: Add Scopus search with ScienceDirect full-text support (opt-in)
  • fix: normalize open-ended date ranges in Scopus search

mildwall and others added 2 commits June 12, 2026 13:55
Adds an optional Scopus (Elsevier) connector, activated by setting
PAPER_SEARCH_MCP_SCOPUS_API_KEY (or legacy SCOPUS_API_KEY), following
the same opt-in pattern as the IEEE/ACM connectors: without a key no
tools are registered and the rest of the server is unaffected.

Capabilities:
- search_scopus: Scopus Search API with advanced query syntax
  (TITLE/ABS/KEY/AUTH/AFFILORG fields, boolean and proximity operators,
  wildcards), sort (relevance/coverDate/citedby-count/creator) and
  publication-date filters. Uses the COMPLETE view (max 25 results per
  request, enforced client-side).
- read_scopus_paper: resolves the paper via the Scopus Abstract
  Retrieval API, then fetches full text through the ScienceDirect
  Search v2 + Article Retrieval APIs for entitled articles.
- download_scopus: returns an explanatory message (the Scopus API does
  not provide direct PDF downloads).
- Participates in the search_papers aggregate and the CLI when enabled.

Robustness and API etiquette:
- Honest client User-Agent (no browser spoofing).
- Request timeouts on every call; exponential backoff on 429 honoring
  Retry-After; weekly-quota-exhausted 429s (X-RateLimit-Remaining: 0)
  fail fast instead of retrying.
- Clear authorization message on 401/403: Elsevier grants subscriber
  views by network/IP, so the error suggests the institutional
  network/VPN instead of surfacing a bare HTTP error.
- Paper IDs validated as numeric before URL interpolation; PII values
  URL-quoted; empty-result sentinel entries filtered out.

Includes 19 fully mocked unit tests (no network, no real keys) and
README/.env.example/smithery.yaml documentation. Live-verified against
the Scopus API: search, date filters, citation sort, abstract
retrieval, and quota handling, with identical behavior to the
pre-port implementation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Scopus API only accepts closed date ranges (2002-2007) or single
years; open-ended forms like 2024- or -2020 silently return an
empty result set. Convert them to closed ranges before sending.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mildwall mildwall changed the title feat: Add Scopus search with ScienceDirect full-text support (opt-in) feat: Add Scopus search with ScienceDirect full-text support (optional) Jun 18, 2026
API failures (rate limiting, authorization errors, malformed responses
without a search-results envelope) were logged and swallowed, returning
an empty list indistinguishable from a genuine zero-match search. Raise
RuntimeError instead so MCP callers see the actual failure.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
HagiaHaya added a commit to HagiaHaya/paper-search-mcp that referenced this pull request Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant