Last updated: 2026-05-10
A standalone, agnostic celestial computation engine exposed via MCP. It provides raw astronomical data as structured JSON. Consumers bring their own meaning.
Core principle: separate what the sky is from what it means.
This is the first version worth committing as a usable baseline.
get_planetary_positionsget_solar_eventsget_lunar_stateget_moon_phaseget_sidereal_timeget_constellation_at_eclipticlist_available_bodiesget_objects_above_horizonget_satellite_passesget_iss_positionpython -m pytest passesrun.sh starts the server on port 7015tests.sh succeeds in the repo-local virtualenv| Decision | Choice | Rationale |
|---|---|---|
| Library | Swiss Ephemeris (pyswisseph) |
High precision, direct fit for the core use case |
| Runtime | FastMCP + FastAPI behind uvicorn | Matches the MCP server pattern used elsewhere |
| Cache | SQLite with TTL | No external DB dependency for the first slice |
| Port | 7015 | Reserved for this service in the workspace |
| Host | 0.0.0.0 | Bind on all interfaces for LAN access |
| Entry point | main.py at repo root, package app factory under src/ephemeris_mcp/ |
Keeps the runtime easy to launch and test |
| NumPy | Not included | Avoid unnecessary build friction |
| Python | 3.13 | Matches the local environment |
| Naming | ephemeris-mcp |
Clear service identity |
./data/| # | Tool | Input | Output |
|---|---|---|---|
| A1 | get_planetary_positions |
datetime?, lat?, lon?, elevation?, geocentric? |
Array of bodies with ecliptic/equatorial coords, distance, speed |
| A2 | get_solar_events |
date, lat, lon |
Sunrise/set, solar noon, all twilight boundaries, day length |
| A3 | get_lunar_state |
datetime?, lat?, lon? |
Phase name, illumination %, age, RA/dec, next phase datetime |
| A4 | get_moon_phase |
datetime?, lat?, lon? |
Quick moon-phase view for manual use |
| A5 | get_sidereal_time |
datetime?, lat?, lon? |
GST, LST, obliquity of ecliptic |
| A6 | get_constellation_at_ecliptic |
ecliptic_lon |
IAU constellation name/abbrev at that ecliptic longitude |
| # | Tool | Input | Output |
|---|---|---|---|
| B1 | get_objects_above_horizon |
lat, lon, elevation?, categories? |
Visible objects filtered by category (planets, moon, sun, bright_stars, messier) |
| B2 | get_satellite_passes |
lat, lon, norad_id or name, start_datetime?, hours? |
Predicted passes with altitude/azimuth/duration/times |
| B3 | get_iss_position |
lat?, lon? |
Current ISS position + next visible pass |
| # | Tool | Input | Output |
|---|---|---|---|
| C1 | list_available_bodies |
category? |
List of all computable bodies and their metadata |
| C2 | get_constellations_list |
— | All 88 IAU constellations with boundaries metadata |
categories in get_objects_above_horizonAccepts a comma-separated string, defaults to "planets,moon,sun" (the most probable standard set for astro-mcp):
planets — Mercury through Plutomoonsunbright_stars — navigational stars, magnitude < 1.5messier — Messier deep-sky objects (when above horizon)now./health and / deterministic and testableget_objects_above_horizonget_satellite_passesget_iss_positionREADME.md, AGENTS.md, and wiki references aligned# Core runtime
fastmcp>=2.0.0
fastapi>=0.115.0
uvicorn[standard]>=0.30.0
pydantic>=2.8.0
# Ephemeris computation
pyswisseph>=2.10 # Swiss Ephemeris C bindings
jplephem>=2.16 # JPL ephemeris file reader
# Satellite tracking
sgp4>=2.22 # SGP4 orbit propagation (no numpy dependency in 2.x)
# Utilities
python-dotenv>=1.0.1
requests>=2.32.0 # For TLE fetch from CelesTrak
# Testing
pytest>=8.0.0
No numpy — swisseph is pure C; sgp4 2.x doesn't require numpy.
-- General computation cache with TTL
CREATE TABLE IF NOT EXISTS cache (
key TEXT PRIMARY KEY,
value TEXT NOT NULL, -- JSON serialized result
expires_at REAL NOT NULL -- Unix timestamp
);
CREATE INDEX idx_cache_expires ON cache(expires_at);
-- TLE data storage
CREATE TABLE IF NOT EXISTS tle_data (
norad_id INTEGER PRIMARY KEY,
name TEXT,
line1 TEXT NOT NULL,
line2 TEXT NOT NULL,
last_fetched REAL NOT NULL
);
get_objects_above_horizon with bright_stars category.)