Skip to main content
Glama

Satellite Tracking MCP Server

visual-passes.ts5.15 kB
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js'; import { N2YOApiClient, SatellitePass, VisualPassesParams } from '../api-client.js'; export const predictVisualPassesToolSchema = { name: 'predict_visual_passes', description: 'Predict visible passes of a satellite over a location', inputSchema: { type: 'object', properties: { norad_id: { type: 'number', description: 'NORAD ID of the satellite', }, observer_lat: { type: 'number', description: 'Observer latitude (-90 to 90)', minimum: -90, maximum: 90, }, observer_lng: { type: 'number', description: 'Observer longitude (-180 to 180)', minimum: -180, maximum: 180, }, observer_alt: { type: 'number', description: 'Observer altitude in meters (optional)', minimum: 0, }, days: { type: 'number', description: 'Number of days to predict (1-10)', minimum: 1, maximum: 10, }, min_visibility: { type: 'number', description: 'Minimum visibility time in seconds (0-600)', minimum: 0, maximum: 600, }, }, required: ['norad_id', 'observer_lat', 'observer_lng'], }, }; export async function predictVisualPassesTool( apiClient: N2YOApiClient, args: { norad_id: number; observer_lat: number; observer_lng: number; observer_alt?: number; days?: number; min_visibility?: number; } ) { try { const { norad_id, observer_lat, observer_lng, observer_alt, days, min_visibility } = args; // Validate NORAD ID if (!Number.isInteger(norad_id) || norad_id <= 0) { throw new McpError( ErrorCode.InvalidParams, 'Invalid NORAD ID. Must be a positive integer.' ); } // Validate coordinates if (observer_lat < -90 || observer_lat > 90) { throw new McpError( ErrorCode.InvalidParams, 'Invalid latitude. Must be between -90 and 90.' ); } if (observer_lng < -180 || observer_lng > 180) { throw new McpError( ErrorCode.InvalidParams, 'Invalid longitude. Must be between -180 and 180.' ); } // Validate days if (days !== undefined && (!Number.isInteger(days) || days < 1 || days > 10)) { throw new McpError( ErrorCode.InvalidParams, 'Invalid days. Must be an integer between 1 and 10.' ); } // Validate min_visibility if (min_visibility !== undefined && (min_visibility < 0 || min_visibility > 600)) { throw new McpError( ErrorCode.InvalidParams, 'Invalid min_visibility. Must be between 0 and 600 seconds.' ); } const params: VisualPassesParams = { noradId: norad_id, observer_lat, observer_lng, observer_alt, days, min_visibility, }; const passes = await apiClient.getVisualPasses(params); if (!passes || passes.length === 0) { return { content: [ { type: 'text', text: JSON.stringify({ satellite_id: norad_id, observer: { latitude: observer_lat, longitude: observer_lng, altitude: observer_alt || 0, }, prediction_days: days || 7, passes: [], message: `No visible passes found for satellite ${norad_id} in the next ${days || 7} days.`, }, null, 2), }, ], }; } // Format the response const formattedPasses = passes.map(pass => formatPassData(pass)); return { content: [ { type: 'text', text: JSON.stringify({ satellite_id: norad_id, satellite_name: passes[0].satname, observer: { latitude: observer_lat, longitude: observer_lng, altitude: observer_alt || 0, }, prediction_days: days || 7, passes: formattedPasses, }, null, 2), }, ], }; } catch (error) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `Error predicting satellite passes: ${(error as Error).message}` ); } } function formatPassData(pass: SatellitePass) { // Convert timestamps to ISO strings const startDate = new Date(pass.startUTC * 1000); const maxDate = new Date(pass.maxUTC * 1000); const endDate = new Date(pass.endUTC * 1000); return { start: { time: startDate.toISOString(), azimuth: pass.startAz, azimuth_compass: pass.startAzCompass, elevation: pass.startEl, }, max: { time: maxDate.toISOString(), azimuth: pass.maxAz, azimuth_compass: pass.maxAzCompass, elevation: pass.maxEl, }, end: { time: endDate.toISOString(), azimuth: pass.endAz, azimuth_compass: pass.endAzCompass, elevation: pass.endEl, }, magnitude: pass.mag, duration_seconds: pass.duration, }; }

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/Cyreslab-AI/satellitetracking-mcp-server'

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