MCP Hub
Back to servers

chuk-mcp-celestial

A professional-grade astronomical MCP server that provides authoritative US Navy and Skyfield-powered data for moon phases, solar eclipses, sun/moon positioning, and seasonal transitions.

Tools
5
Updated
Nov 29, 2025

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

MethodSetup TimeRequires InternetUpdatesBest For
HostedInstantYesAutomaticQuick testing, production use
uvxInstantYes (first run)AutomaticNo local install, always latest
Local1-2 minOnly for installManualOffline use, custom deployments

Option 1: Use Hosted Version (Recommended)

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

ProviderSpeedAccuracyOfflineFeatures
Navy APIStandard (~700ms)AuthoritativeAll features
SkyfieldFast (~25ms)Research-gradeMoon 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:

Recommended Server Combinations

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 ServerMulti-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

Featurechuk-mcp-celestialOther Services
Data SourceUS Navy (official)Various APIs
Type SafetyFull Pydantic modelsOften dictionaries
EnumsYes (no magic strings)Usually strings
AsyncNative httpxMixed
Eclipse DataLocal circumstancesOften just dates
Historical Range200-400 yearsUsually limited
Test Coverage70%+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

Links

Reviews

No reviews yet

Sign in to write a review