Sky Compass MCP
Uses NASA/JPL Horizons ephemeris data for solar-system object positions, and the experimental offline ephemeris can refresh its state-vector snapshot from Horizons when network access is available.
Resolves place names to latitude and longitude through OpenStreetMap Nominatim geocoding, returning resolved coordinates and OpenStreetMap attribution while caching results locally.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Sky Compass MCP What's the compass bearing and altitude of Mars from New Delhi at 8pm tonight?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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-mcpOr run it without installing, using uv:
uvx sky-compass-mcpRelated 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 |
| Resolves a place name and returns its latitude and longitude |
| Object name (solar system, catalogue, or SIMBAD identifier) + observer coordinates or |
| RA/Dec (degrees, ICRS J2000) + observer coordinates or |
| Streams timed samples with altitude and bearing rates (degrees per second), for observer coordinates or |
| 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 |
|
| Local catalogue file |
| off | Disable SIMBAD lookups |
|
| SIMBAD timeout, seconds |
| Harvard, then CDS mirror | Comma-separated SIMBAD TAP endpoints, tried in order |
| enabled | Disable place-name lookup; latitude/longitude continue to work |
|
| Nominatim geocoding timeout, seconds |
|
| Streamable HTTP with SSE, bound to localhost |
| 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' -vTo 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' -vRun 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:8000Open 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.pyIf 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:
In LM Studio, load a model with tool-calling support (default
qwen/qwen3.5-9b) and start the local server (port 1234).Keep the model loaded while the agent runs. If LM Studio unloads it, the request fails with
400 Model unloaded.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.pyThe 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 toolsget_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
Scored across 5 tools
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.
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.
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.
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
Offline observational astronomy: positions, rise/set, moon phases, eclipses, and seasons.
Birth charts, transits, moon phases and more from precise astronomical calculations. Natal Compass.
Elevation-corrected sun, moon, twilight, solar and tide data for any point on Earth
Read-only astronomy calculations: sun, moon, planets, eclipses, twilight and star positions.
Related MCP Servers
- AlicenseAqualityBmaintenanceCalculate the altitude, rise, and set times of celestial objects (Sun, Moon, planets, stars, and deep-space objects) for any location on Earth.21531 PyPIMIT
- FlicenseAqualityDmaintenanceProvides 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.31-
- FlicenseNot gradedqualityDmaintenanceEnables 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).-
- AlicenseAqualityBmaintenanceAccurate astronomical catalog data and observing session planner for LLM assistants. Stops hallucinated magnitudes, coordinates, and visibility.3123 npm3MIT