Skip to main content
Glama
landmark-tools.ts8.04 kB
/** * Landmark tools for EVE Online */ import { z } from "zod"; import { ESIClient } from "./esi-client.js"; import { SDEClient } from "./sde-client.js"; const esiClient = new ESIClient(); const sdeClient = new SDEClient(); /** * Helper function for euclidean distance calculation */ function calculateEuclideanDistance(pos1: {x: number, y: number, z: number}, pos2: number[]): number { if (!pos2 || pos2.length < 3) return 0; const dx = pos1.x - pos2[0]; const dy = pos1.y - pos2[1]; const dz = pos1.z - pos2[2]; // Convert from meters to AU (1 AU = 149,597,870.7 km = 149,597,870,700 m) const distanceMeters = Math.sqrt(dx * dx + dy * dy + dz * dz); const distanceAU = distanceMeters / 149597870700; return Math.round(distanceAU * 100) / 100; // Round to 2 decimal places } /** * Find nearest landmarks to a solar system */ export const findNearestLandmarksTool = { annotations: { openWorldHint: true, // This tool interacts with external APIs readOnlyHint: true, // This tool doesn't modify anything title: "Find Nearest Landmarks", }, description: "Find the nearest EVE Online landmarks to a specified solar system. Returns landmarks sorted by distance with detailed information including descriptions and positions.", execute: async (args: { system: string | number; limit?: number; maxJumps?: number; }) => { try { let systemId: number; // Convert system to ID if it's a string if (typeof args.system === 'string') { const systemResult = await esiClient.getSolarSystemIds([args.system]); if (systemResult.length === 0) { return JSON.stringify({ success: false, message: `System '${args.system}' not found`, landmarks: [] }); } systemId = systemResult[0].id; } else { systemId = args.system; } // Get system information const systemInfo = await esiClient.getSolarSystemInfo(systemId); const systemNames = await esiClient.idsToNames([systemId]); const systemName = systemNames[0]?.name || `System ${systemId}`; // Get all landmarks from SDE const landmarkIds = await sdeClient.getAllLandmarkIds(); if (landmarkIds.length === 0) { return JSON.stringify({ success: false, message: "No landmarks found in database", landmarks: [] }); } const landmarkResults = []; // Process each landmark for (const landmarkId of landmarkIds) { try { const landmark = await sdeClient.getLandmarkById(landmarkId); // Skip if no location ID if (!landmark.locationID) { continue; } // Get landmark system information const landmarkSystemInfo = await esiClient.getSolarSystemInfo(landmark.locationID); const landmarkSystemNames = await esiClient.idsToNames([landmark.locationID]); const landmarkSystemName = landmarkSystemNames[0]?.name || `System ${landmark.locationID}`; // Get constellation info to determine region let regionId = null; try { const constellationInfo = await esiClient.getConstellationInfo(landmarkSystemInfo.constellation_id); regionId = constellationInfo.region_id; } catch (error) { // Skip region info if constellation lookup fails } // Calculate route distance let jumps = 0; let routeAvailable = true; try { const route = await esiClient.calculateRoute(systemId, landmark.locationID); jumps = route.length - 1; } catch (error) { routeAvailable = false; } // Skip if max jumps specified and exceeded if (args.maxJumps && jumps > args.maxJumps) { continue; } // Calculate euclidean distance if both positions are available let euclideanDistanceAU = null; if (landmark.position && systemInfo.position) { euclideanDistanceAU = calculateEuclideanDistance(systemInfo.position, landmark.position); } landmarkResults.push({ landmark: { id: landmarkId, name: `Landmark ${landmarkId}`, description: `EVE Online landmark located in ${landmarkSystemName}`, position: landmark.position || null, }, location: { system_id: landmark.locationID, system_name: landmarkSystemName, security_status: landmarkSystemInfo.security_status, constellation_id: landmarkSystemInfo.constellation_id, region_id: regionId, }, distance: { jumps: routeAvailable ? jumps : null, route_available: routeAvailable, euclidean_distance_au: euclideanDistanceAU } }); } catch (error) { // Skip problematic landmarks continue; } } // Sort by jumps (null values last), then by euclidean distance landmarkResults.sort((a, b) => { if (a.distance.jumps === null && b.distance.jumps === null) { // Both have no route, sort by euclidean distance if (a.distance.euclidean_distance_au === null && b.distance.euclidean_distance_au === null) return 0; if (a.distance.euclidean_distance_au === null) return 1; if (b.distance.euclidean_distance_au === null) return -1; return a.distance.euclidean_distance_au - b.distance.euclidean_distance_au; } if (a.distance.jumps === null) return 1; if (b.distance.jumps === null) return -1; // Both have routes, sort by jumps first if (a.distance.jumps !== b.distance.jumps) { return a.distance.jumps - b.distance.jumps; } // Same jump count, sort by euclidean distance if (a.distance.euclidean_distance_au === null && b.distance.euclidean_distance_au === null) return 0; if (a.distance.euclidean_distance_au === null) return 1; if (b.distance.euclidean_distance_au === null) return -1; return a.distance.euclidean_distance_au - b.distance.euclidean_distance_au; }); // Apply limit const limit = args.limit || 10; const limitedResults = landmarkResults.slice(0, limit); return JSON.stringify({ success: true, message: `Found ${limitedResults.length} nearest landmarks to ${systemName}`, origin: { system_id: systemId, system_name: systemName, security_status: systemInfo.security_status, position: systemInfo.position }, landmarks: limitedResults, summary: { total_landmarks_checked: landmarkIds.length, landmarks_returned: limitedResults.length, closest_landmark: limitedResults.length > 0 ? { name: limitedResults[0].landmark.name, jumps: limitedResults[0].distance.jumps, description: limitedResults[0].landmark.description, euclidean_distance_au: limitedResults[0].distance.euclidean_distance_au } : null } }); } catch (error) { return JSON.stringify({ success: false, message: `Error finding nearest landmarks: ${error instanceof Error ? error.message : 'Unknown error'}`, landmarks: [] }); } }, name: "find_nearest_landmarks", parameters: z.object({ system: z.union([z.string(), z.number()]).describe("Solar system name (English proper noun like 'Jita') or ID to search from"), limit: z.number().min(1).max(50).optional().default(10).describe("Maximum number of landmarks to return (1-50, default: 10)"), maxJumps: z.number().min(1).max(20).optional().describe("Maximum jump distance to search (optional, filters out distant landmarks)") }), };

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/kongyo2/eve-online-traffic-mcp'

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