Skip to main content
Glama

calculate_multiple_routes

Read-only

Plan efficient EVE Online travel by calculating routes from one origin to multiple destinations. Choose optimal paths based on shortest, secure, or insecure preferences, with the option to avoid specific systems.

Instructions

Calculate routes from one origin system to multiple destination systems. Useful for finding the best destination or comparing routes.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
avoidSystemsNoOptional array of solar system names (English proper nouns) or IDs to avoid in all routes
destinationsYesArray of destination solar system names (English proper nouns) or IDs (max 20)
flagNoRoute preference: shortest (default), secure (high-sec only), or insecure (low/null-sec allowed)shortest
originYesOrigin solar system name (English proper noun like 'Jita') or ID

Implementation Reference

  • The main handler function 'execute' that implements the tool logic: converts system names/IDs, calculates routes to multiple destinations using ESI API, sorts by jump count, and returns detailed results with summaries and errors.
    execute: async (args: { 
      origin: string | number; 
      destinations: (string | number)[]; 
      flag?: 'shortest' | 'secure' | 'insecure';
      avoidSystems?: (string | number)[];
    }) => {
      try {
        if (args.destinations.length === 0) {
          return JSON.stringify({
            success: false,
            message: "At least one destination must be provided",
            routes: []
          });
        }
    
        if (args.destinations.length > 20) {
          return JSON.stringify({
            success: false,
            message: "Maximum 20 destinations allowed per request",
            routes: []
          });
        }
    
        let originId: number;
        let avoidSystemIds: number[] | undefined;
    
        // Convert origin to ID if it's a string
        if (typeof args.origin === 'string') {
          const originResult = await esiClient.getSolarSystemIds([args.origin]);
          if (originResult.length === 0) {
            return JSON.stringify({
              success: false,
              message: `Origin system '${args.origin}' not found`,
              routes: []
            });
          }
          originId = originResult[0].id;
        } else {
          originId = args.origin;
        }
    
        // Convert avoid systems to IDs if provided
        if (args.avoidSystems && args.avoidSystems.length > 0) {
          avoidSystemIds = [];
          for (const system of args.avoidSystems) {
            if (typeof system === 'string') {
              const avoidResult = await esiClient.getSolarSystemIds([system]);
              if (avoidResult.length > 0) {
                avoidSystemIds.push(avoidResult[0].id);
              }
            } else {
              avoidSystemIds.push(system);
            }
          }
        }
    
        const routes = [];
        const errors = [];
    
        // Calculate routes to each destination
        for (const destination of args.destinations) {
          try {
            let destinationId: number;
    
            // Convert destination to ID if it's a string
            if (typeof destination === 'string') {
              const destinationResult = await esiClient.getSolarSystemIds([destination]);
              if (destinationResult.length === 0) {
                errors.push(`Destination system '${destination}' not found`);
                continue;
              }
              destinationId = destinationResult[0].id;
            } else {
              destinationId = destination;
            }
    
            // Calculate route
            const routeInfo = await esiClient.calculateRouteWithDetails(
              originId,
              destinationId,
              args.flag || 'shortest',
              avoidSystemIds
            );
    
            routes.push({
              destination: routeInfo.destination,
              jumps: routeInfo.jumps,
              route_length: routeInfo.route.length,
              route_type: routeInfo.flag
            });
          } catch (error) {
            errors.push(`Error calculating route to ${destination}: ${error instanceof Error ? error.message : 'Unknown error'}`);
          }
        }
    
        // Sort routes by jump count (shortest first)
        routes.sort((a, b) => a.jumps - b.jumps);
    
        return JSON.stringify({
          success: routes.length > 0,
          message: `Calculated ${routes.length} route(s) from ${typeof args.origin === 'string' ? args.origin : `System ${args.origin}`}`,
          routes,
          errors: errors.length > 0 ? errors : undefined,
          summary: {
            total_destinations_requested: args.destinations.length,
            successful_routes: routes.length,
            failed_routes: errors.length,
            shortest_route: routes.length > 0 ? {
              destination: routes[0].destination.name,
              jumps: routes[0].jumps
            } : null,
            longest_route: routes.length > 0 ? {
              destination: routes[routes.length - 1].destination.name,
              jumps: routes[routes.length - 1].jumps
            } : null
          }
        });
      } catch (error) {
        return JSON.stringify({
          success: false,
          message: `Error calculating multiple routes: ${error instanceof Error ? error.message : 'Unknown error'}`,
          routes: []
        });
      }
    },
  • Zod schema defining the input parameters, including origin, destinations array (1-20), optional flag and avoidSystems.
    parameters: z.object({
      origin: z.union([z.string(), z.number()]).describe("Origin solar system name (English proper noun like 'Jita') or ID"),
      destinations: z.array(z.union([z.string(), z.number()])).min(1).max(20).describe("Array of destination solar system names (English proper nouns) or IDs (max 20)"),
      flag: z.enum(['shortest', 'secure', 'insecure']).optional().default('shortest').describe("Route preference: shortest (default), secure (high-sec only), or insecure (low/null-sec allowed)"),
      avoidSystems: z.array(z.union([z.string(), z.number()])).optional().describe("Optional array of solar system names (English proper nouns) or IDs to avoid in all routes")
    }),
  • src/server.ts:62-62 (registration)
    Registration of the tool in the FastMCP server by adding it via server.addTool.
    server.addTool(calculateMultipleRoutesTool);
  • src/server.ts:19-22 (registration)
    Import of the calculateMultipleRoutesTool from route-tools.js for use in the server.
      calculateRouteTool,
      calculateMultipleRoutesTool,
      findSystemsInRangeTool
    } from "./route-tools.js";
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations indicate readOnlyHint=true and openWorldHint=true, covering safety and data scope. The description adds value by explaining the tool's utility ('finding the best destination or comparing routes'), which provides behavioral context beyond annotations. It doesn't contradict annotations (readOnlyHint aligns with 'calculate' as a query operation), and adds practical insight into how results might be used.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two concise sentences that are front-loaded with the core purpose and followed by a utility statement. Every word earns its place with no redundancy or fluff, making it highly efficient and easy to parse for an AI agent.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (4 parameters, 100% schema coverage, annotations present, no output schema), the description is reasonably complete. It clarifies the multi-destination scope and utility, which complements the structured data. However, it could better address sibling differentiation or output expectations to be fully comprehensive, but it's adequate for the context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with all parameters well-documented in the schema (e.g., 'destinations' max 20 items, 'flag' enum values). The description doesn't add any parameter-specific details beyond what the schema provides, such as explaining 'avoidSystems' usage or 'flag' implications. Baseline 3 is appropriate as the schema carries the full burden of parameter documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool calculates routes from one origin to multiple destinations, specifying the verb 'calculate' and resources 'routes' with scope 'multiple destinations'. It distinguishes from the sibling 'calculate_route' by emphasizing 'multiple' destinations, though it doesn't explicitly name the sibling. The purpose is specific but could be more differentiated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides implied usage context with 'useful for finding the best destination or comparing routes', which suggests when to use this tool. However, it doesn't explicitly state when to use this versus the single-route sibling 'calculate_route' or other routing alternatives, nor does it mention any prerequisites or exclusions. The guidance is helpful but incomplete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Related Tools

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