query_satellites_with_tle
Locate satellites using natural language queries, filter by category, and retrieve structured data including Name and TLE for satellite tracking and analysis.
Instructions
Find satellites by natural language query and return structured data with Name and TLE
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| categoryFilter | No | Optional filter for satellite category | all |
| maxResults | No | Maximum number of satellites to return (default: 10) | |
| query | Yes | Natural language query about satellites (e.g., 'ISS', 'Starlink satellites over California', 'military satellites') |
Implementation Reference
- src/server.ts:798-876 (handler)The primary handler function for the 'query_satellites_with_tle' tool. It reuses the natural language query logic to find satellites over a location, limits the results, fetches TLE data for each using getSatelliteTle, and returns structured data including name, NORAD ID, TLE, position, etc.private async querySatellitesWithTle(query: string, categoryFilter: string = "all", maxResults: number = 10): Promise<CallToolResult> { try { // First, use the existing natural language query to find satellites const naturalQueryResult = await this.querySatellitesNatural(query, categoryFilter); if (naturalQueryResult.isError) { return naturalQueryResult; } // Parse the response to extract satellite data const responseText = naturalQueryResult.content[0]?.text; if (typeof responseText !== 'string') { throw new Error('Invalid response format from natural query'); } const naturalData = JSON.parse(responseText); const satellites = naturalData.satellites || []; // Limit results const limitedSatellites = satellites.slice(0, maxResults); // Get TLE data for each satellite const satellitesWithTle = []; for (const satellite of limitedSatellites) { try { const tleResult = await this.getSatelliteTle(String(satellite.noradId)); if (!tleResult.isError) { const tleResponseText = tleResult.content[0]?.text; if (typeof tleResponseText !== 'string') { continue; } const tleData = JSON.parse(tleResponseText); satellitesWithTle.push({ name: satellite.name, noradId: String(satellite.noradId), tle: tleData, position: satellite.position, launchDate: satellite.launchDate, internationalDesignator: satellite.internationalDesignator, }); } } catch (error) { // Skip satellites that don't have TLE data available console.warn(`Could not get TLE for satellite ${satellite.noradId}: ${error}`); } } // Return structured response const response = { query: query, location: naturalData.location, time: naturalData.time, categoryFilter: categoryFilter, satellites: satellitesWithTle, count: satellitesWithTle.length, totalFound: satellites.length, summary: `Found ${satellitesWithTle.length} satellites with TLE data (${satellites.length} total matches)`, }; return { content: [ { type: "text", text: JSON.stringify(response, null, 2), }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error processing query with TLE: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }
- src/server.ts:64-88 (registration)Tool registration in the getTools() method, defining the name, description, and input schema for 'query_satellites_with_tle'.{ name: "query_satellites_with_tle", description: "Find satellites by natural language query and return structured data with Name and TLE", inputSchema: { type: "object", properties: { query: { type: "string", description: "Natural language query about satellites (e.g., 'ISS', 'Starlink satellites over California', 'military satellites')", }, categoryFilter: { type: "string", enum: ["all", "military", "weather", "gps", "amateur", "starlink", "space-stations"], default: "all", description: "Optional filter for satellite category", }, maxResults: { type: "number", default: 10, description: "Maximum number of satellites to return (default: 10)", }, }, required: ["query"], }, },
- src/server.ts:67-87 (schema)Input schema defining parameters: query (required string), categoryFilter (string enum default 'all'), maxResults (number default 10).inputSchema: { type: "object", properties: { query: { type: "string", description: "Natural language query about satellites (e.g., 'ISS', 'Starlink satellites over California', 'military satellites')", }, categoryFilter: { type: "string", enum: ["all", "military", "weather", "gps", "amateur", "starlink", "space-stations"], default: "all", description: "Optional filter for satellite category", }, maxResults: { type: "number", default: 10, description: "Maximum number of satellites to return (default: 10)", }, }, required: ["query"], },
- src/server.ts:435-436 (registration)Dispatch case in callTool() switch statement that routes the tool call to the querySatellitesWithTle handler method.case "query_satellites_with_tle": return await this.querySatellitesWithTle(args.query, args.categoryFilter, args.maxResults);
- src/server.ts:581-744 (helper)Helper method called by the handler to perform the initial natural language satellite query over a location.private async querySatellitesNatural( query: string, categoryFilter: string = "all" ): Promise<CallToolResult> { try { // Parse the natural language query const parsed = LocationTimeParser.extractLocationAndTime(query); if (!parsed.location) { return { content: [ { type: "text", text: "Could not identify a location in your query. Please specify a location like 'France', 'New York', or 'Germany'.", }, ], isError: true, }; } // Default to current time if no time specified const targetTime = parsed.time?.timestamp || Math.floor(Date.now() / 1000); const timeDescription = parsed.time?.description || "right now"; // Determine which satellites to get based on the query context let satellites; const categoryId = categoryFilter !== "all" ? this.n2yoClient.getCategoryId(categoryFilter) : 0; // Check if query is asking about future time (for predictions) or current/past time (for current position) const timeDiff = targetTime - Math.floor(Date.now() / 1000); if (timeDiff > 300) { // More than 5 minutes in the future // This is a future prediction query - but N2YO "above" endpoint only shows current satellites // We'll get current satellites and note the limitation satellites = await this.n2yoClient.getSatellitesAbove( parsed.location.latitude, parsed.location.longitude, 0, // altitude 85, // search radius categoryId ); const filteredSatellites = categoryFilter !== "all" ? satellites.filter((sat) => this.matchesCategoryFilter(sat, categoryFilter) ) : satellites; const response = { query: query, location: { name: parsed.location.name, coordinates: { latitude: parsed.location.latitude, longitude: parsed.location.longitude, }, }, time: { requested: timeDescription, note: "Showing satellites currently above the location. N2YO API provides current positions, not future predictions for overhead satellites.", }, categoryFilter: categoryFilter, satellites: filteredSatellites.map((sat) => ({ noradId: sat.satid, name: sat.satname, position: { latitude: sat.satlat, longitude: sat.satlng, altitude: sat.satalt, }, launchDate: sat.launchDate, internationalDesignator: sat.intDesignator, })), count: filteredSatellites.length, summary: `Found ${filteredSatellites.length} ${ categoryFilter === "all" ? "" : categoryFilter + " " }satellites currently above ${parsed.location.name}`, }; return { content: [ { type: "text", text: JSON.stringify(response, null, 2), }, ], }; } else { // This is a current or near-current time query satellites = await this.n2yoClient.getSatellitesAbove( parsed.location.latitude, parsed.location.longitude, 0, // altitude 85, // search radius categoryId ); const filteredSatellites = categoryFilter !== "all" ? satellites.filter((sat) => this.matchesCategoryFilter(sat, categoryFilter) ) : satellites; const response = { query: query, location: { name: parsed.location.name, coordinates: { latitude: parsed.location.latitude, longitude: parsed.location.longitude, }, }, time: { description: timeDescription, timestamp: targetTime, }, categoryFilter: categoryFilter, satellites: filteredSatellites.map((sat) => ({ noradId: sat.satid, name: sat.satname, position: { latitude: sat.satlat, longitude: sat.satlng, altitude: sat.satalt, }, launchDate: sat.launchDate, internationalDesignator: sat.intDesignator, })), count: filteredSatellites.length, summary: `Found ${filteredSatellites.length} ${ categoryFilter === "all" ? "" : categoryFilter + " " }satellites above ${parsed.location.name} ${timeDescription}`, }; return { content: [ { type: "text", text: JSON.stringify(response, null, 2), }, ], }; } } catch (error) { return { content: [ { type: "text", text: `Error processing natural language query: ${ error instanceof Error ? error.message : String(error) }`, }, ], isError: true, }; } }