Skip to main content
Glama
Rkm1999

Celestial Position MCP Server

by Rkm1999

getCelestialDetails

Retrieve precise astronomical data for any celestial object, including coordinates, visibility status, rise/transit/set times, and phase details, using the observer’s location and current system time.

Instructions

Retrieves detailed astronomical information for a specified celestial object (e.g., planet, star, Messier object, NGC/IC object). Information includes current equatorial and horizontal (altitude/azimuth) coordinates, visibility status (above/below horizon), rise/transit/set times, and, where applicable, distance, phase illumination, and upcoming moon phases. All calculations are performed for the pre-configured observer location and the current system time. The tool automatically resolves common names (e.g., 'Andromeda Galaxy' to 'M31') and handles various catalog identifiers.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
objectNameYesThe name or catalog identifier of the celestial object. Examples: 'Jupiter', 'Sirius', 'M31', 'NGC 7000', 'Crab Nebula'. The tool will attempt to resolve common names.

Implementation Reference

  • Tool class definition with name 'getCelestialDetails' and description. Extends MCPTool for automatic discovery and registration by the MCP framework.
    class CelestialDetailsTool extends MCPTool<CelestialDetailsInput> { name = 'getCelestialDetails'; description = "Retrieves detailed astronomical information for a specified celestial object (e.g., planet, star, Messier object, NGC/IC object). Information includes current equatorial and horizontal (altitude/azimuth) coordinates, visibility status (above/below horizon), rise/transit/set times, and, where applicable, distance, phase illumination, and upcoming moon phases. All calculations are performed for the pre-configured observer location and the current system time. The tool automatically resolves common names (e.g., 'Andromeda Galaxy' to 'M31') and handles various catalog identifiers.";
  • Input schema definition using Zod for validation of objectName parameter.
    protected schema = { objectName: { type: z.string(), description: "The name or catalog identifier of the celestial object. Examples: 'Jupiter', 'Sirius', 'M31', 'NGC 7000', 'Crab Nebula'. The tool will attempt to resolve common names." } // Removed: useSystemTime, dateTime, latitude, longitude, elevation };
  • Core handler function that fetches equatorial coordinates, converts to alt/az, computes visibility (above horizon, rise/transit/set times), object details (distance, phase for Moon/planets), and formats response for the given celestial object using pre-configured observer location and current time.
    async execute(params: CelestialDetailsInput) { try { // Always use current system time const date = new Date(); // Always use pre-configured observer location const observer = { latitude: OBSERVER_CONFIG.latitude, longitude: OBSERVER_CONFIG.longitude, elevation: OBSERVER_CONFIG.altitude, temperature: OBSERVER_CONFIG.temperature, pressure: OBSERVER_CONFIG.pressure }; // Get equatorial coordinates for the object let equatorialCoords: EquatorialCoordinates; try { equatorialCoords = await getEquatorialCoordinates(params.objectName, date); } catch (error: any) { throw new Error(`Could not find object: ${params.objectName}. ${error.message}`); } // Convert to horizontal (altaz) coordinates (NEW) const altazCoords = convertToAltAz(equatorialCoords, observer, date); // Get detailed information const details = getObjectDetails(params.objectName, date, observer); // Format the location for display const locationName = `Configured (${OBSERVER_CONFIG.latitude.toFixed(4)}°, ${OBSERVER_CONFIG.longitude.toFixed(4)}°)`; // Calculate visibility (NEW) const isAboveHorizon = altazCoords.altitude > 0; const visibility = isAboveHorizon ? altazCoords.altitude > 30 ? "Excellent visibility" : "Above horizon" : "Below horizon (not visible)"; // Format the response const response: any = { object: params.objectName, ...(typeof equatorialCoords.magnitude === 'number' && { apparentMagnitude: equatorialCoords.magnitude }), observationTime: date.toLocaleString() + " (system local time)", location: locationName, coordinates: { equatorial: { rightAscension: equatorialCoords.rightAscension.toFixed(4) + "h", declination: equatorialCoords.declination.toFixed(4) + "°" }, // Added altitude and azimuth to response horizontal: { altitude: altazCoords.altitude.toFixed(4) + "°", azimuth: altazCoords.azimuth.toFixed(4) + "°" } }, // Added these fields aboveHorizon: isAboveHorizon ? "Yes" : "No", visibility: visibility }; // Add rise/set/transit times if available if (details) { const formatTime = (timeObj: Date | Astronomy.AstroTime | null | undefined): string => { if (!timeObj) return "N/A"; // AstroTime objects have a .date property which is a JS Date. // Fixed objects might return JS Date directly for riseTime/setTime. const date = timeObj instanceof Date ? timeObj : new Date((timeObj as Astronomy.AstroTime).date); return date.toLocaleTimeString(); }; let note = ""; if (details.isCircumpolar) { if (details.alwaysAboveHorizon) { note = "This object is circumpolar and remains above the horizon from this location."; } else if (details.alwaysBelowHorizon) { note = "This object is circumpolar and remains below the horizon from this location."; } else { note = "This object is circumpolar from this location."; } } else { // Not circumpolar. Check if it doesn't rise/set and transit is below horizon. if (!details.riseTime && !details.setTime && details.transitTime && details.transitTime.hor && details.transitTime.hor.altitude < 0) { note = "This object does not rise above the horizon on this date from this location."; } } const riseStr = formatTime(details.riseTime); // details.transitTime is an event object like { time: AstroTime | Date, hor: HorizontalCoordinates } const transitStr = formatTime(details.transitTime ? details.transitTime.time : null); const setStr = formatTime(details.setTime); if (riseStr === "N/A" && transitStr === "N/A" && setStr === "N/A" && !note) { note = "Rise, transit, and set times are not available for this object on this date at this location."; } response.visibilityTimes = { rise: riseStr, transit: transitStr, set: setStr }; if (note) response.visibilityTimes.note = note; } else { response.visibilityTimes = { note: "Astronomical details, including rise/set times, could not be determined for this object." }; } // Add distance information if available if (details && details.distance) { response.distance = { astronomicalUnits: details.distance.au.toFixed(6), kilometers: Math.round(details.distance.km).toLocaleString() }; } // Add phase information for solar system objects if (details && details.phaseInfo) { response.phase = { percentIlluminated: details.phaseInfo.phasePercent.toFixed(1) + "%", trend: details.phaseInfo.isWaxing ? "Waxing" : "Waning" }; } // Add moon phase information if this is the Moon if (details && details.moonPhases && params.objectName.toLowerCase() === 'moon') { response.upcomingPhases = { newMoon: new Date(details.moonPhases.nextNewMoon.date).toLocaleDateString(), firstQuarter: new Date(details.moonPhases.nextFirstQuarter.date).toLocaleDateString(), fullMoon: new Date(details.moonPhases.nextFullMoon.date).toLocaleDateString(), lastQuarter: new Date(details.moonPhases.nextLastQuarter.date).toLocaleDateString() }; } return response; } catch (error: any) { throw new Error(`Failed to get celestial details: ${error.message}`); } }

Other Tools

Related Tools

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/Rkm1999/CelestialMCP'

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