Skip to main content
Glama
europarcel
by europarcel

Get Fixed Locations

getFixedLocations

Retrieve fixed locations (lockers) in Romania. Filter by locality, carrier, or search by name and address.

Instructions

Retrieves fixed locations (lockers) for a country. Requires country_code. Optional filters: locality_id, carrier_id (single or comma-separated list), locality_name+county_name combination.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
country_codeYesThe country code - must be 'RO' (Romania)
locality_idNoOptional locality ID to filter by
carrier_idNoOptional carrier ID: Single ID (1=Cargus, 2=DPD, 3=FAN Courier, 4=GLS, 6=Sameday, 16=Bookurier) or comma-separated list (e.g., '1,2,3')
locality_nameNoOptional locality name to filter by (must be used with county_name)
county_nameNoOptional county name to filter by (must be used with locality_name)
searchNoOptional search term to filter by name or address (minimum 2 characters, partial match, case-insensitive)

Implementation Reference

  • The main tool handler function 'registerGetFixedLocationsTool' that registers the 'getFixedLocations' tool with the MCP server. It validates inputs (country_code required, locality_name+county_name paired), calls the API client, formats response with location details (name, type, carrier, address, coordinates), and handles errors.
    export function registerGetFixedLocationsTool(server: McpServer): void {
      // Create API client instance
    
      // Register getFixedLocations tool
      server.registerTool(
        "getFixedLocations",
        {
          title: "Get Fixed Locations",
          description:
            "Retrieves fixed locations (lockers) for a country. Requires country_code. Optional filters: locality_id, carrier_id (single or comma-separated list), locality_name+county_name combination.",
          inputSchema: {
            country_code: z
              .enum(["RO"])
              .describe("The country code - must be 'RO' (Romania)"),
            locality_id: z
              .number()
              .min(1)
              .optional()
              .describe("Optional locality ID to filter by"),
            carrier_id: z
              .union([
                z.literal(1),
                z.literal(2),
                z.literal(3),
                z.literal(4),
                z.literal(6),
                z.literal(16),
                z.string().regex(/^(\d+,)*\d+$/),
              ])
              .optional()
              .describe(
                "Optional carrier ID: Single ID (1=Cargus, 2=DPD, 3=FAN Courier, 4=GLS, 6=Sameday, 16=Bookurier) or comma-separated list (e.g., '1,2,3')",
              ),
            locality_name: z
              .string()
              .min(2)
              .max(100)
              .optional()
              .describe(
                "Optional locality name to filter by (must be used with county_name)",
              ),
            county_name: z
              .string()
              .min(2)
              .max(100)
              .optional()
              .describe(
                "Optional county name to filter by (must be used with locality_name)",
              ),
            search: z
              .string()
              .min(2)
              .max(100)
              .optional()
              .describe(
                "Optional search term to filter by name or address (minimum 2 characters, partial match, case-insensitive)",
              ),
          },
        },
        async (args: any) => {
          // Get API key from async context
          const apiKey = apiKeyStorage.getStore();
    
          if (!apiKey) {
            return {
              content: [
                {
                  type: "text",
                  text: "Error: X-API-KEY header is required",
                },
              ],
            };
          }
    
          // Create API client with customer's API key
          const client = new EuroparcelApiClient(apiKey);
    
          try {
            if (!args.country_code) {
              return {
                content: [
                  {
                    type: "text",
                    text: "Error: country_code parameter is required",
                  },
                ],
              };
            }
    
            // Validate locality_name and county_name combination
            if (
              (args.locality_name && !args.county_name) ||
              (!args.locality_name && args.county_name)
            ) {
              return {
                content: [
                  {
                    type: "text",
                    text: "Error: locality_name and county_name must be used together",
                  },
                ],
              };
            }
    
            logger.info("Fetching fixed locations", args);
    
            // Build parameters object
            const params: any = {};
            if (args.locality_id) params.locality_id = args.locality_id;
            if (args.carrier_id) params.carrier_id = args.carrier_id;
            if (args.locality_name) params.locality_name = args.locality_name;
            if (args.county_name) params.county_name = args.county_name;
            if (args.search) params.search = args.search;
    
            const locations = await client.getFixedLocations(
              args.country_code,
              params,
            );
    
            logger.info(`Retrieved ${locations.length} fixed locations`);
    
            let formattedResponse = `Found ${locations.length} fixed locations in ${args.country_code}`;
    
            // Show applied filters
            const filters = [];
            if (args.locality_id) filters.push(`locality_id: ${args.locality_id}`);
            if (args.locality_name && args.county_name)
              filters.push(`locality: ${args.locality_name}, ${args.county_name}`);
            if (args.carrier_id) filters.push(`carrier_id: ${args.carrier_id}`);
            if (args.search) filters.push(`search: "${args.search}"`);
    
            if (filters.length > 0) {
              formattedResponse += ` (filtered by ${filters.join(", ")})`;
            }
            formattedResponse += ":\n\n";
    
            locations.forEach((location) => {
              formattedResponse += `${location.name} (ID: ${location.id})\n`;
              formattedResponse += `  Type: ${location.fixed_location_type}\n`;
              formattedResponse += `  Carrier: ${location.carrier_name}\n`;
              formattedResponse += `  Address: ${location.address}\n`;
              formattedResponse += `  Location: ${location.locality_name}, ${location.county_name}\n`;
              formattedResponse += `  Drop-off: ${location.allows_drop_off ? "Yes" : "No"}\n`;
              formattedResponse += `  Coordinates: ${location.coordinates.lat}, ${location.coordinates.long}\n\n`;
            });
    
            return {
              content: [
                {
                  type: "text",
                  text: formattedResponse,
                },
              ],
            };
          } catch (error: any) {
            logger.error("Failed to fetch fixed locations", error);
    
            return {
              content: [
                {
                  type: "text",
                  text: `Error fetching fixed locations: ${error.message || "Unknown error"}`,
                },
              ],
            };
          }
        },
      );
    
      logger.info("getFixedLocations tool registered successfully");
    }
  • Zod input schema defining the tool's parameters: country_code (required, 'RO' only), locality_id (optional number), carrier_id (optional single number 1/2/3/4/6/16 or comma-separated string), locality_name + county_name (optional pair), and search (optional string for name/address filtering).
    inputSchema: {
      country_code: z
        .enum(["RO"])
        .describe("The country code - must be 'RO' (Romania)"),
      locality_id: z
        .number()
        .min(1)
        .optional()
        .describe("Optional locality ID to filter by"),
      carrier_id: z
        .union([
          z.literal(1),
          z.literal(2),
          z.literal(3),
          z.literal(4),
          z.literal(6),
          z.literal(16),
          z.string().regex(/^(\d+,)*\d+$/),
        ])
        .optional()
        .describe(
          "Optional carrier ID: Single ID (1=Cargus, 2=DPD, 3=FAN Courier, 4=GLS, 6=Sameday, 16=Bookurier) or comma-separated list (e.g., '1,2,3')",
        ),
      locality_name: z
        .string()
        .min(2)
        .max(100)
        .optional()
        .describe(
          "Optional locality name to filter by (must be used with county_name)",
        ),
      county_name: z
        .string()
        .min(2)
        .max(100)
        .optional()
        .describe(
          "Optional county name to filter by (must be used with locality_name)",
        ),
      search: z
        .string()
        .min(2)
        .max(100)
        .optional()
        .describe(
          "Optional search term to filter by name or address (minimum 2 characters, partial match, case-insensitive)",
        ),
    },
  • Registration of the tool via registerGetFixedLocationsTool(server) call, aggregated alongside other location tools in the registerLocationTools function.
      registerGetFixedLocationsTool(server);
      registerGetFixedLocationByIdTool(server);
    
      logger.info("All location tools registered successfully");
    }
  • API client helper method 'getFixedLocations' that makes an HTTP GET request to /locations/fixedlocations/{countryCode} with optional query params and returns a Promise of FixedLocation[].
    async getFixedLocations(
      countryCode: string,
      params?: {
        locality_id?: number;
        carrier_id?: number | string;
        locality_name?: string;
        county_name?: string;
      },
    ): Promise<FixedLocation[]> {
      const response = await this.client.get<FixedLocation[]>(
        `/locations/fixedlocations/${countryCode}`,
        {
          params,
        },
      );
      return response.data;
    }
  • Type definition for the FixedLocation interface returned by the tool, including fields: id, fixed_location_type, carrier_id/name, locality_id/name, county_id/name, country_code, name, address, allows_drop_off, is_active, coordinates (lat/long), schedule, payment_type.
    export interface FixedLocation {
      id: number;
      fixed_location_type: string;
      carrier_id: number;
      carrier_name: string;
      locality_id: number;
      locality_name: string;
      county_id: number;
      county_name: string;
      country_code: string;
      name: string;
      address: string;
      allows_drop_off: boolean;
      is_active: boolean;
      coordinates: {
        lat: number;
        long: number;
      };
      schedule: any;
      payment_type: string;
    }
Behavior3/5

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

No annotations provided, so the description is the sole source. It discloses retrieval behavior and filtering constraints, but does not mention output format, pagination, or rate limits. Adequate but not comprehensive.

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?

Two sentences, front-loaded with purpose and required param, then optional filters. Every word earns its place; no redundancy.

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

Completeness3/5

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

The description covers usage constraints well, but lacks information about output format (e.g., list of location objects) and potential pagination. Given no output schema, more completeness would be beneficial.

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

Parameters4/5

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

With 100% schema coverage, the description adds value by clarifying that locality_name and county_name must be used together, and carrier_id can be a comma-separated list. This goes beyond the schema's basic descriptions.

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

Purpose5/5

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

The description clearly states the verb 'retrieves', the resource 'fixed locations (lockers)', and the scope 'for a country'. It distinguishes from sibling tool getFixedLocationById by focusing on multiple locations with filters.

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

Usage Guidelines4/5

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

The description specifies required and optional filters, and implies use when needing fixed locations for a country. It does not explicitly state when to use alternatives like getFixedLocationById, but the context is clear.

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

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/europarcel/mcp-docker'

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