Add ADS and ASCL tools for astrophysics literature and code discovery - #114
Open
pushwithak wants to merge 2 commits into
Open
Add ADS and ASCL tools for astrophysics literature and code discovery#114pushwithak wants to merge 2 commits into
pushwithak wants to merge 2 commits into
Conversation
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
force-pushed
the
feature/ads-ascl-tools
branch
from
July 13, 2026 14:32
805ae7e to
abc2811
Compare
sanzog03
reviewed
Jul 13, 2026
sanzog03
left a comment
Collaborator
There was a problem hiding this comment.
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_TOKENis 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
- 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.
sanzog03
approved these changes
Jul 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 owndescribed_infield often under-reports.ADS requires an API token (
ADS_API_TOKEN); ASCL is public.ASCL —
ascl_search_toolquery— 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).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_toolquery(free text or Solr field syntax, e.g.title:"emcee",bibcode:"..."),rows(1–50), optionalfqfilter.ADSPaper):bibcode,title,authors,abstract,year,citation_count,doi,pub, linked data archives, esources, properties.bibcode→associated_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)
base_url,api_token(ADS_API_TOKEN),timeout.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 withADS_API_TOKENset (skips cleanly without one)ads_search_tool,ads_links_resolver_tool,ascl_search_toolalongside the existing toolserror=instead of raisingSupersedes #68 and #69.