Skip to main content
Glama

Sky Compass MCP

An MCP server that tells you where a celestial object is in the sky for your location. Give it a name such as Moon, Mars, or Andromeda Galaxy and it returns:

  • the magnetic compass bearing in degrees and as a 16-point direction (N, NNE, … ENE … W, NW, …)

  • the altitude (vertical angle above the horizon) to look up to

  • whether the object is above the horizon right now

It also converts raw sky coordinates (right ascension and declination) into the same output.

The built-in catalog includes common solar-system and deep-sky targets. When remote catalog lookup is enabled, other object names or identifiers can be resolved through SIMBAD; the built-in list is not an exhaustive list of all SIMBAD objects. above_horizon means the calculated geometric altitude is above zero. It does not guarantee visibility through a particular telescope: brightness, aperture, sky darkness, obstructions, and atmospheric conditions also matter.

It is built on the official MCP Python SDK (FastMCP, pinned to mcp>=1.2,<2).

Install

pip install sky-compass-mcp

Or run it without installing, using uv:

uvx sky-compass-mcp

Related MCP server: Celestial Position MCP Server

Use with an MCP client

Add the server to your client's MCP configuration, for example:

{
  "mcpServers": {
    "sky-compass": {
      "command": "uvx",
      "args": ["sky-compass-mcp"]
    }
  }
}

If uvx is not available, use "command": "sky-compass-mcp" after installing with pip.

Tools

Tool

Purpose

get_place_coordinates

Resolves a place name and returns its latitude and longitude

locate_celestial_object

Object name (solar system, catalogue, or SIMBAD identifier) + observer coordinates or place_name → bearing and altitude

locate_by_coordinates

RA/Dec (degrees, ICRS J2000) + observer coordinates or place_name → bearing and altitude

track_object

Streams timed samples with altitude and bearing rates (degrees per second), for observer coordinates or place_name

list_supported_objects

Lists built-in solar-system and catalogue objects

For observer location, provide either both latitude and longitude, or place_name—not both. For example:

{
  "object_name": "Moon",
  "place_name": "Bhidi, Deoli, Wardha, Maharashtra, India"
}

To get coordinates without requesting a celestial calculation, call get_place_coordinates:

{
  "place_name": "Bhidi, Deoli, Wardha, Maharashtra, India"
}

It returns the resolved place name, latitude, longitude, data source, and OpenStreetMap attribution.

The resolved location, coordinates, and attribution are included in the result. Place names may be approximate or ambiguous; refine an ambiguous query rather than assuming the first result is correct. The geocoding provider receives the place-name query, which is also cached in the local catalog database.

Streaming

track_object takes start_time_utc, duration_s (up to 3600), and interval_s (0.1 to 60). When the client sends a progressToken in _meta, each sample is delivered as a standard notifications/progress message, paced in real time. The final result holds the sample count and the first and last samples. Without a token, the result contains all samples.

Each sample carries magnetic_bearing_deg, altitude_deg, altitude_rate_deg_s, and magnetic_bearing_rate_deg_s, which a telescope controller can compare against its gyroscope, accelerometer, and magnetometer readings.

Example

Request:

{
  "object_name": "Mars",
  "latitude": 28.6139,
  "longitude": 77.2090,
  "elevation_m": 216,
  "time_utc": "2026-11-02T20:00:00Z",
  "magnetic_declination_deg": 0.5
}

Response (abridged):

{
  "object": "Mars",
  "altitude_deg": 13.654,
  "above_horizon": true,
  "magnetic_bearing_deg": 77.9,
  "compass_direction": "ENE",
  "compass_direction_name": "East-northeast"
}

Supported objects

  • Solar system: Sun, Moon, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune

  • Fixed objects: looked up in SIMBAD when remote lookup is enabled. There is no built-in object list.

  • Additional objects: names and identifiers are looked up in SIMBAD when remote lookup is enabled. Successful results are cached in the local SQLite catalog. This does not expose or enumerate the full SIMBAD catalog.

Pluto is not included.

For any requested object, the server reports its altitude and above_horizon status for the given observer and time. This is a geometric horizon check, not a telescope-aware observability prediction.

Configuration

Option / variable

Default

Purpose

--db / SKY_COMPASS_DB

~/.cache/sky-compass-mcp/catalog.sqlite

Local catalogue file

--no-remote-catalog / SKY_COMPASS_SIMBAD=0

off

Disable SIMBAD lookups

--simbad-timeout / SKY_COMPASS_SIMBAD_TIMEOUT

10

SIMBAD timeout, seconds

--simbad-url / SKY_COMPASS_SIMBAD_URL

Harvard, then CDS mirror

Comma-separated SIMBAD TAP endpoints, tried in order

--no-geocoding / SKY_COMPASS_GEOCODING=0

enabled

Disable place-name lookup; latitude/longitude continue to work

--geocoding-timeout / SKY_COMPASS_GEOCODING_TIMEOUT

10

Nominatim geocoding timeout, seconds

--transport http --host --port

stdio, 127.0.0.1:8765

Streamable HTTP with SSE, bound to localhost

--no-realtime

off

Do not pace streams in wall-clock time (useful for tests)

SIMBAD lookups need internet access. Solar-system objects work offline. When SIMBAD-derived results are shown, credit the SIMBAD database (CDS, Strasbourg; Wenger et al. 2000, A&AS 143, 9). The constant is SIMBAD_ATTRIBUTION in sky_compass_mcp/catalog/simbad.py. Ephemeris data is credited to NASA/JPL Horizons; see JPL_ATTRIBUTION in sky_compass_mcp/astronomy/offline_ephemeris.py. Place-name lookups send the supplied place name to the public OpenStreetMap Nominatim service. Results are cached in the local SQLite catalog database; coordinate-based requests do not contact Nominatim. Ambiguous names are rejected with candidate places so the caller can refine the query. Nominatim results include OpenStreetMap attribution and are subject to its usage policy. The public Nominatim service is rate-limited; this server spaces requests to at least one second apart within a process. For multi-process or high-volume deployments, use a geocoding service or instance whose terms support that use instead of scaling requests to the public endpoint.

Scope: read-only

This server only computes angles. It does not control motors or read sensors. Sensor fusion and motor control belong in a separate client that applies its own limits and safety checks.

Magnetic declination

A magnetic compass points to magnetic north, which differs from true north by the local magnetic declination. This server computes bearings from true north, then subtracts the declination you pass in magnetic_declination_deg (east positive). It does not bundle a magnetic model, so the default is 0, which means magnetic equals true. Look up your location's declination for the current date, for example with NOAA's calculator, before using the bearing with a real compass.

Accuracy

Object type

Typical accuracy

Sun and planets

about 0.1°

Moon

about 0.3°

Fixed objects

catalog precision; proper motion, precession, and refraction are ignored

Altitude is geometric. Atmospheric refraction raises low objects by up to about 0.5°. This is suitable for finding objects by eye and is not for navigation or professional observation.

Experimental offline ephemeris

sky_compass_mcp/astronomy/offline_ephemeris.py is a standalone Newtonian N-body model. It propagates from a JPL Horizons state-vector snapshot. The built-in snapshot is 2026-01-01 00:00 TDB. calibrated_seed() re-fetches the snapshot from Horizons when it is more than 7 days old and the network is available, and can cache it to a JSON file. A request more than 365 days from the seed is flagged stale. Propagation itself makes no network requests. Its propagation code is original to this project; its initial state vectors and gravitational parameters are attributed JPL reference data. The module documents their sources and units. The project's MIT license does not automatically relicense third-party reference data; check source terms before redistribution.

The model integrates the outer planets from their system barycenters and then applies a fixed planet-center offset. It has been compared with geometric Earth-relative JPL vectors for the Sun, Moon, and planets at the seed epoch and at 12 hours, 7, 30, and 90 days after it. In that sample, the worst inner-body difference was about 25 km (Venus at 90 days), and the outer planets stayed within 0.08 arcsec. The remaining outer-planet error comes from the moons' motion around each planet, which the model does not track. This is a limited validation, not a guarantee of accuracy at other dates or suitable for navigation. The model omits relativistic effects, minor bodies, and light-time corrections. It is not connected to the MCP service, which continues to use ephemeris.py.

Run the local checks with:

python -m unittest discover -s tests -p 'test_offline_ephemeris*.py' -v

To repeat the live comparison, which requires internet access:

SKY_COMPASS_COMPARE_JPL=1 python -m unittest discover -s tests -p 'test_offline_ephemeris_horizons.py' -v

Run from source

python -m pip install -r requirements.txt
python -m sky_compass_mcp          # starts the stdio server
python -m unittest discover -s tests -v
SKY_COMPASS_LIVE=1 python -m unittest tests.test_simbad_live -v   # live SIMBAD (needs internet)

requirements.txt installs this project and its runtime dependencies from pyproject.toml; it avoids maintaining a second dependency list.

Phone web page

A single mobile-friendly page with a dropdown of solar-system objects and manual latitude/longitude entry. It uses only the standard library and the offline model, so no extra packages are needed.

cd POC
python3 web/server.py            # listens on 0.0.0.0:8000

Open the printed http://<computer-LAN-IP>:8000 address on a phone connected to the same Wi-Fi. The page has no GPS button because browsers only allow location access on HTTPS, so enter coordinates manually. The server is intended for a trusted home network only; it has no authentication.

The chat box at the bottom sends a question to the LangGraph agent (see below), which calls this MCP server. It needs the agent packages and a running LM Studio, so start the server with the Python environment that has them installed:

cd POC
/path/to/venv/bin/python web/server.py

If the packages are missing, the chat returns HTTP 503. If LM Studio is not reachable, it returns HTTP 502. The dropdown and location features work without either.

LangGraph agent example

examples/langgraph_agent.py is a minimal LangGraph agent that calls this server as its tool source. It uses a local LLM served by LM Studio through its OpenAI-compatible API:

  1. In LM Studio, load a model with tool-calling support (default qwen/qwen3.5-9b) and start the local server (port 1234).

  2. Keep the model loaded while the agent runs. If LM Studio unloads it, the request fails with 400 Model unloaded.

  3. Run:

pip install langgraph langchain langchain-mcp-adapters langchain-openai
python examples/langgraph_agent.py "Where is Jupiter from Pune right now?"

Environment variables: LMSTUDIO_BASE_URL (default http://127.0.0.1:1234/v1) and LMSTUDIO_MODEL (must match the model id loaded in LM Studio).

Place-name geocoding POC

examples/geocode_place.py looks up a place name with the public OpenStreetMap Nominatim service and prints up to five candidate names and coordinates:

python examples/geocode_place.py

The program prompts for a place name. You can also pass it as an argument:

python examples/geocode_place.py "Ganeshpur, Andori, Maharashtra, India"

This sends the query to Nominatim; results may be missing, approximate, or ambiguous. Choose the matching result rather than assuming the first one is correct. This single-query demo is not an autocomplete or bulk-geocoding tool. Follow the Nominatim usage policy and retain OpenStreetMap attribution.

Protocol

Built on the official MCP Python SDK (FastMCP). Served over stdio by default, or over Streamable HTTP at POST /mcp with --transport http. Logs go to stderr only.

The fixed-object coordinates are approximate and should be checked against SIMBAD before publishing. The SIMBAD client tries each configured mirror in turn. Live tests (SKY_COMPASS_LIVE=1) pass through the Harvard mirror when the CDS host is unreachable, but each unreachable mirror adds its full timeout to a lookup.

Publishing

See PUBLISHING.md for the release checklist covering GitHub, PyPI, MIT licensing, security practices, and MCP Registry publication.

License

MIT

Available Tools

5 tools
get_place_coordinatesA

Resolve a place name and return its latitude and longitude.

Inputs: place_name (required).

list_supported_objectsC

List built-in objects; arbitrary SIMBAD-resolvable names can also be requested for location.

Inputs: no named parameters.

locate_by_coordinatesB

Magnetic compass bearing and altitude for explicit RA/Dec (ICRS, J2000 degrees).

Inputs: ra_deg (required), dec_deg (required), latitude, time_utc, +4 more.

locate_celestial_objectB

Find a named celestial object's bearing, altitude, and whether it is geometrically above the horizon.

Inputs: object_name (required), latitude, time_utc, longitude, +3 more.

track_objectB

Stream timed bearing/altitude samples with rates. Each sample is sent as a progress notification when the client supplies a progressToken; the full list is also returned.

Inputs: ra_deg, dec_deg, latitude, longitude, +7 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.4/5.0

    Scored across 5 tools

    Disambiguation4/5

    Most tools are clearly distinct: place-name geocoding, named-object lookup, explicit RA/Dec lookup, tracking, and listing. The main potential confusion is between get_place_coordinates and locate_by_coordinates, but the descriptions clarify terrestrial place names versus celestial ICRS coordinates.

    Naming Consistency4/5

    The set mostly follows a consistent snake_case verb_noun pattern (get_place_coordinates, locate_celestial_object, track_object, list_supported_objects). locate_by_coordinates is a minor deviation because it omits the object noun, but overall naming is predictable.

    Tool Count5/5

    Five tools is well-scoped for a focused celestial navigation server. Each tool covers a distinct operation and there is no obvious filler or missing major capability at this size.

    Completeness4/5

    The core workflow is covered: resolve a place, list known objects, locate an object or coordinates, and track motion over time. Minor gaps such as rise/set calculations or observer-time context are not fatal but would improve the surface.

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      A
      quality
      D
      maintenance
      Provides altitude-azimuth coordinates for celestial objects including planets, over 117,000 stars, and 14,000 deep sky objects based on system time and configurable location.
      3
      1
      -
    • F
      license
      Not graded
      quality
      D
      maintenance
      Enables satellite orbital mechanics calculations including visibility predictions, access window analysis, and TLE generation from natural language descriptions. Supports 200+ world cities and multiple orbit types (LEO, MEO, GEO, SSO, Molniya, Polar).
      -
    • A
      license
      A
      quality
      B
      maintenance
      Accurate astronomical catalog data and observing session planner for LLM assistants. Stops hallucinated magnitudes, coordinates, and visibility.
      3
      123 npm
      3
      MIT