Skip to content

Add ADS and ASCL tools for astrophysics literature and code discovery - #114

Open
pushwithak wants to merge 2 commits into
NASA-IMPACT:developfrom
pushwithak:feature/ads-ascl-tools
Open

Add ADS and ASCL tools for astrophysics literature and code discovery#114
pushwithak wants to merge 2 commits into
NASA-IMPACT:developfrom
pushwithak:feature/ads-ascl-tools

Conversation

@pushwithak

Copy link
Copy Markdown

Summary

Two wrappers over the astrophysics discovery services, built to work together — ASCL finds the code, ADS finds the papers behind it:

  • ascl_search_tool — searches the Astrophysics Source Code Library (ASCL), a curated registry of ~4,000 astrophysics codes, by capability keyword or ASCL id.
  • ads_search_tool — searches NASA's Astrophysics Data System (ADS) for papers.
  • ads_links_resolver_tool — resolves an ADS bibcode to its "associated" bibcodes; for an ASCL record this recovers the code's canonical description papers, which ASCL's own described_in field often under-reports.

ADS requires an API token (ADS_API_TOKEN); ASCL is public.

ASCL — ascl_search_tool

  • query — capability keyword (e.g. radiative transfer) or an ASCL id (1303.002 / ascl:1303.002); ids are auto-detected and formatted as an exact-match lookup.
  • rows — max entries (1–50, client-side cap; the ASCL API has no row limit).
  • Output (ASCLEntry): ascl_id, title, credit, abstract, site_list (code URLs), bibcode, described_in / used_in (ADS URLs), used_in_count, views. PHP-serialized list fields are parsed into clean URL lists.

ADS — ads_search_tool / ads_links_resolver_tool

  • Search: query (free text or Solr field syntax, e.g. title:"emcee", bibcode:"..."), rows (1–50), optional fq filter.
  • Output (ADSPaper): bibcode, title, authors, abstract, year, citation_count, doi, pub, linked data archives, esources, properties.
  • Resolver: bibcodeassociated_bibcodes (the "Described in" relationship).

Error handling

Every tool returns a populated error= field on failure and never raises out of _arun: response parsing runs inside the request's error boundary and is null-safe, so a malformed or sparse API response degrades gracefully rather than crashing.

Configuration (instance-level)

  • ADS: base_url, api_token (ADS_API_TOKEN), timeout.
  • ASCL: base_url (ASCL_API_URL), timeout.

Test plan

  • uv run pytest tests/tools/test_ascl.py — 11 passed (live ASCL API)
  • uv run pytest tests/tools/test_ads.py — passes with ADS_API_TOKEN set (skips cleanly without one)
  • MCP server registers ads_search_tool, ads_links_resolver_tool, ascl_search_tool alongside the existing tools
  • Null / malformed API responses return error= instead of raising

Supersedes #68 and #69.

@pushwithak pushwithak changed the title test Add ADS and ASCL tools for astrophysics literature and code discovery Jul 13, 2026
Two wrappers over the astrophysics discovery services, built to work
together -- ASCL finds the code, ADS finds the papers behind it:

- ascl_search_tool: search the Astrophysics Source Code Library by
  capability keyword or ASCL id.
- ads_search_tool: search NASA's Astrophysics Data System for papers.
- ads_links_resolver_tool: resolve an ADS bibcode to its associated
  bibcodes, recovering a code's canonical description papers that ASCL's
  own described_in field often under-reports.

ADS requires ADS_API_TOKEN; ASCL is public. Response parsing runs inside
each tool's error boundary and is null-safe, so a malformed or sparse API
response returns a populated error= rather than raising.
@pushwithak
pushwithak force-pushed the feature/ads-ascl-tools branch from 805ae7e to abc2811 Compare July 13, 2026 14:32

@sanzog03 sanzog03 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review (high effort)

Reviewed the ADS/ASCL tool additions. 8 distinct findings below as inline comments, ranked by severity. Two headline issues worth addressing before merge:

  • ADS config validator crashes the whole MCP server at startup when ADS_API_TOKEN is unset (register_all_tools() instantiates every tool at import time, with no try/except).
  • ASCL free-text queries are wrapped as exact-phrase (q='"..."'), silently dropping relevant capability-search results.

The rest are narrower correctness gaps and cleanup items.

🤖 Generated with Claude Code

Comment thread akd_ext/tools/ads.py Outdated
Comment thread akd_ext/tools/ascl.py Outdated
Comment thread akd_ext/tools/ascl.py Outdated
Comment thread akd_ext/tools/ads.py Outdated
Comment thread akd_ext/tools/ascl.py Outdated
Comment thread akd_ext/tools/ads.py Outdated
Comment thread tests/tools/test_ads.py
Comment thread akd_ext/tools/ascl.py Outdated
- ADS: don't crash the MCP server when ADS_API_TOKEN is unset. Drop the
  config validator and report the missing token per call instead, so
  register_all_tools() can instantiate every tool at import time.
- ADS: handle a scalar (non-list) title/doi from the API via a _first_str
  helper, instead of slicing a bare string to its first character.
- ASCL: match multi-word queries by ANDing each word order-independently
  (one quoted search per word, intersected by ascl_id) rather than
  requiring the exact contiguous phrase. Split the normalized query so a
  leading ascl:/URL prefix can't leak in as a required term.
- ASCL: reject empty queries (min_length=1) and normalize id prefixes
  idempotently (case-insensitive, loop until stable).
- ASCL: derive used_in_count from used_in via a computed field.
- Extract the shared GET + raise_for_status + json() into
  akd_ext/tools/_http.py::get_json, reused by all three tools (the ASCL
  path passes a shared client across its per-word requests).
- Tests: add token-less ADS tests (test_ads_no_token.py) plus multi-word
  AND, prefix-normalization, and empty/whitespace ASCL coverage.
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.

2 participants