Skip to main content
Glama

jpl_horizons

Access ephemeris data for solar system objects to calculate positions and orbits for astronomical observations and research.

Instructions

JPL Horizons - Solar system objects ephemeris data

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
formatNoResponse format (json, text)
COMMANDYesTarget object identifier (e.g., '499' for Mars, '1' for Ceres, 'C/2020 F3' for Comet NEOWISE)
OBJ_DATANoInclude object data
MAKE_EPHEMNoGenerate ephemeris
EPHEM_TYPENoType of ephemeris (OBSERVER, VECTORS, ELEMENTS)
CENTERNoCoordinate center (e.g., '500@399' for Earth)
START_TIMENoStart time for ephemeris (e.g., '2023-01-01')
STOP_TIMENoStop time for ephemeris (e.g., '2023-01-02')
STEP_SIZENoStep size for ephemeris points (e.g., '1d' for daily, '1h' for hourly)
QUANTITIESNoObservable quantities to include (e.g., 'A' for all, or '1,2,20,23' for specific ones)
OUT_UNITSNoOutput units for vector tables

Implementation Reference

  • Core handler function `horizonsHandler` that executes the JPL Horizons API request using axios, customizes resource metadata based on parameters like COMMAND and EPHEM_TYPE, adds the JSON response as a jpl://horizons resource, and returns formatted content or error.
    export async function horizonsHandler(args: Record<string, any>) {
      try {
        // Base URL for the Horizons API
        const baseUrl = 'https://ssd.jpl.nasa.gov/api/horizons.api';
        
        // Make the API request
        const response = await axios.get(baseUrl, { params: args });
        const data = response.data;
        
        // Create a resource URI that represents this query
        let resourceUri = 'jpl://horizons';
        let resourceName = 'JPL Horizons ephemeris data';
        
        // Customize resource name based on the request type
        if (args.COMMAND) {
          // Add the object identifier to the resource URI
          resourceUri += `/object/${encodeURIComponent(args.COMMAND)}`;
          
          // Update resource name based on EPHEM_TYPE
          if (args.EPHEM_TYPE === 'OBSERVER') {
            resourceName = `${args.COMMAND} observer ephemeris data`;
          } else if (args.EPHEM_TYPE === 'VECTORS') {
            resourceName = `${args.COMMAND} vector ephemeris data`;
          } else if (args.EPHEM_TYPE === 'ELEMENTS') {
            resourceName = `${args.COMMAND} orbital elements data`;
          } else {
            resourceName = `${args.COMMAND} ephemeris data`;
          }
          
          // Add time range info if available
          if (args.START_TIME && args.STOP_TIME) {
            resourceName += ` (${args.START_TIME} to ${args.STOP_TIME})`;
          }
        }
        
        // Add query parameters to the URI
        const queryParams = Object.entries(args)
          .filter(([key]) => key !== 'COMMAND' && key !== 'format')
          .map(([key, value]) => `${key}=${encodeURIComponent(String(value))}`)
          .join('&');
        
        if (queryParams) {
          resourceUri += `?${queryParams}`;
        }
        
        // Add response to resources
        addResource(resourceUri, {
          name: resourceName,
          mimeType: "application/json",
          text: JSON.stringify(data, null, 2)
        });
        
        // Format the response
        return {
          content: [{
            type: "text",
            text: JSON.stringify(data, null, 2)
          }]
        };
      } catch (error: any) {
        return {
          content: [{
            type: "text",
            text: `Error accessing JPL Horizons API: ${error.message}`
          }],
          isError: true
        };
      }
    }
  • src/index.ts:1231-1287 (registration)
    Registration of the 'jpl_horizons' tool in the tools/list handler response, including full name, description, and detailed inputSchema for parameter validation (e.g., COMMAND required, EPHEM_TYPE enum).
    name: "jpl_horizons",
    description: "JPL Horizons - Solar system objects ephemeris data",
    inputSchema: {
      type: "object",
      properties: {
        format: {
          type: "string",
          description: "Response format (json, text)",
          enum: ["json", "text"]
        },
        COMMAND: {
          type: "string",
          description: "Target object identifier (e.g., '499' for Mars, '1' for Ceres, 'C/2020 F3' for Comet NEOWISE)"
        },
        OBJ_DATA: {
          type: "string",
          description: "Include object data",
          enum: ["YES", "NO"]
        },
        MAKE_EPHEM: {
          type: "string",
          description: "Generate ephemeris",
          enum: ["YES", "NO"]
        },
        EPHEM_TYPE: {
          type: "string",
          description: "Type of ephemeris (OBSERVER, VECTORS, ELEMENTS)",
          enum: ["OBSERVER", "VECTORS", "ELEMENTS"]
        },
        CENTER: {
          type: "string",
          description: "Coordinate center (e.g., '500@399' for Earth)"
        },
        START_TIME: {
          type: "string",
          description: "Start time for ephemeris (e.g., '2023-01-01')"
        },
        STOP_TIME: {
          type: "string",
          description: "Stop time for ephemeris (e.g., '2023-01-02')"
        },
        STEP_SIZE: {
          type: "string",
          description: "Step size for ephemeris points (e.g., '1d' for daily, '1h' for hourly)"
        },
        QUANTITIES: {
          type: "string",
          description: "Observable quantities to include (e.g., 'A' for all, or '1,2,20,23' for specific ones)"
        },
        OUT_UNITS: {
          type: "string",
          description: "Output units for vector tables",
          enum: ["KM-S", "AU-D", "KM-D"]
        }
      },
      required: ["COMMAND"]
    }
  • src/index.ts:533-536 (registration)
    Brief registration of 'jpl_horizons' tool in the tools/manifest API response with id 'jpl/horizons'.
      name: "jpl_horizons",
      id: "jpl/horizons",
      description: "JPL Horizons - Solar system objects ephemeris data"
    },
  • Dynamic import and dispatch logic in handleToolCall for JPL tools: imports `./handlers/jpl/horizons.js` (endpoint='horizons') and executes its default export handler function with the provided arguments.
      // Extract the JPL API endpoint name
      const endpoint = internalToolId.split("/")[1];
      serverInstance?.sendLoggingMessage({
        level: "info",
        data: `JPL Endpoint: ${endpoint}`,
      });
      
      try {
        // Dynamic import for JPL handlers using the original slash format path
        serverInstance?.sendLoggingMessage({
          level: "info",
          data: `Importing handler module: ./handlers/jpl/${endpoint}.js`,
        });
        const handlerModule = await import(`./handlers/jpl/${endpoint}.js`);
        
        // Try to find the handler function in various export formats
        const handlerFunction = handlerModule.default || 
                               handlerModule[`jpl${endpoint.charAt(0).toUpperCase() + endpoint.slice(1)}Handler`] ||
                               handlerModule[`${endpoint}Handler`];
        
        if (typeof handlerFunction === 'function') {
          return await handlerFunction(args);
        } else {
          throw new Error(`Handler for ${endpoint} not found in module`);
        }
      } catch (error: unknown) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return {
          content: [{
            type: "text",
            text: `Error executing JPL tool '${toolName}': ${errorMessage}`
          }],
          isError: true
        };
      }
    }
  • src/index.ts:2142-2148 (registration)
    Global MCP tool registration for 'mcp__jplhorizons' that delegates to handleToolCall('jpl/horizons', args).
    registerGlobalTool('mcp__jplhorizons', async (args: Record<string, any>) => {
      serverInstance?.sendLoggingMessage({
        level: "info",
        data: `MCP JPL Horizons called with args: ${JSON.stringify(args)}`,
      });
      return await handleToolCall('jpl/horizons', args);
    });

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/ProgramComputer/NASA-MCP-server'

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