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
| Name | Required | Description | Default |
|---|---|---|---|
| waybill | Yes | The 22-digit WayBill number returned when booking (or from a previously booked consignment). | |
| format | No | Label format. PDF for standard printers, ZPL for thermal (Zebra/Rollo), PNG for previews. |
Implementation Reference
- src/carriers/apc.js:351-388 (handler)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, }; } } ); - src/index.js:121-123 (schema)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.'), }, - src/utils/labels.js:22-30 (helper)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; }