Data sources¶
The current tool surface reaches three external no-auth data sources. Each
sits behind an adapter that caches responses on disk so repeated tool
calls don't hammer the upstream, and each handles network failure by
falling back to a cached value flagged stale=true rather than
silently returning nothing.
CelesTrak — tle_lookup¶
CelesTrak is the canonical no-auth source for
current TLEs. tle_lookup calls the gp.php endpoint with the
caller-supplied query routed to the right CelesTrak parameter — NORAD
catalogue ID (CATNR=), satellite name (NAME=), or one of the
recognised group / category keywords (GROUP=). The recognised groups
are listed in the tool's description.
CelesTrak honours If-Modified-Since for most catalogue endpoints. The
adapter respects the upstream's soft per-IP cap (~100 MB/day) by caching
parsed OMM JSON for six hours by default. A cached response is served
without contacting the upstream; the fetched_at field carries the
timestamp of the original fetch.
When the upstream is unreachable:
- A cached value within or beyond its TTL is returned with
stale=Trueand the originalfetched_at. Treat the TLE as best-effort. - No cached value → the call fails with a
DataSourceErrorcarrying the codedata_source.celestrak_unreachable.
The User-Agent header carries the package version and a URL pointing back to this project so CelesTrak's analytics can distinguish well-behaved traffic from anonymous scraping.
JPL Horizons — porkchop, bplane_target¶
JPL Horizons supplies planetary ephemerides for the porkchop and B-plane tools. The adapter fetches vector ephemerides for the requested bodies over the requested time window and caches the response under a request hash.
Default TTL is seven days — planetary ephemerides drift on geological scales, and even the highest-precision missions tolerate week-old ephemerides without measurable error for these tools' use cases. Horizons is rate-limited and tolerates one in-flight request per client; the adapter does not parallelise calls to the upstream.
Failure modes mirror CelesTrak: a stale cached value is preferred over
total failure; no cache → data_source.horizons_unreachable.
IERS — time_convert, frame_transform¶
Earth-orientation parameters (UT1-UTC, polar motion) and leap-second
tables come from the IERS data center.
The adapter reuses astropy.coordinates' own IERS cache rather than
maintaining a second copy — astropy already polls IERS Bulletin A on a
schedule that matches its Thursday ~20:00 UTC refresh cycle.
Default adapter TTL is 24 hours so the cached value is re-validated
within one upstream cycle. When Bulletin A is unreachable and the
on-disk copy is older than the adapter's TTL, the tool emits a warning
through the response's stale field (or, for time_convert, a
data-source warning in the response payload) while still using the most
recent cached values for the conversion. The conversion result is still
correct up to the residual UT1-UTC error introduced by the staleness,
typically below a millisecond.
On-disk cache¶
All three adapters write to the same XDG-aware cache directory:
- Linux:
~/.cache/astrodynamics-mcp/ - macOS:
~/Library/Caches/astrodynamics-mcp/ - Windows:
%LOCALAPPDATA%\astrodynamics-mcp\Cache\
The cache is one JSON file per (source, key) entry, written via
atomic rename so concurrent astrodynamics-mcp stdio / ... http
processes can share the same directory safely. Two writers racing on the
same key both create their own tempfile; whichever os.replace lands
second wins, neither write is torn, and readers never see an
intermediate state.
To disable the cache (for tests or pristine CI cells), set
ASTRODYNAMICS_MCP_CACHE_DIR="" (empty string). With that override
get always misses, put is a no-op, and every tool call goes
straight to the upstream.
To redirect the cache to a custom directory, set
ASTRODYNAMICS_MCP_CACHE_DIR=/path/to/cache to any writable directory.
The XDG cache layer and its API are documented under
astrodynamics_mcp.cache.
stale=true semantics¶
Tools that return cache-backed payloads carry an explicit stale
boolean (typically inside each result element — see
tle_lookup). The contract is:
stale |
Meaning |
|---|---|
false |
The upstream was reached this call (or within the TTL window). The result reflects the latest upstream state. |
true |
The upstream was unreachable on this call; the result is the most recently cached value. The fetched_at field carries the timestamp of the original fetch — usually minutes to hours, occasionally days, before the call. |
LLM clients should treat stale=true as a signal to mention the
staleness in the human-facing reply ("using a TLE from N hours ago
because CelesTrak was unreachable just now") rather than quoting the
result as live.
Unit discipline¶
Every numeric value on the wire is wrapped in {value, unit} (or
{value: [...], unit} for vectors). Unit strings come from a closed
registry — "km", "km/s", "deg", "s", "min", "hours", "days",
"AU", "rad", "m", "m/s", "km^2/s^2", "km^3/s^2", "kg",
"K", and "1" for dimensionless quantities. Adding a new tool with a
bare number field fails the static unit-discipline check; the
allowed-units set is extended deliberately as new physical dimensions
enter the tool surface.
See astrodynamics_mcp.units for the registry and
helpers, and the
unit-discipline test source
for the static check.