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}`);
      }
    }
Install Server

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