Skip to main content
Glama

get_label

Retrieve the shipping label for a booked APC consignment, automatically polling until generation completes, then save it to disk and return the local file path.

Instructions

Get the shipping label for a booked APC consignment and save it to disk. Call any time after book_shipment — APC typically needs 3-5 seconds to generate, which this tool polls for automatically. Returns the local file path. Default save location is ~/Downloads/parcel-toolkit/, overridable via the PARCEL_TOOLKIT_LABELS_DIR env var.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
waybillYesThe 22-digit WayBill number returned when booking (or from a previously booked consignment).
formatNoLabel format. PDF for standard printers, ZPL for thermal (Zebra/Rollo), PNG for previews.PDF

Implementation Reference

  • The core handler function that fetches a shipping label from the APC API. It polls the API up to 5 times (with 3s delay) for the label, handles single/multi-piece responses, and returns base64-encoded label content.
    export async function getLabel(waybill, format = 'PDF', { retries = 4, retryDelayMs = 3000 } = {}) {
      const path = `/Orders/${waybill}.json?labelformat=${format}&markprinted=True&searchtype=CarrierWaybill&labels=True`;
    
      let lastError;
      for (let attempt = 0; attempt <= retries; attempt++) {
        try {
          const result = await request('GET', path);
          const items = result?.Orders?.Order?.ShipmentDetails?.Items?.Item;
    
          // Multi-piece responses come back as an array; single-piece as an object.
          // The first item carries the full Label payload APC generates for the consignment.
          const first = Array.isArray(items) ? items[0] : items;
          const label = first?.Label;
    
          if (label?.Content) {
            return {
              success: true,
              waybill,
              format:      label.Format || format,
              labelBase64: label.Content,
            };
          }
          lastError = new Error('Label not yet available');
        } catch (err) {
          lastError = err;
        }
    
        if (attempt < retries) {
          await new Promise(r => setTimeout(r, retryDelayMs));
        }
      }
    
      throw new Error(
        `Label not available after ${retries + 1} attempts over ~${((retries + 1) * retryDelayMs) / 1000}s. ` +
        `APC may still be generating it — try calling get_label again in a moment. ` +
        `Last error: ${lastError?.message}`
      );
    }
  • src/index.js:117-152 (registration)
    The MCP tool registration for 'get_label'. Defines the tool with description, Zod schema for waybill (string) and format (PDF/ZPL/PNG), and the handler that calls apc.getLabel() and saves result to disk.
    server.tool(
      'get_label',
      'Get the shipping label for a booked APC consignment and save it to disk. Call any time after book_shipment — APC typically needs 3-5 seconds to generate, which this tool polls for automatically. Returns the local file path. Default save location is ~/Downloads/parcel-toolkit/, overridable via the PARCEL_TOOLKIT_LABELS_DIR env var.',
      {
        waybill: z.string().describe('The 22-digit WayBill number returned when booking (or from a previously booked consignment).'),
        format:  z.enum(['PDF', 'ZPL', 'PNG']).default('PDF').describe('Label format. PDF for standard printers, ZPL for thermal (Zebra/Rollo), PNG for previews.'),
      },
      async ({ waybill, format }) => {
        try {
          const result = await apc.getLabel(waybill, format);
          const extension = (result.format || format).toLowerCase();
          const filePath = await saveLabelToDisk({
            labelBase64: result.labelBase64,
            filenameStem: `apc-${waybill}-${timestamp()}`,
            extension,
          });
          return {
            content: [{
              type: 'text',
              text: JSON.stringify({
                success: true,
                waybill,
                format: result.format,
                filePath,
                message: `Label saved to ${filePath}. Open or drag the file to print.`,
              }, null, 2),
            }],
          };
        } catch (err) {
          return {
            content: [{ type: 'text', text: `Error getting label: ${err.message}` }],
            isError: true,
          };
        }
      }
    );
  • Zod input schema for the get_label tool: waybill (string) and format (enum PDF/ZPL/PNG, defaults to PDF).
      waybill: z.string().describe('The 22-digit WayBill number returned when booking (or from a previously booked consignment).'),
      format:  z.enum(['PDF', 'ZPL', 'PNG']).default('PDF').describe('Label format. PDF for standard printers, ZPL for thermal (Zebra/Rollo), PNG for previews.'),
    },
  • Helper function saveLabelToDisk that writes the base64-decoded label to disk (default: ~/Downloads/parcel-toolkit/) and returns the file path.
    export async function saveLabelToDisk({ labelBase64, filenameStem, extension = 'pdf' }) {
      const dir = labelsDir();
      await mkdir(dir, { recursive: true });
      const filename = `${filenameStem}.${extension}`;
      const fullPath = join(dir, filename);
      const buffer = Buffer.from(labelBase64, 'base64');
      await writeFile(fullPath, buffer);
      return fullPath;
    }
Behavior4/5

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

The description discloses key behavioral traits beyond the schema: it polls for the label, saves to disk, returns a local file path, and has a configurable save directory via environment variable. This is valuable as no annotations are provided. However, it does not mention potential side effects or errors on the remote system.

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 four sentences long, with the primary action stated first ('Get the shipping label...'). Every sentence adds necessary information: purpose, timing/behavior, return value, and configuration. No redundant or vague language.

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 has only two parameters and no output schema, the description covers the essential aspects: what it does, when to use it, what it returns (file path), and how to configure save location. It lacks explicit error handling or timeout behavior, but is otherwise complete for a simple retrieval tool.

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?

The input schema already provides descriptions for both parameters (waybill and format). The description adds context about the waybill source ('returned when booking') and explains the default save location and env var override, which are not in the schema. This adds practical value beyond the schema fields.

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 tool 'Get the shipping label for a booked APC consignment and save it to disk', specifying the exact resource (APC consignment label) and action (get and save). It distinguishes itself from siblings like book_shipment (booking) and track_shipment (tracking) by focusing on label retrieval after booking.

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 explains when to call ('after book_shipment'), mentions a 3-5 second delay that is automatically polled, and indicates the output is saved to a specific location. While it provides clear context, it does not explicitly state alternatives or when not to use, such as using book_batch_and_label for batch operations.

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/catrinmdonnelly/apc-mcp'

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