Skip to main content
Glama
chrishayuk

chuk-mcp-celestial

by chrishayuk

chuk-mcp-celestial

PyPI version Python 3.11+ License: MIT

MCP server for US Navy astronomical and celestial data - The definitive celestial MCP server providing moon phases, solar eclipses, sun/moon rise/set times, and Earth's seasons from the official US Navy Astronomical Applications API.

🌐 Try it now - Hosted version available! - No installation required.

Features

πŸŒ™ Comprehensive Celestial Data:

  • Moon phases with exact timing (New Moon, First Quarter, Full Moon, Last Quarter)

  • Sun and moon rise/set/transit times for any location

  • Solar eclipse predictions with local circumstances

  • Earth's seasons (equinoxes, solstices, perihelion, aphelion)

⚑ Flexible Providers:

  • Navy API - Authoritative US Navy data, all features

  • Skyfield - 28x faster, offline calculations, research-grade accuracy

  • Hybrid mode - Mix providers per-tool (e.g., Skyfield for moon phases, Navy for eclipses)

  • S3 storage - Cloud-based ephemeris storage via chuk-virtual-fs

πŸ”’ Type-Safe & Robust:

  • Pydantic v2 models for all responses - no dictionary goop!

  • Enums for all constants - no magic strings!

  • Full async/await support with httpx

  • Comprehensive error handling

πŸ”— Multi-Server Integration:

  • Works seamlessly with time and weather servers

  • Combine celestial + time + weather for comprehensive astronomical intelligence

  • Answer complex questions like "Will the moon be visible tonight with current weather?"

βœ… Production Ready:

  • 70%+ test coverage with pytest

  • GitHub Actions CI/CD

  • Automated releases to PyPI

  • Type checking with mypy

  • Code quality with ruff

Installation

Comparison of Installation Methods

Method

Setup Time

Requires Internet

Updates

Best For

Hosted

Instant

Yes

Automatic

Quick testing, production use

uvx

Instant

Yes (first run)

Automatic

No local install, always latest

Local

1-2 min

Only for install

Manual

Offline use, custom deployments

No installation needed! Use our public hosted version:

{ "mcpServers": { "celestial": { "url": "https://celestial.chukai.io/mcp" } } }

Option 2: Install via uvx (No Installation Required)

Run directly without installing:

{ "mcpServers": { "celestial": { "command": "uvx", "args": ["chuk-mcp-celestial"] } } }

Option 3: Install Locally

Basic Installation (Navy API only):

# With pip pip install chuk-mcp-celestial # Or with uv (recommended) uv pip install chuk-mcp-celestial # Or with pipx (isolated installation) pipx install chuk-mcp-celestial

With Skyfield Support (offline calculations, 28x faster):

# Install with Skyfield and S3 support pip install "chuk-mcp-celestial[skyfield]" # Or with uv uv pip install "chuk-mcp-celestial[skyfield]" # Download ephemeris files (one-time setup) python scripts/download_ephemeris.py --backend local

Then configure in your MCP client:

{ "mcpServers": { "celestial": { "command": "chuk-mcp-celestial" } } }

Optional: Configure hybrid provider mode (create celestial.yaml):

# Use Skyfield for fast queries, Navy API for everything else default_provider: navy_api providers: moon_phases: skyfield # 28x faster earth_seasons: skyfield # 33x faster

Quick Start

Claude Desktop Configuration

Choose one of the installation methods above and add to your Claude Desktop config:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json Windows: %APPDATA%/Claude/claude_desktop_config.json

Hosted version (easiest):

{ "mcpServers": { "celestial": { "url": "https://celestial.chukai.io/mcp" } } }

uvx version (no install):

{ "mcpServers": { "celestial": { "command": "uvx", "args": ["chuk-mcp-celestial"] } } }

Local installation:

{ "mcpServers": { "celestial": { "command": "chuk-mcp-celestial" } } }

Then ask questions like:

  • "When is the next full moon?"

  • "What time does the sun rise in Seattle tomorrow?"

  • "Are there any solar eclipses visible from New York in 2024?"

  • "When are the equinoxes this year?"

Using with mcp-cli

Test the server interactively with mcp-cli:

# Using hosted version uv run mcp-cli --server https://celestial.chukai.io/mcp --provider openai --model gpt-4o-mini # Using uvx (local execution) uv run mcp-cli --server celestial --provider openai --model gpt-4o-mini

Example session:

> when does the sunrise tomorrow in london βœ“ Completed: get_sun_moon_data (0.50s) Sunrise in London tomorrow (2025-11-29) is at 07:41 GMT (UTC). Additional info: - Begin civil twilight: 07:02 GMT - Sunset: 15:56 GMT - Daylight length: about 8 h 15 m

As a Python Library

Using MCP Server Tools (Default Provider)

import asyncio from chuk_mcp_celestial.server import ( get_moon_phases, get_sun_moon_data, get_solar_eclipse_by_date, get_earth_seasons, ) async def main(): # Get next 4 moon phases (uses configured provider) phases = await get_moon_phases(date="2024-12-1", num_phases=4) for phase in phases.phasedata: print(f"{phase.phase}: {phase.year}-{phase.month:02d}-{phase.day:02d} at {phase.time} UT") # Get sun/moon times for Seattle data = await get_sun_moon_data( date="2024-12-21", latitude=47.60, longitude=-122.33, timezone=-8 ) print(f"Moon phase: {data.properties.data.curphase}") print(f"Illumination: {data.properties.data.fracillum}") # Check eclipse visibility eclipse = await get_solar_eclipse_by_date( date="2024-4-8", latitude=40.71, # New York longitude=-74.01 ) print(f"Eclipse: {eclipse.properties.description}") print(f"Magnitude: {eclipse.properties.magnitude}") asyncio.run(main())

Using Providers Directly

import asyncio from chuk_mcp_celestial.providers import NavyAPIProvider, SkyfieldProvider async def main(): # Use Navy API provider navy = NavyAPIProvider() phases_navy = await navy.get_moon_phases("2024-1-1", num_phases=4) print("Navy API moon phases:") for phase in phases_navy.phasedata: print(f" {phase.phase}: {phase.year}-{phase.month:02d}-{phase.day:02d} {phase.time}") # Use Skyfield provider (faster, offline) skyfield = SkyfieldProvider( ephemeris_file="de421.bsp", storage_backend="memory", # or "s3" or "local" auto_download=True ) phases_skyfield = await skyfield.get_moon_phases("2024-1-1", num_phases=4) print("\nSkyfield moon phases:") for phase in phases_skyfield.phasedata: print(f" {phase.phase}: {phase.year}-{phase.month:02d}-{phase.day:02d} {phase.time}") # Earth seasons with Skyfield (fast!) seasons = await skyfield.get_earth_seasons(2024) print("\nEarth seasons 2024:") for event in seasons.data: print(f" {event.phenom}: {event.year}-{event.month:02d}-{event.day:02d} {event.time}") asyncio.run(main())

Hybrid Approach (Best of Both Worlds)

import asyncio from chuk_mcp_celestial.providers import NavyAPIProvider, SkyfieldProvider async def main(): # Use Skyfield for fast offline calculations skyfield = SkyfieldProvider(storage_backend="local") # Use Navy API for features not in Skyfield navy = NavyAPIProvider() # Fast moon phases from Skyfield phases = await skyfield.get_moon_phases("2024-12-1", num_phases=12) # Detailed rise/set times from Navy API sun_moon = await navy.get_sun_moon_data( date="2024-12-21", latitude=47.60, longitude=-122.33 ) # Solar eclipses only from Navy API (not in Skyfield) eclipse = await navy.get_solar_eclipse_by_date( date="2024-4-8", latitude=40.71, longitude=-74.01 ) print(f"Next moon phase: {phases.phasedata[0].phase}") print(f"Sunrise: {sun_moon.properties.data.sundata[0].time}") print(f"Eclipse: {eclipse.properties.description}") asyncio.run(main())

Available Tools

get_moon_phases(date, num_phases)

Get upcoming moon phases starting from a given date.

Parameters:

  • date (str): Start date (YYYY-MM-DD)

  • num_phases (int): Number of phases to return (1-99, default 12)

Returns: MoonPhasesResponse with list of phase data

get_sun_moon_data(date, latitude, longitude, timezone?, dst?, label?)

Get complete sun and moon data for one day at a specific location.

Parameters:

  • date (str): Date (YYYY-MM-DD)

  • latitude (float): Latitude in decimal degrees (-90 to 90)

  • longitude (float): Longitude in decimal degrees (-180 to 180)

  • timezone (float, optional): Timezone offset from UTC in hours

  • dst (bool, optional): Apply daylight saving time

  • label (str, optional): User label for the query

Returns: OneDayResponse (GeoJSON Feature) with sun/moon rise/set/transit times, twilight, moon phase, and illumination

get_solar_eclipse_by_date(date, latitude, longitude, height?)

Get local solar eclipse circumstances for a specific date and location.

Parameters:

  • date (str): Eclipse date (YYYY-MM-DD)

  • latitude (float): Observer latitude

  • longitude (float): Observer longitude

  • height (int, optional): Height above sea level in meters (default 0)

Returns: SolarEclipseByDateResponse (GeoJSON Feature) with eclipse type, magnitude, obscuration, duration, and local circumstances

get_solar_eclipses_by_year(year)

Get a list of all solar eclipses occurring in a specific year.

Parameters:

  • year (int): Year to query (1800-2050)

Returns: SolarEclipseByYearResponse with list of eclipse events

get_earth_seasons(year, timezone?, dst?)

Get Earth's seasons and orbital events for a year.

Parameters:

  • year (int): Year to query (1700-2100)

  • timezone (float, optional): Timezone offset from UTC

  • dst (bool, optional): Apply daylight saving time

Returns: SeasonsResponse with equinoxes, solstices, perihelion, and aphelion

Architecture

No Dictionary Goop

All responses are strongly-typed Pydantic models:

# ❌ Bad (dictionary goop) phase = data["phasedata"][0]["phase"] # βœ… Good (typed models) phase = data.phasedata[0].phase # IDE autocomplete works!

No Magic Strings

All constants use enums:

from chuk_mcp_celestial.models import MoonPhase, SeasonPhenomenon # ❌ Bad (magic strings) if phase == "Full Moon": # βœ… Good (enums) if phase == MoonPhase.FULL_MOON:

Async Native

All API calls use async/await with httpx:

async with httpx.AsyncClient() as client: response = await client.get(API_URL, params=params, timeout=30.0) response.raise_for_status() data = response.json() return PydanticModel(**data)

Provider Architecture

This server supports multiple calculation providers via a factory pattern, allowing you to choose between different astronomical calculation backends:

Available Providers

Provider

Speed

Accuracy

Offline

Features

Navy API

Standard (~700ms)

Authoritative

❌

All features

Skyfield

Fast (~25ms)

Research-grade

βœ…

Moon phases, seasons

Configuration

Create a celestial.yaml file to configure providers:

# Default provider for all tools default_provider: navy_api # Per-tool provider configuration (mix and match!) providers: moon_phases: skyfield # Fast offline calculations sun_moon_data: navy_api # Rise/set times solar_eclipse_date: navy_api # Eclipse circumstances solar_eclipse_year: navy_api # Eclipse catalogs earth_seasons: skyfield # Fast offline seasons # Skyfield configuration skyfield: # Ephemeris file to use ephemeris: de440s.bsp # 32 MB, covers 1849-2150 # Storage backend for ephemeris files storage_backend: s3 # Options: local, s3, memory # S3 configuration (when storage_backend=s3) s3: bucket: chuk-celestial-ephemeris region: us-east-1 prefix: ephemeris/ # profile: default # Optional AWS profile # Local directory (when storage_backend=local) data_dir: ~/.skyfield # Auto-download ephemeris if not present auto_download: true # Navy API configuration navy_api: base_url: https://aa.usno.navy.mil/api timeout: 30.0 max_retries: 3 retry_delay: 1.0

Config file locations (checked in order):

  1. Path from CELESTIAL_CONFIG_PATH environment variable

  2. ./celestial.yaml (current directory)

  3. ~/.config/chuk-mcp-celestial/celestial.yaml (user config)

Environment variable overrides:

  • CELESTIAL_PROVIDER - Default provider

  • CELESTIAL_MOON_PHASES_PROVIDER - Provider for moon phases

  • SKYFIELD_STORAGE_BACKEND - Storage backend (local/s3/memory)

  • SKYFIELD_S3_BUCKET - S3 bucket name

  • SKYFIELD_S3_REGION - S3 region

  • See celestial.yaml.example for all options

Ephemeris Storage with chuk-virtual-fs

Skyfield requires JPL ephemeris files (~32 MB) for astronomical calculations. This server uses chuk-virtual-fs to provide flexible storage options:

Storage Backends:

  1. S3 (Recommended for production) - Cloud storage with AWS S3

    • Persistent across deployments

    • Shared across multiple instances

    • No local disk required

    • Easy CDN integration

  2. Local - Traditional filesystem storage

    • Good for development and offline use

    • No cloud dependencies

    • Requires local disk space

  3. Memory - In-memory storage for testing

    • Ephemeral storage

    • Fast but non-persistent

Download Ephemeris Files:

# Download recommended ephemeris (de440s.bsp) to S3 python scripts/download_ephemeris.py # Download all ephemeris files to S3 python scripts/download_ephemeris.py --all # Download specific ephemeris to S3 python scripts/download_ephemeris.py --file de421.bsp # Force re-download even if file exists python scripts/download_ephemeris.py --force # Download to local filesystem python scripts/download_ephemeris.py --backend local # Download all files to local storage python scripts/download_ephemeris.py --all --backend local # List available ephemeris files python scripts/download_ephemeris.py --list

Features:

  • βœ… Auto-creates S3 bucket if it doesn't exist

  • βœ… Skips files that already exist in storage

  • βœ… Use --force to re-download existing files

  • βœ… Batch download with --all flag

Note: For S3 backend, create a .env file with AWS credentials:

cp .env.example .env # Edit .env with your AWS credentials

Available ephemeris files:

  • de440s.bsp - 32 MB, covers 1849-2150 (⭐ recommended)

  • de421.bsp - 17 MB, covers 1900-2050 (smaller, older)

  • de440.bsp - 114 MB, covers 1550-2650 (most comprehensive)

How it works:

  1. Ephemeris files are stored in your configured backend (S3, local, or memory)

  2. On first use, Skyfield provider downloads files to a local temp cache

  3. Skyfield reads from the cache for fast calculations

  4. Cache persists across provider instances for performance

See COMPARISON_REPORT.md for detailed accuracy and performance comparison between providers.

Deployment

Docker

Build and run with Docker:

# Build Docker image make docker-build # Run container make docker-run # Or build and run in one command make docker-up

The server will be available at http://localhost:8000 in HTTP mode.

Fly.io

Deploy to Fly.io:

# First time setup fly launch # Set AWS secrets for S3 ephemeris storage fly secrets set AWS_ACCESS_KEY_ID=your_key AWS_SECRET_ACCESS_KEY=your_secret # Deploy make fly-deploy # Check status make fly-status # View logs make fly-logs # Open in browser make fly-open

Configuration (fly.toml):

  • Environment variables for provider settings

  • S3 bucket configuration

  • AWS credentials via fly secrets (not in file)

  • Auto-scales to 0 when not in use

Ephemeris Setup for Production:

# Download ephemeris files to S3 before first deployment cp .env.example .env # Edit .env with your AWS credentials python scripts/download_ephemeris.py --backend s3 # Or download all files python scripts/download_ephemeris.py --all --backend s3

Development

Setup

# Clone the repo git clone https://github.com/yourusername/chuk-mcp-celestial cd chuk-mcp-celestial # Install with all dependencies (dev + skyfield) uv sync --extra dev --extra skyfield # Or with pip pip install -e ".[dev,skyfield]" # Set up environment variables for S3 (optional) cp .env.example .env # Edit .env with your AWS credentials # Download ephemeris files for local development python scripts/download_ephemeris.py --backend local

Testing

# Run tests make test # Run tests with coverage make test-cov # Run specific test pytest tests/test_server.py::test_get_moon_phases -v

Code Quality

# Format code make format # Run linters make lint # Type checking make typecheck # Security checks make security # Run all checks make check

Quick Reference

Common Tasks

Download ephemeris files:

# Recommended (auto-select de440s.bsp) python scripts/download_ephemeris.py # All files python scripts/download_ephemeris.py --all # To S3 (production) python scripts/download_ephemeris.py --backend s3 # List available files python scripts/download_ephemeris.py --list

Configure providers (celestial.yaml):

default_provider: navy_api providers: moon_phases: skyfield # Fast offline earth_seasons: skyfield # Fast offline sun_moon_data: navy_api # Full features solar_eclipse_date: navy_api

Environment variables (.env):

# AWS credentials AWS_ACCESS_KEY_ID=your_key AWS_SECRET_ACCESS_KEY=your_secret AWS_REGION=us-east-1 # Provider selection CELESTIAL_PROVIDER=navy_api CELESTIAL_MOON_PHASES_PROVIDER=skyfield

Test provider comparison:

# Run comparison tests uv run pytest tests/test_provider_comparison.py -v # See detailed report cat COMPARISON_REPORT.md

Multi-Server Integration

The chuk-mcp-celestial server works beautifully with other MCP servers to answer complex questions:

Celestial + Time + Weather = Complete Astronomical Intelligence

{ "mcpServers": { "celestial": { "url": "https://celestial.chukai.io/mcp" }, "time": { "url": "https://time.chukai.io/mcp" }, "weather": { "url": "https://weather.chukai.io/mcp" } } }

Example Multi-Server Queries

1. Moon Visibility with Location Intelligence

Q: "Where will the moon be in Leavenheath Suffolk tonight at 10:30pm? Will it be visible and what phase will it be?" Uses: - weather server β†’ geocode_location (find coordinates) - celestial server β†’ get_sun_moon_data (moon position & phase) - AI reasoning β†’ combine data for comprehensive answer Result: βœ“ Moon will be visible in western sky at 22:30 GMT βœ“ Phase: Waxing Gibbous (52% illuminated) βœ“ Position: Descending from upper transit at 18:21

2. Sunrise + Current Time

Q: "When does the sun rise in London and what time is it there now?" Uses: - time server β†’ get_time_for_timezone (current time in Europe/London) - celestial server β†’ get_sun_moon_data (sunrise time) - weather server β†’ geocode_location (confirm location) Result: βœ“ Current time: 21:43:19 GMT βœ“ Sunrise tomorrow: 07:41 GMT βœ“ Time until sunrise: 9h 58m

3. Eclipse + Weather Forecast

Q: "Will the next solar eclipse be visible from New York, and what will the weather be like?" Uses: - celestial server β†’ get_solar_eclipses_by_year, get_solar_eclipse_by_date - weather server β†’ get_weather_forecast (for eclipse date) - time server β†’ timezone conversions Result: βœ“ Eclipse visibility and timing βœ“ Weather forecast for eclipse day βœ“ Optimal viewing conditions

Why Multi-Server Works Better

Single Server

Multi-Server Combination

"Moon rises at 12:55 UTC"

"Moon rises at 12:55 (7:55am local time)"

"Sunrise at 07:41"

"Sunrise at 07:41, currently 21:43, sunset was at 15:56"

"Eclipse on 2024-4-8"

"Eclipse on 2024-4-8, weather: partly cloudy, 60% visibility chance"

Server Responsibilities

Celestial Server (this server):

  • πŸŒ™ Moon phases, positions, rise/set times

  • β˜€οΈ Sun rise/set times, twilight, transit

  • πŸŒ‘ Solar eclipse predictions and local circumstances

  • 🌍 Earth's seasons and orbital events

Time Server:

  • ⏰ Precise current time with NTP synchronization

  • 🌐 Timezone conversions and DST handling

  • πŸ“… Date/time calculations

Weather Server:

  • πŸ—ΊοΈ Geocoding (convert place names to coordinates)

  • β›… Weather forecasts and current conditions

  • πŸ“Š Historical weather data

  • πŸ’¨ Air quality information

Testing Multi-Server Setup

# Test all three servers together uv run mcp-cli --server celestial,time,weather \ --provider openai \ --model gpt-4o-mini

Then ask questions like:

  • "When is sunset in Tokyo and what time is it there now?"

  • "What phase is the moon tonight and will it be cloudy?"

  • "When is the next eclipse visible from London and what's the forecast?"

Data Source

This MCP server uses the official US Navy Astronomical Applications Department API (https://aa.usno.navy.mil/data/api), which provides:

  • Highly accurate astronomical data

  • Historical data from 1700-2100 (varies by endpoint)

  • Solar eclipse data from 1800-2050

  • Official US government source

Comparison with Other Services

Feature

chuk-mcp-celestial

Other Services

Data Source

US Navy (official)

Various APIs

Type Safety

Full Pydantic models

Often dictionaries

Enums

Yes (no magic strings)

Usually strings

Async

Native httpx

Mixed

Eclipse Data

Local circumstances

Often just dates

Historical Range

200-400 years

Usually limited

Test Coverage

70%+

Varies

Contributing

Contributions are welcome! Please:

  1. Fork the repository

  2. Create a feature branch (git checkout -b feature/amazing-feature)

  3. Make your changes

  4. Run tests and checks (make check)

  5. Commit your changes

  6. Push to the branch

  7. Open a Pull Request

License

MIT License - see LICENSE file for details

Credits

-
security - not tested
A
license - permissive license
-
quality - not tested

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/chrishayuk/chuk-mcp-celestial'

If you have feedback or need assistance with the MCP directory API, please join our Discord server