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}`);
      }
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It describes key behaviors: automatic name resolution, pre-configured observer location and current time calculations, and the types of information returned. However, it doesn't mention potential limitations like accuracy constraints, failure modes for unresolvable names, or performance characteristics.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficiently structured in two sentences: the first states the purpose and comprehensive information returned, the second explains behavioral aspects like automatic resolution and calculation settings. Every sentence adds essential information with zero wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no annotations and no output schema, the description does a reasonable job covering the tool's purpose, behavior, and parameter context. However, it doesn't describe the format or structure of returned information, which would be important for an agent to process the results effectively.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage for the single parameter, the baseline is 3. The description adds value by explaining the tool's automatic name resolution capability ('resolves common names') and providing broader context about what types of celestial objects are supported, which complements the schema's examples.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb ('Retrieves') and resource ('detailed astronomical information for a specified celestial object'), with specific examples of object types (planet, star, Messier object) and information returned (coordinates, visibility, times, distance, phases). It distinguishes from sibling tools by focusing on detailed information retrieval rather than pathfinding or listing.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: to get detailed astronomical information for a specific celestial object. It mentions automatic name resolution and pre-configured observer/time settings, but doesn't explicitly state when NOT to use it or name alternatives among sibling tools (e.g., use listCelestialObjects for browsing).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

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