
Research
/Security News
737 Chrome VPN Extensions Linked to Brand Impersonation and Browser Traffic Redirection
The campaign amassed more than 75,000 installs by targeting Russian-speaking users seeking access to blocked services.
@cyanheads/astronomy-mcp-server
Advanced tools
What's in the sky, computed offline — planet and moon positions, rise/set, phases, eclipses, and seasons for any place and time via MCP. STDIO or Streamable HTTP.
What's in the sky, computed offline — planet and moon positions, rise/set, phases, eclipses, and seasons for any place and time via MCP. STDIO or Streamable HTTP.
Seven tools — five form the keyless, offline, deterministic core (always registered); two are network-backed extensions that register only when their config gate is enabled.
| Tool | Description |
|---|---|
astronomy_get_sky_position | Apparent position of one body or named star for an observer and instant — equatorial (RA/Dec), horizontal (alt/az), ecliptic, plus distance, magnitude, angular diameter, phase, and constellation. |
astronomy_get_rise_set | Rise, set, and culmination times for a body at a location, with maximum altitude at transit. For the Sun, also the three twilight pairs (civil/nautical/astronomical). |
astronomy_get_moon_phase | Moon phase for an instant: illuminated fraction, phase name, synodic age, phase angle, and the next four quarter phases with timestamps. |
astronomy_find_events | Forward search for the next occurrences of one sky-event class: eclipses, equinoxes, solstices, moon quarters, oppositions, conjunctions, greatest elongations, and apsides. |
astronomy_list_visible | The one-call "what's up right now" answer: every naked-eye body (and optional bright stars) above the horizon, ranked, annotated, and gated by the Sun's altitude into daylight/twilight/dark. |
astronomy_get_ephemeris | (gated extension) Time-series ephemeris for a small body (asteroid/comet) or spacecraft via JPL Horizons — covers what the in-process major-body set cannot. Off by default. |
astronomy_get_satellite_passes | (gated extension) Visible passes of a satellite (by NORAD ID) over an observer, from a CelesTrak TLE propagated with SGP4 in-process. Off by default. |
This server computes geometry — where a body is, when an event happens — not astrophysics. The core wraps astronomy-engine (sub-arcminute accuracy, ≈1900–2100), so given the same (body, time, observer) every core tool returns identical output with no network, no rate limit, and no API key. It does not geocode: resolve a place name to latitude/longitude upstream (e.g. via an OpenStreetMap server) and pass an IANA timezone to receive observer-local times alongside UTC.
astronomy_get_sky_positionApparent topocentric position of one solar-system body or a named bright star.
star (e.g. "Sirius", "Polaris") instead of body to target a catalog star; star takes precedence over bodynull magnitude / angular diameter / phase fields where the engine cannot compute them — never fabricatedastronomy_get_rise_setRise, set, and culmination times, with twilight for the Sun.
start and returns the next count cycles (default 1, max 31)body: "sun", bundles the three twilight pairs (civil −6°, nautical −12°, astronomical −18°) so a single call answers "when does the sun set and when is it truly dark"null rise/set fields with an explanatory note rather than an error — the fact is the answertimezone is suppliedastronomy_find_eventsForward search across nine event classes under one event enum.
solar_eclipse, lunar_eclipse, equinox, solstice, moon_quarter, opposition, conjunction, max_elongation, perigee_apogeelatitude/longitude) and report local visibility and contact times; lunar eclipses are geocentric and need no locationopposition, conjunction, max_elongation, perigee_apogee) require a body, gated to the bodies each event exists for: opposition to the superior planets (mars through pluto), conjunction to any planet, max_elongation to mercury and venus, perigee_apogee to the moon, earth, or a planetperigee_apogee on earth returns its perihelion and aphelion; conjunction on mercury or venus returns both the inferior and superior passes, labelled by conjunction_kindcount occurrences (default 1, max 20)astronomy_list_visibleThe workflow flagship — one call returns a ranked, condition-gated "what's up" list.
include_stars, the bundled bright stars), keeps those above the horizon, and ranks them brightest-and-highest firstvisibility_note to each body, computed from real magnitude and altitude — no synthetic scoredaylight / civil_twilight / nautical_twilight / astronomical_twilight / dark) and the Sun's altitude alongside the listtime is a single evaluation instant, not a window — for "tonight" pass a time after astronomical dusk (use astronomy_get_rise_set on the Sun to find it)min_altitude to skip objects grazing the horizonastronomy_get_ephemeris (gated extension)Time-series ephemeris for a small body or spacecraft via the keyless JPL Horizons API. Registered only when ASTRONOMY_ENABLE_HORIZONS is set.
"433;" (Eros), "1;" (Ceres)"DES=1P;CAP" (Halley), "DES=2P;CAP" (Encke)"-48" (Hubble)"433 Eros" or "1P/Halley" returns no match or an ambiguous record list and is rejected. Look up designations at ssd.jpl.nasa.gov/tools/sbdb_lookup.html.start/stop are ISO 8601 UTC and stop must be after start; step is a positive count plus a unit of m, h, d, mo, or y ("10m", "1h", "1d")latitude/longitude yields topocentric coordinates and adds alt/az — pass both or neither; one alone is rejected rather than silently downgraded to a geocentric querystart at that instant, or split the range into smaller adjacent spans — keep the same step and repeat until truncated is false, which reconstructs every sample. Widening the step discards samples the original range asked forastronomy_get_satellite_passes (gated extension)Visible passes of a satellite over an observer. Registered only when ASTRONOMY_ENABLE_SATELLITES is set.
25544 for the ISS) and propagates it with SGP4 in-processstart is omitted rather than reported with start as its rise_utc; move start earlier to see it. A pass rising exactly at start is kept, so feeding a reported rise_utc back as start never loses itstart too far from it — so an empty passes list means only "no visible passes in this window"start must be within about a month of today: an element set describes the orbit for weeks around its epoch, and CelesTrak publishes only current onesdays (default 7, max 10); optional observer-local pass times| Type | Name | Description |
|---|---|---|
| Resource | astronomy://body/{body} | Static reference card for a solar-system body — canonical name, type, mean radius (km), and naked-eye visibility. {body} is one of sun, moon, mercury … pluto. |
| Prompt | astronomy_stargazing_plan | Structures a "plan tonight's stargazing from <place>" workflow, chaining the tools in order and naming the cross-server geocoding and weather steps. |
All resource data is also reachable via tools — astronomy_get_sky_position returns the same body metadata inline — so tool-only clients lose nothing. Design reference: docs/design.md.
Built on @cyanheads/mcp-ts-core:
none, jwt, oauthin-memory, filesystem, Supabase, Cloudflare KV/R2/D1Astronomy-specific:
astronomy-engine is the source of truth for positional astronomy; no network, no rate limit, no API key for the five core toolstimezone is supplied; the server never guesses a timezone from coordinatesastronomy_list_visible and astronomy_get_sky_position answer for named starsAgent-friendly output:
null (not 0, not omitted) when unavailable, and format() renders "unavailable" rather than inventing a valueformat() is content-complete on every tool — content[]-only clients see the same fields as structuredContent clients, and the same numbers: a value reads as a rounded display figure followed by its exact counterpart in brackets, e.g. RA 4.4116 h [4.411597993526305], dropped when the rounding already round-trips. astronomy_list_visible is the one scan surface, so its per-body line keeps only the distance's exact tail; astronomy_get_sky_position takes any body listed there and returns the same field set with every exact valueAdd the following to your MCP client configuration file. The five core tools need no configuration; set ASTRONOMY_ENABLE_HORIZONS and/or ASTRONOMY_ENABLE_SATELLITES to true to register the gated extensions.
{
"mcpServers": {
"astronomy-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/astronomy-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"astronomy-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/astronomy-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"astronomy-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/astronomy-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
git clone https://github.com/cyanheads/astronomy-mcp-server.git
cd astronomy-mcp-server
bun install
All configuration is optional and validated at startup via Zod schemas in src/config/server-config.ts. The core runs with no configuration at all.
| Variable | Description | Default |
|---|---|---|
ASTRONOMY_ENABLE_HORIZONS | Register the astronomy_get_ephemeris tool (JPL Horizons). | false |
ASTRONOMY_ENABLE_SATELLITES | Register the astronomy_get_satellite_passes tool (CelesTrak + SGP4). | false |
ASTRONOMY_HORIZONS_BASE_URL | Override the JPL Horizons API endpoint. | https://ssd.jpl.nasa.gov/api/horizons.api |
ASTRONOMY_CELESTRAK_BASE_URL | Override the CelesTrak GP/TLE endpoint. | https://celestrak.org/NORAD/elements/gp.php |
ASTRONOMY_DEFAULT_TIMEZONE | Fallback IANA timezone when a tool call omits timezone. Unset = UTC-only output. | none |
ASTRONOMY_REQUEST_TIMEOUT_MS | HTTP timeout (ms) for Horizons and CelesTrak requests. | 15000 |
ASTRONOMY_TLE_CACHE_TTL_MS | In-process TLE cache TTL (ms) — respects CelesTrak's refetch guidance (~once/2h). | 7200000 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for the HTTP server. | 3010 |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend. | in-memory |
OTEL_ENABLED | Enable OpenTelemetry instrumentation. | false |
See .env.example for the full list of optional overrides.
Build and run:
# One-time build
bun run rebuild
# Run the built server
bun run start:stdio
# or
bun run start:http
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security
bun run test # Vitest test suite
bun run lint:mcp # Validate MCP definitions against spec
docker build -t astronomy-mcp-server .
docker run --rm -e MCP_TRANSPORT_TYPE=stdio astronomy-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/astronomy-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools/resources/prompts and inits services. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts). Five core tools plus two gated extensions. |
src/mcp-server/resources | Resource definitions (*.resource.ts). Body reference card. |
src/mcp-server/prompts | Prompt definitions (*.prompt.ts). Stargazing plan. |
src/services/ephemeris | The offline compute core — astronomy-engine wrapper, body-radius table, and bundled bright-star catalog. |
src/services/horizons | JPL Horizons HTTP client (gated extension). |
src/services/satellite | CelesTrak TLE fetch + SGP4 propagation (gated extension). |
tests/ | Unit and integration tests mirroring src/. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging, ctx.state for tenant-scoped storagecreateApp() arrays in src/index.tsnull and never fabricate missing fieldsIssues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.
FAQs
What's in the sky, computed offline — planet and moon positions, rise/set, phases, eclipses, and seasons for any place and time via MCP. STDIO or Streamable HTTP.
We found that @cyanheads/astronomy-mcp-server demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
The campaign amassed more than 75,000 installs by targeting Russian-speaking users seeking access to blocked services.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.