jpl_scout
Access JPL Scout data to retrieve orbits, ephemerides, and impact risk assessments for near-Earth objects using temporary designations or orbit IDs.
Instructions
Scout - NEOCP orbits, ephemerides, and impact risk data
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tdes | No | Object temporary designation (e.g., P21Eolo) | |
| orbit_id | No | Scout internal orbit ID | |
| limit | No | Limit number of results | |
| file | No | Type of data file to return (summary, ephem, obs, crit, all) | |
| plot | No | Include plots in the response | |
| summary | No | Include summary data in the response |
Implementation Reference
- src/handlers/jpl/scout.ts:63-121 (handler)The primary handler function that implements the core logic for the 'jpl_scout' tool. It makes API requests to JPL Scout, handles errors, processes results using a helper, formats output, and adds resources.export async function jplScoutHandler(params: ScoutParams) { try { // Call the Scout API using jplApiRequest const result = await jplApiRequest('/scout.api', params); // Check for errors returned by jplApiRequest itself (network, etc.) if (result.isError) { return result; // Already formatted error response } // Check for API-specific errors within the payload (different formats) if (result.error_code || result.error) { return { isError: true, content: [{ type: "text", text: `Error from Scout API: ${result.error_msg || result.error}` }] }; } // Process the successful result const summaryText = processScoutResult(result, params); // Add the result as an MCP resource let resourceUri = 'jpl://scout/list'; if (params.tdes) { resourceUri = `jpl://scout?tdes=${params.tdes}`; } else if (params.orbit_id) { resourceUri = `jpl://scout?orbit_id=${params.orbit_id}`; } else if (params.limit) { resourceUri = `jpl://scout/list?limit=${params.limit}`; } // Add more specific URIs if other params like 'file' are used addResource(resourceUri, { name: `JPL Scout Data ${params.tdes || params.orbit_id || '(List)'}`, mimeType: 'application/json', text: JSON.stringify(result, null, 2) }); return { content: [{ type: "text", text: summaryText }], isError: false }; } catch (error: any) { // Catch unexpected errors during processing console.error('Error in JPL Scout handler:', error); return { isError: true, content: [{ type: "text", text: `Handler Error: ${error.message || 'An unexpected error occurred processing Scout data'}` }] }; } }
- src/handlers/setup.ts:98-105 (schema)Zod schema defining the input parameters (ScoutParams) for the jpl_scout tool, exported for use in handlers.const ScoutSchema = z.object({ tdes: z.string().describe("Object temporary designation (e.g., P21Eolo)").optional(), orbit_id: z.string().describe("Scout internal orbit ID").optional(), limit: z.number().int().positive().describe("Limit number of results").optional(), file: z.enum(['summary', 'ephem', 'obs', 'crit', 'all']).describe("Type of data file to return").optional(), plot: z.boolean().describe("Include plots in the response").optional(), summary: z.boolean().describe("Include summary data in the response").optional() });
- src/index.ts:1693-1709 (registration)Registers the direct MCP request handler for the 'jpl/scout' method, validating params with inline schema and delegating to the dynamic handleToolCall which imports and executes the handler.// Scout Handler server.setRequestHandler( z.object({ method: z.literal("jpl/scout"), params: z.object({ tdes: z.string().optional(), orbit_id: z.string().optional(), limit: z.number().int().positive().optional(), file: z.enum(['summary', 'ephem', 'obs', 'crit', 'all']).optional(), plot: z.boolean().optional(), summary: z.boolean().optional() }).optional() }), async (request) => { return await handleToolCall("jpl/scout", request.params || {}); } );
- src/index.ts:537-541 (registration)Lists 'jpl_scout' in the tools/manifest response, providing the tool name, ID, and description.{ name: "jpl_scout", id: "jpl/scout", description: "NEOCP orbits, ephemerides, and impact risk data (Scout)" },
- src/handlers/jpl/scout.ts:9-56 (helper)Supporting function that formats raw Scout API data into a human-readable markdown summary for single objects or lists.function processScoutResult(data: any, params: ScoutParams): string { // Handle API-level errors first if (data.error_code) { return `Error from Scout API (${data.error_code}): ${data.error_msg}`; } if (data.error) { // Handle other error format like "object does not exist" return `Error from Scout API: ${data.error}`; } let summary = `## JPL Scout Data\n\n`; if (params.tdes || params.orbit_id) { // Single object result if (!data.data || data.data.length === 0) { // If no specific error was returned, but data is empty, state that. return summary + `No data array found for object specified by ${params.tdes ? 'tdes='+params.tdes : ''}${params.orbit_id ? 'orbit_id='+params.orbit_id : ''}. Object may not exist or data type not available.`; } const obj = data.data[0]; summary += `**Object:** ${obj.neo || 'N/A'} (${params.tdes || params.orbit_id})\n`; summary += `**Last Observed:** ${obj.last_obs || 'N/A'}\n`; summary += `**Observations:** ${obj.n_obs || 'N/A'}\n`; summary += `**RMS:** ${obj.rms || 'N/A'}\n`; summary += `**MOID (AU):** ${obj.moid || 'N/A'}\n`; summary += `**V_inf (km/s):** ${obj.v_inf || 'N/A'}\n`; summary += `**Impact Probability:** ${obj.impact_prob || 'N/A'}\n`; if (obj.summary) { summary += `**Summary:** ${obj.summary}\n`; } // Add more fields if file=ephem, obs, crit, all are requested } else { // List result summary += `**Total Objects Found:** ${data.total || 'N/A'}\n`; summary += `**Showing:** ${data.count !== undefined ? data.count : 'N/A'} (Limit: ${params.limit || data.limit || 'default'})\n\n`; if (data.data && Array.isArray(data.data) && data.data.length > 0) { data.data.forEach((obj: any, index: number) => { summary += `### ${index + 1}. ${obj.neo || 'Unknown Designation'}\n`; summary += ` - Last Observed: ${obj.last_obs || 'N/A'}\n`; summary += ` - Observations: ${obj.n_obs || 'N/A'}\n`; summary += ` - MOID (AU): ${obj.moid || 'N/A'}\n`; summary += ` - Impact Probability: ${obj.impact_prob || 'N/A'}\n`; }); } else { summary += `No objects found matching criteria or returned in list.\n`; } } return summary; }